fredrik
fredrik

Reputation: 10291

How to show PySide/PyQt UI and auto-run one of its methods?

I wish to open a PySide/PyQt window and automatically start executing a method, which will show a progress in the UI while it is executing.

With the code below, the ui is not shown until the process has completed, thus you cannot see the progress. How can I change the code to see the progress before the process has completed?

from PySide import QtGui
import time

class MyApp(QtGui.QMainWindow)
    def __init__(self, parent=None):
        super(MyApp, self).__init__(parent)

        # Setup
        self.centralWidget = QtGui.QWidget(self)
        self.setCentralWidget(self.centralWidget)
        self.setup_UI()

        # Execute process!
        self.process()

    def setup_UI(self):
        ''' Attach widgets to window '''
        self.mainLayout=QtGui.QVBoxLayout(self.centralWidget)
        self.list_widget = QtGui.QListWidget()
        self.progress_bar = QtGui.QProgressBar()
        self.mainLayout.addWidget(self.list_widget)
        self.mainLayout.addWidget(self.progress_bar)

    def process(self):
        ''' Manipulate the ui '''
        self.progress_bar.setMaximum(0)
        self.progress_bar.setMaximum(10)

        for x in range(0, 10):
            time.sleep(1)
            self.list_widget.addItem('Item ' + str(x))
            self.progress_bar.setValue(x)



my_app = MyApp()
my_app.show()

Upvotes: 1

Views: 1173

Answers (2)

ekhumoro
ekhumoro

Reputation: 120768

The example can be made to work quite easily by starting the processing with a single-shot timer and then calling processEvents within the loop to update the GUI:

    # Execute process!
    QtCore.QTimer.singleShot(100, self.process)

    ...

    for x in range(0, 10):
        time.sleep(1)
        ...
        QtGui.qApp.processEvents(QtCore.QEventLoop.AllEvents, 50)

However, there is no guarantee that this type of approach will work with a more realistic example. You may end up needing to use threads or multiprocessing - it all depends on the specific kind of processing you are going to do.

Upvotes: 1

Slava Bacherikov
Slava Bacherikov

Reputation: 2066

Your main problem that you are blocking qt main thread by calling time.sleep. To solve this issue you have two options. One of them is using threading. Another option is change your code to asynchronous like this:

from PySide import QtGui, QtCore
import time
import sys

class MyApp(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MyApp, self).__init__(parent)

        # Setup
        self.centralWidget = QtGui.QWidget(self)
        self.setCentralWidget(self.centralWidget)
        self.setup_UI()

        # Execute process!
        self.set_process()
        self.timer = QtCore.QTimer()
        self.i = 0
        self.timer.timeout.connect(self.update)
        self.timer.start(1000)

    def setup_UI(self):
        ''' Attach widgets to window '''
        self.mainLayout=QtGui.QVBoxLayout(self.centralWidget)
        self.list_widget = QtGui.QListWidget()
        self.progress_bar = QtGui.QProgressBar()
        self.mainLayout.addWidget(self.list_widget)
        self.mainLayout.addWidget(self.progress_bar)

    def set_process(self):
        ''' Manipulate the ui '''
        self.progress_bar.setMaximum(0)
        self.progress_bar.setMaximum(10)

    def update(self):
        if self.i > 9:
            self.timer.stop()

        self.list_widget.addItem('Item ' + str(self.i))
        self.progress_bar.setValue(self.i)
        self.i += 1


def main():
    app = QtGui.QApplication(sys.argv)
    my_win = MyApp()
    my_win.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

This example are using Qtimer object for updating progress bar with delay.

Upvotes: 3

Related Questions