asit_dhal
asit_dhal

Reputation: 1269

QThread workaround in a Basic GUI

Here is the sample code

import sys, time
from PyQt4 import QtCore, QtGui

class MyApp(QtGui.QWidget):

    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setGeometry(300, 300, 280, 600)
        self.setWindowTitle('threads')
        self.layout = QtGui.QVBoxLayout(self)
        self.testButton = QtGui.QPushButton("test")
        self.connect(self.testButton, QtCore.SIGNAL("released()"), self.test)
        self.listwidget = QtGui.QListWidget(self)
        self.layout.addWidget(self.testButton)
        self.layout.addWidget(self.listwidget)

    def add(self, text):
        print "Add: ", text
        self.listwidget.addItems(text)
        self.listwidget.sortItems()

#    def addBatch(self, text="test", iters=6, delay=0.3):
#        for i in range(iters):
#            time.sleep(delay)
#            self.add(text + "  " + str(i))

    def test(self):
        self.listwidget.clear()
        #self.addBatch("_non_thread", iters=6, delay=0.3)
        self.workThread = WorkThread()
        self.connect(self.workThread, QtCore.SIGNAL("update(QString"), self.add)
        self.workThread.start()

class WorkThread(QtCore.QThread):

    def __init__(self):
        QtCore.QThread.__init__(self)

    def __del__(self):
        self.wait()

    def run(self):
        for i in range(6):
            time.sleep(0.3)
            self.emit(QtCore.SIGNAL('update(QString'), "from work thread " + str(i))
        return

app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
app.exec_()

Here I have a basic GUI with a listwidget and a push button. When I press the push button, I program should wait a moment and display a string in that listwidget. The WorkThread class does the waiting stuff and after waiting it emits a signal. But when I run the program, only I can see the GUI and nothing is displayed in the listwidget.

Can somebody tell me what is the reason behind this and how to fix this ?

Upvotes: 0

Views: 747

Answers (2)

Avaris
Avaris

Reputation: 36715

QListWidget.addItems expects a list of items but you're giving it a single QString. You should use .addItem.

There are also a few minor corrections. You don't need to implement __del__ in your thread. You can skip __init__ if you're not doing additional stuff. And you should use new style signals and connections.

Here is the result with all corrections:

import sys, time
from PyQt4 import QtCore, QtGui


class MyApp(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setGeometry(300, 300, 280, 600)
        self.setWindowTitle('threads')
        self.layout = QtGui.QVBoxLayout(self)
        self.testButton = QtGui.QPushButton("test")
        self.testButton.clicked.connect(self.test)
        self.listwidget = QtGui.QListWidget(self)
        self.layout.addWidget(self.testButton)
        self.layout.addWidget(self.listwidget)

    def add(self, text):
        print "Add: ", type(text)
        self.listwidget.addItem(text)
        self.listwidget.sortItems()

#    def addBatch(self, text="test", iters=6, delay=0.3):
#        for i in range(iters):
#            time.sleep(delay)
#            self.add(text + "  " + str(i))

    def test(self):
        self.listwidget.clear()
        #self.addBatch("_non_thread", iters=6, delay=0.3)
        self.workThread = WorkThread()
        self.workThread.update.connect(self.add)
        self.workThread.start()


class WorkThread(QtCore.QThread):
    update = QtCore.pyqtSignal(str)

    def run(self):
        for i in range(6):
            time.sleep(0.3)
            self.update.emit("from work thread " + str(i))

app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
sys.exit(app.exec_())

Upvotes: 2

Aaron Digulla
Aaron Digulla

Reputation: 328594

The PyQtWiki contains a pretty elaborate example how to send signals from a background thread to the UI. Apparently, no special magic is necessary as long as you QThread to implement your thread.

But I noticed that you use the signal released() to connect the button with the method test(). Did you try clicked()?

Upvotes: 1

Related Questions