Saar Drimer
Saar Drimer

Reputation: 1201

Waiting for a button click during the execution of a function in Pyside

I have multiple buttons. When I click one of them, I call a function that iterates over rows of a table (say, changes the background colour of the row). During the execution of this function, in the middle of the iteration, I'd like to "pause" and wait for another button to be clicked in order to resume the execution of the function. During this "pause" I'd like all other buttons (that is, the ones I'm not waiting to be clicked) to be disabled or ignored.

I've looked into QTimer and QThread, but I think that I'm unnecessarily over-complicating things. Looking for suggestions...

Upvotes: 1

Views: 3556

Answers (2)

qurban
qurban

Reputation: 3945

First of all you need to call QtGui.qApp.processEvents() method at the end or beginning of the iteration in order to make the gui responsive during the execution of the loop. Then you need to maintain a list of rows (say, self.allRows), in each iteration pop one row from the list change the background color and append it to a second list (say, self.doneRows). Also declare a boolean variable as False (say, self.pause = False) inside __init__ and add a check statement at the beginning of the loop, if the self.pause is True, break the loop. Then you need to add a slot to update the value of self.pause to True.

def pause_execution(self):
    self.pause = True
    # loop through all the buttons to make them disabled excluding the pause and resume buttons
    for btn in self.buttons:
        btn.setEnabled(False)
    QtGui.qApp.processEvents()

Connect Pause button's clicked signal to this slot. Now the loop will be broken and self.allRows contains only the rows with no background color changed yet. Create another slot to resume the loop again. This time the loop will change the background color of only remaining rows.

def resume(self):
    self.stop = False
    # loop through all the buttons that were disabled, to make them enabled (if you need to)
    for btn in self.buttons:
        btn.setEnabled(True)
    QtGui.qApp.processEvents()
    # call the method which contains the background color changing loop.

Upvotes: 3

László Papp
László Papp

Reputation: 53175

I think you are looking for this to execute on each method depending on the mouse button click:

myWidget.setDisabled(true)

Then, you could find all the children of the main window or the root widget whatever that is, this way:

widgets = form.findChildren(QtGui.QWidget)

Then, you could connect your push button click to the desired method as follows:

button.clicked.connect(setDisableWidgets)

So, here is a simple example:

import sys
from PySide.QtCore import *
from PySide.QtGui import *

g_disable = true
g_mainWidget = ...

def setDisableWidgets():
    ''' This will get more exciting when you have other widgets, too,  for sure '''
    widgets = mainWidget.findChildren(QtGui.QWidget)

    for widget in widgets:
        # filter out push button though based objectName for instance
        widget.setDisabled(disable)

    # Toggle for the next run
    disable = not disable

app = QApplication(sys.argv)
button = QPushButton("Click me")
button.clicked.connect(setDisableWidgets)
button.show()
app.exec_()

In your QThread run, you could extend the code that runs that function the way that, for instance is checks against the disable variable after processing each row or even small units if you wish and if that is false, it runs QThread.sleep(100) or so, and then wakes up for a check against disable. If it is false, then it continues the execution, otherwise sleeps back.

Here is the pseudo code:

class MyThread (QThread):
    def run():
        isEnd = false
        while not isEnd:
            while disable:
                self.msleep(200)
            # Process next row
            # if we are done, isEnd = true

Upvotes: 2

Related Questions