mardi 20 mai 2014

Plantage de l'application avec wx.CallAfter() depuis un moment une boucle infinie dans wxPython/python - Stack Overflow


I am working with python v2.7 and wxPython v3.0 on windows 7 OS. In the following code snippet I have implemented a publisher-subscriber mechanism to update my GUI. I am using wx.CallAfter() for sending the updates to my GUI main loop.


Problem: Why does my code snippet provided below my application crashes. Why is this happening? How to avoid this?


Code: The images used in the code can be downloaded from here blue.bmp & g.bmp.


import wx
import time
from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
from threading import Thread
import threading
import random

class gui(wx.Frame):

def __init__(self, parent, id, title):
wx.Frame.__init__(self, None, id, title, size=(200,200), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
self.mainPanel = mainPanel = wx.Panel(self, -1)
mySizer = wx.BoxSizer(wx.VERTICAL)
self.myButton1 = wx.Button(mainPanel, -1, size=(30,30))
mySizer.Add(self.myButton1)
mainPanel.SetSizer(mySizer)
Bimage_file = 'blue.bmp'
self.Blue = wx.Image(Bimage_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
Gimage_file = 'g.bmp'
self.Green = wx.Image(Gimage_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
pub.subscribe(self.updateImages, 'Update')

def updateImages(self, value):
self.myButton1.DestroyChildren()
if value <= 5:
wx.StaticBitmap(self.myButton1, -1, self.Blue, (0, 0))
self.mainPanel.Layout()
else:
wx.StaticBitmap(self.myButton1, -1, self.Green, (0, 0))
self.mainPanel.Layout()
class myThread(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
while True:
result = random.randrange(0,10)
wx.CallAfter(pub.sendMessage, 'Update', value=result)
#Uncomment the following line to avoid the crash!!!
#time.sleep(1)
if __name__=='__main__':
app = wx.App()
frame = gui(parent=None, id=-1, title="Demo")
frame.Show()
myThread()
app.MainLoop()

However if I add the following line after wx.CallAfter() it works fine:


time.sleep(1)

Thanks for your time!




The problem is probably due to overflowing the Windows message queue. There are several tickets about this bug in wxWidgets bug tracker and some of its occurrences have been fixed, but probably not all.


In any case, even if we manage to always avoid the overflow, it's still a bad idea to flood the main thread with events like this (because every call to wx.CallAfter() is morally equivalent to an event). In real life situations, the background thread would be doing some work in between them, so this is unlikely to happen, but if you really need to make it work in such toy example, using sleep() is probably actually the right thing to do.



I am working with python v2.7 and wxPython v3.0 on windows 7 OS. In the following code snippet I have implemented a publisher-subscriber mechanism to update my GUI. I am using wx.CallAfter() for sending the updates to my GUI main loop.


Problem: Why does my code snippet provided below my application crashes. Why is this happening? How to avoid this?


Code: The images used in the code can be downloaded from here blue.bmp & g.bmp.


import wx
import time
from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
from threading import Thread
import threading
import random

class gui(wx.Frame):

def __init__(self, parent, id, title):
wx.Frame.__init__(self, None, id, title, size=(200,200), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
self.mainPanel = mainPanel = wx.Panel(self, -1)
mySizer = wx.BoxSizer(wx.VERTICAL)
self.myButton1 = wx.Button(mainPanel, -1, size=(30,30))
mySizer.Add(self.myButton1)
mainPanel.SetSizer(mySizer)
Bimage_file = 'blue.bmp'
self.Blue = wx.Image(Bimage_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
Gimage_file = 'g.bmp'
self.Green = wx.Image(Gimage_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
pub.subscribe(self.updateImages, 'Update')

def updateImages(self, value):
self.myButton1.DestroyChildren()
if value <= 5:
wx.StaticBitmap(self.myButton1, -1, self.Blue, (0, 0))
self.mainPanel.Layout()
else:
wx.StaticBitmap(self.myButton1, -1, self.Green, (0, 0))
self.mainPanel.Layout()
class myThread(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
while True:
result = random.randrange(0,10)
wx.CallAfter(pub.sendMessage, 'Update', value=result)
#Uncomment the following line to avoid the crash!!!
#time.sleep(1)
if __name__=='__main__':
app = wx.App()
frame = gui(parent=None, id=-1, title="Demo")
frame.Show()
myThread()
app.MainLoop()

However if I add the following line after wx.CallAfter() it works fine:


time.sleep(1)

Thanks for your time!



The problem is probably due to overflowing the Windows message queue. There are several tickets about this bug in wxWidgets bug tracker and some of its occurrences have been fixed, but probably not all.


In any case, even if we manage to always avoid the overflow, it's still a bad idea to flood the main thread with events like this (because every call to wx.CallAfter() is morally equivalent to an event). In real life situations, the background thread would be doing some work in between them, so this is unlikely to happen, but if you really need to make it work in such toy example, using sleep() is probably actually the right thing to do.


0 commentaires:

Enregistrer un commentaire