PythonCard - My app stuck when button clicked

Dave Angel davea at ieee.org
Thu May 14 08:37:19 EDT 2009


daved170 wrote:
> On May 13, 7:42 pm, Dave Angel <da... at ieee.org> wrote:
>   
>> daved170 wrote:
>>     
>>> Hi there,
>>> I'm newbie in pythonCard.
>>> I have an application with 2 buttons : START , STOP
>>> Start execute a while(1) loop that execute my calculations.
>>> Stop suppose to raise a flag that will end that loop.
>>>       
>>> Whenever I pish the START button my GUI is stuck. the calculation
>>> executes but I can't push the STOP button.
>>>       
>>> I added thread that START start a thread that execute my calculations.
>>> I also added a Global variable that will hold the indication if the
>>> loop should continue.
>>> The problem now is that the thread ignore that variable and loop
>>> forever.
>>>       
>>> Is there a simple way to make sure that the GUI won't stuck (without
>>> threads)?
>>> And if there isn't such way I would appriciet it very much if anyone
>>> could post an example of how to make my thread read that variable
>>> Thanks
>>> Dave
>>>       
>> I don't know PythonCard, but most GUI's are similar enough that the
>> concepts will work, even though the details differ.  I'll assume that
>> PythonCard has a traditional event loop, from which all events are
>> dispatched.
>>
>> If your loop is fairly small, then you should keep it to one thread.  
>> Debugging it will usually be much easier.  The trick is to break the
>> task into pieces (each piece might be once around what is now a loop),
>> and invoke one piece each time the event loop empties.  I can't tell you
>> how to do that without seeing your loop, but it's not usually very hard.
>>
>> Now, there is some way of POSTing an event to the event loop.  That puts
>> the event *after* all the events that are already there, but returns
>> control immediately.  So create a custom event, and POST it from the
>> START button's button-pressed event.  That will fire off one "loop" of
>> the special task, in other words, make one function call to your new
>> function.  Then at the end of the function, POST it again, unless the
>> STOP button has been pressed in the meantime.
>>
>> An optimization for this is to use coroutines, which are usually done
>> with a generator.  It's much trickier to describe, but much easier to
>> accomplish.  Roughly, you'd take your existing loop, and put a yield
>> statement in it at appropriate place(s).  Then the custom event is
>> simply a call to the .next() function of that generator.
>>
>> Now, threading isn't that tough either, depending on how much data is
>> being shared between the thread and the main program.  You say that
>> sharing a global flag isn't working, but it should.  So how about if you
>> show us some code, and somebody'll spot the trouble.  For example, is
>> the thread defined in the same module as the App?  Global only shares
>> between a single module.  Another reason globals might seem to fail is
>> if you tried to do mutual imports between two or more modules.  (A
>> imports B, which imports A).  Sometimes that fails in mysterious ways.
>>
>> Make a simple (stripped) example of what you're trying, and we'll try to
>> find the problem.  Without concrete code, we end up with ambiguities
>> like the above usage of two different meanings for "the loop."- Hide quoted text -
>>
>> - Show quoted text -
>>     
>
> Thank's Dave,
> Here my code, It's a very simple app. the Start button starts a TCP/IP
> communication and the Stop should dtop it and kill the client.
> I'll be thankful if you'll be able to spot my mistake.
> Thanks again
> Dave
>
> #Global Variable
> bStopLoop =alse
>
> #Global Function
> def execute(sockObj):
>    while(!bStopLoop):
>       str =ockObj.recv(1024)
>       tmpStr =Hello " + str
>       sockObj.send(tmpStr)
>
> #Thread handle class
> class myThread(threading.Thread):
>    def __init__(self,sockObj):
>       threading.Thread.__init__(self)
>       bStopLoop =alse
>       self.sockObj =ockObj
>
>    def run(self):
>       execute(self.SockObj)
>
> # GUI
> class GUI(model.Background)
>
>    def on_Start_mouseclick(self,event):
>    try:
>       event.target.enable =alse
>       event.target.redraw()
>       self.components.Start.enable =alse
>       self.currThread =yThread(self.sockObj)
>       self.currThread.Start()
>       wx.SafeYield(self)
>       self.components.Start.enable =rue
>    except:
>       .....
>
>    def on_Stop_mouseclick(self,event):
>       bStopLoop =rue
>
>   
In the two methods that try to change bStopLoop, you don't declare it 
global.  Add the line "global bStopLoop"  to beginning of both 

on_Start_mouseclick() and on_Stop_mouseclick(), and (my preference) to function execute()

The semantics of global versus local variables for non-nested functions/methods is roughly:   if a function or method assigns to a name, it's taken to be a local, unless it's explicitly declared as global. 





More information about the Python-list mailing list