Questo accade solo su Linux (anche possibile sistema operativo X, non può testare atm), funziona bene su Windows.wx.ProgressDialog che causa l'errore di seg e/o l'errore GTK_IS_WINDOW quando viene distrutto
Ho un wx.ProgressDialog generato con il thread principale. Invio il lavoro a un altro thread e periodicamente richiama una funzione di callback nel thread principale che aggiornerà il ProgressDialog o, alla fine del lavoro, lo distruggerà. Tuttavia, ricevo un messaggio di interessante su Linux quando questo accade:
(python:12728): Gtk-CRITICAL **: IA__gtk_window_set_modal: assertion 'GTK_IS_WINDOW (window)' failed
La finestra di dialogo non si chiude, ma se provo a deporre le uova di nuovo sembra che è già quasi finito. A volte un errore seg seguirà anche questo messaggio.
Ho cercato di simulare con una versione ridotta qui:.
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()
(selezioniamo 2.8, ma idealmente qualsiasi correzione deve lavorare sia in 2.8 e 3.0 io in realtà non sono stati in grado di testarlo in 3.0 a linux a causa di una versione 3.0 non corretta)
Questo è un buon lavoro nel rappresentare il problema: funziona bene in Windows, ma sega errore quando tenta di distruggere la finestra di dialogo di avanzamento. Tuttavia, non posso ottenere l'esempio per mostrare GTK_IS_WINDOW
Ive ha provato a cercare soluzioni. Ho letto che potrebbe essere dovuto al fatto che il thread di lavoro termina troppo velocemente, e quindi lascia la GUI con alcuni messaggi nella sua coda. Non sono sicuro di averlo capito completamente (non ho mai capito il rendimento di Rendimenti e messaggi, ecc.), Ma quello che credo significhi è che quando il lavoratore è al 100%, il ProgressDialog (essendo più lento), potrebbe essere solo 75% e ha ancora il 25% in più di messaggi da utilizzare per "aggiornare" la GUI, ma viene distrutto.
Vorrei qualche chiarimento se sto capendo che correttamente o no.
Inoltre, credo che .Hide()
funzioni come un aggiramento, ma mi piacerebbe distruggerlo invece perché è la cosa giusta da fare.
Indipendentemente da ciò, qualsiasi aiuto sarebbe molto apprezzato. =)