stopping a while loop

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

stopping a while loop

Post by Zolko »

Hello,

I have made an animation command that changes a variable between 2 values, and updates the assembly at each step. The code is extremely trivial:

Code: Select all

def onRun(self):
    # the selected variable
    varName = self.varList.currentText()
    begin   = self.minValue.value()
    end     = self.maxValue.value()
    step    = self.stepValue.value()
    varValue = begin
    while varValue <= end:
        setattr( self.Variables, varName, varValue )
        App.ActiveDocument.Model.recompute('True')
        Gui.updateGui()
        varValue += step
    return
It is launched when clicking on the button "Run" which is connected to the function by :

Code: Select all

self.OKButton.clicked.connect(self.onRun)
This all works well. Except that if I have made a mistake in the values, this loop can be very slow and long, so I have foreseen a Stop button to stop the loop in the middle. I imagined to connect the Stop button to a "break" in the while loop but Python (or Qt) doesn't accept that.

Is there a way to use this Stop button to halt that while loop ?

self.StopButton.clicked.connect(self.onStop)
try the Assembly4 workbench for FreCAD — tutorials here and here
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: stopping a while loop

Post by DeepSOIC »

You can call QtGui.QApplication.processEvents() from within the loop. That requires instance of qApp, and I have not been able to reliably obtain one from PySide2. Apparently it's buggy.

Another option is to use progress window. An example can be found in Macro Recompute Profiler. I don't know, but likely it is possible to use FreeCAD's progress bar in status window for this purpose as well.
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: stopping a while loop

Post by DeepSOIC »

Another approach (better, but more difficult/less readable code) is to use a timer and a state machine to drive your animation.
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

Re: stopping a while loop

Post by Zolko »

DeepSOIC wrote: Mon Dec 02, 2019 1:56 pm Another approach (better, but more difficult/less readable code) is to use a timer and a state machine to drive your animation.
I don't know what a state machine is, but that gave me an idea: I added a variable self.Run which is initialized to True, and I connect the Stop button to a function that sets it to False, and I check that variable in the while loop:

Code: Select all

while varValue <= end and self.Run:
   ...

def onStop(self):
    self.Run = False
    return
...
self.StopButton.clicked.connect(self.onStop)
And that does it. Thank-you
try the Assembly4 workbench for FreCAD — tutorials here and here
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: stopping a while loop

Post by DeepSOIC »

Zolko wrote: Mon Dec 02, 2019 2:16 pm I added a variable self.Run which is initialized to True, and I connect the Stop button to a function that sets it to False, and I check that variable in the while loop … And that does it.
Good to know, so Gui.updateGui is likely just a call to QApplication.processEvents, I persume. Otherwise, the button should not be pressable while your loop is running, because the event loop is blocked.
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: stopping a while loop

Post by openBrain »

DeepSOIC wrote: Mon Dec 02, 2019 1:49 pm You can call QtGui.QApplication.processEvents() from within the loop. That requires instance of qApp, and I have not been able to reliably obtain one from PySide2. Apparently it's buggy.
This is quite easily circumvent using QtGui.QApplication.instance().processEvents() ;)
Zolko wrote: Mon Dec 02, 2019 2:16 pm I don't know what a state machine is, but that gave me an idea: I added a variable self.Run which is initialized to True, and I connect the Stop button to a function that sets it to False, and I check that variable in the while loop:
You posted while I was compiling the small below example, but yes, you need to use a state variable.
However, running processEvents() as described by DeePSOIC should also be done. Try the simple below example, once as is and once with processEvents() line commented out (beware to save your data before) ;)

Code: Select all

from PySide import QtGui

class Infinite(QtGui.QMessageBox):

    def __init__(self):
        super(Infinite, self).__init__()
        self.run = False
        self.brun = self.addButton("Run", QtGui.QMessageBox.ActionRole)
        self.brun.clicked.disconnect()
        self.bstop = self.addButton("Stop", QtGui.QMessageBox.ActionRole)
        self.bstop.clicked.disconnect()
        self.addButton("Quit", QtGui.QMessageBox.ActionRole)
        self.setWindowTitle("Test")
        self.setText("Click on run")
        self.brun.clicked.connect(self.infiniteLoop)
        self.bstop.clicked.connect(self.stopLoop)

    def infiniteLoop(self):
        self.run = True
        while self.run:
            self.setText("Running...")
            QtGui.QApplication.instance().processEvents()
        self.setText("Stopped")

    def stopLoop(self):
        self.run = False

Infinite().exec_()
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: stopping a while loop

Post by openBrain »

DeepSOIC wrote: Mon Dec 02, 2019 2:38 pm Good to know, so Gui.updateGui is likely just a call to QApplication.processEvents, I persume. Otherwise, the button should not be pressable while your loop is running, because the event loop is blocked.
Fully agree with this ! :)
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: stopping a while loop

Post by DeepSOIC »

openBrain wrote: Mon Dec 02, 2019 2:42 pm QtGui.QApplication.instance()
thanks, will try it next time I need it.
Post Reply