PythonCard - My app stuck when button clicked

D

daved170

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
 
A

Adam Gaskins

I second this.

I am very interested in PyCard having just discovered it in your message
here. I know I'll run in to this same problem in my application that will
run test routines that must have a mechanism to abort.

Sorry for the lack of any help here...

-Adam
 
D

Dave Angel

daved170 said:
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."
 
D

daved170

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 = False

#Global Function
def execute(sockObj):
while(!bStopLoop):
str = sockObj.recv(1024)
tmpStr = "Hello " + str
sockObj.send(tmpStr)

#Thread handle class
class myThread(threading.Thread):
def __init__(self,sockObj):
threading.Thread.__init__(self)
bStopLoop = False
self.sockObj = sockObj

def run(self):
execute(self.SockObj)

# GUI
class GUI(model.Background)

def on_Start_mouseclick(self,event):
try:
event.target.enable = False
event.target.redraw()
self.components.Start.enable = False
self.currThread = myThread(self.sockObj)
self.currThread.Start()
wx.SafeYield(self)
self.components.Start.enable = True
except:
.....

def on_Stop_mouseclick(self,event):
bStopLoop = True
 
D

Dave Angel

daved170 said:
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.
 
M

MRAB

daved170 said:
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 = False

#Global Function
def execute(sockObj):
while(!bStopLoop):

That should be:

while not bStopLoop:
str = sockObj.recv(1024)
tmpStr = "Hello " + str
sockObj.send(tmpStr)

#Thread handle class
class myThread(threading.Thread):
def __init__(self,sockObj):
threading.Thread.__init__(self)
bStopLoop = False

'bStopLoop' is local to __init__. Add:

global bStopLoop
self.sockObj = sockObj

def run(self):
execute(self.SockObj)

# GUI
class GUI(model.Background)

def on_Start_mouseclick(self,event):
try:
event.target.enable = False
event.target.redraw()
self.components.Start.enable = False
self.currThread = myThread(self.sockObj)
self.currThread.Start()
wx.SafeYield(self)
self.components.Start.enable = True
except:
.....

def on_Stop_mouseclick(self,event):
bStopLoop = True

'bStopLoop' is local to on_Stop_mouseclick. Add:

global bStopLoop
 
D

daved170

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.- Hide quoted text -

- Show quoted text -

Thanks Dave. It works! It solved that problem. Now all i need is to
stop the socket in a way that whenever I push the Start button again
my app won't raise network connectio, but I think I'll handle that by
myself.
Thank's again
Dave.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top