This only happens on Linux (maybe OS X also cannot test atm), it works fine on Windows.
I have a wx.ProgressDialog that is created using the main thread. I send the work to another thread, and it periodically calls back the callback function in the main thread, which will update the ProgressDialog or, at the end of the work, destroy it. However, when this happens, I get an interesting Linux post:
(python:12728): Gtk-CRITICAL **: IA__gtk_window_set_modal: assertion 'GTK_IS_WINDOW (window)' failed
The dialog closes, but if I try to create it again, it seems to be almost done. Sometimes a seg error also follows with this message.
I tried to simulate it with a stripped down version here:
import wxversion wxversion.select("2.8") import wx import sys import threading MAX_COUNT = 100 ## This class is in a different area of the codebase and class WorkerThread(threading.Thread): def __init__(self, callback): threading.Thread.__init__(self) self.callback = callback def run(self): # simulate work done. IRL, this calls another function in another # area of the codebase. This function would generate an XML document, # which loops through a list of items and creates a set of elements for # each item, calling back after each item. Here, we simply set up a for # loop and simulate work with wx.MilliSleep for i in xrange(MAX_COUNT): print i wx.MilliSleep(30) wx.CallAfter(self.callback, i) # Send done signal to GUI wx.CallAfter(self.callback, -1) class Frame(wx.Frame): def __init__(self, title): wx.Frame.__init__(self, None, title=title, pos=(150,150), size=(350,200)) panel = wx.Panel(self) box = wx.BoxSizer(wx.VERTICAL) m_btn = wx.Button(panel, wx.ID_ANY, "Run Stuff") m_btn.Bind(wx.EVT_BUTTON, self.OnRunButton) box.Add(m_btn, 0, wx.ALL, 10) panel.SetSizer(box) panel.Layout() def OnRunButton(self, event): self.progressDialog = wx.ProgressDialog("Doing work", "Doing Work", maximum=MAX_COUNT, parent=self, style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME) self.worker(self.threadCallback) self.progressDialog.ShowModal() def worker(self, callback): # This bit is in another part of the codebase originally. In the test, # I could have added it to OnRunButton, but I wanted function calls to # be similar between test and actual code thread = WorkerThread(callback) thread.start() def threadCallback(self, info): # We update based on position, or destroy if we get a -1 if info == -1: self.progressDialog.Destroy() else: self.progressDialog.Update(info) app = wx.App(redirect=False) top = Frame("ProgressDialog Test") top.Show() app.MainLoop()
(we choose 2.8, but ideally, any fix should work in both 2.8 and 3.0. I really could not test it in 3.0 on Linux due to poor build 3.0)
This is a good job at presenting the problem: works fine on Windows, but seg fault when it tries to destroy the progress dialog. However, I cannot give an example to show GTK_IS_WINDOW
Ive tried to find a solution. I read that this may be due to the fact that the workflow ends too quickly and thus leaves the GUI with some messages in the queue. Iβm not sure I fully understand this (I never got access to income and messages, etc.), but I believe that this means that when an employee is 100%, ProgressDialog (slower) can be only 75%, and still there is an additional 25% of the messages that need to be used to βupdateβ the GUI, but are destroyed instead.
I would like clarification as to whether I understand this correctly.
In addition, I believe .Hide() works like a job, but I would like to destroy it because it needs to be done.
Regardless, any help would be greatly appreciated. =)