How to make pulsing progress bar in wxpython when running command? - python-3.x

I'd like to indicate that my program is running and didn't freeze with a pulsing progress bar. The command that would run in the background is this:
os.system('apt install program etc...')
It'll start on button press and I'd like to show a popup progress dialog during the process.
Here's the code of the releated part:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import wx
import threading
import common as g
class myThread (threading.Thread):
def __init__(self, threadID, name):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
def run(self):
print ("Starting " + self.name)
my_thread()
print ("Exiting " + self.name)
class myThread2 (threading.Thread):
def __init__(self, threadID, name):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
def run(self):
print ("Starting " + self.name)
my_thread2()
print ("Exiting " + self.name)
def my_thread():
os.system('apt update')
def my_thread2():
dlg = wx.ProgressDialog('Test', 'Please wait..', style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_CAN_ABORT | wx.STAY_ON_TOP)
test = OtherFrame(title='progres')
counter = 1
while g.th.isAlive():
print('HEEYY')
wx.MilliSleep(300)
dlg.Pulse("Doing computation %d"%counter)
test.Show()
counter += 1
class OtherFrame(wx.Frame):
def __init__(self, title, parent=None):
wx.Frame.__init__(self, parent=parent, title=title, size=(700, 400))
self.Centre()
self.InitUI()
self.Show()
def InitUI(self):
gs = wx.GridSizer(1, 1, 7, 7)
update = wx.Button(self,label = 'Check for system Updates')
gs.Add(update,28,wx.EXPAND)
update.Bind(wx.EVT_BUTTON, self.OnUpdate)
self.SetSizer(gs)
def OnUpdate(self, e):
g.th = myThread(1, "Thread-1")
thread2 = myThread2(2, "Thread-2")
thread2.start()
g.th.start()
g.th.join()
thread2.join()
def main():
app = wx.App()
f1 = OtherFrame(title='frame')
f1.Show()
app.MainLoop()
if __name__ == '__main__':
main()
The text 'HEEYY' appears in the right time on the right place, but the dialog doesn't show up.

You appear to be trying to use 1 thread to determine if the other one is still running.
There is a simpler way, see below:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import wx
import threading
#import common as g
class myThread (threading.Thread):
def __init__(self, threadID, name):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
def run(self):
print ("Starting " + self.name)
os.system('apt update')
print ("Exiting " + self.name)
class OtherFrame(wx.Frame):
def __init__(self, title, parent=None):
wx.Frame.__init__(self, parent=parent, title=title, size=(700, 400))
self.Centre()
self.InitUI()
self.Show()
def InitUI(self):
gs = wx.GridSizer(1, 1, 7, 7)
update = wx.Button(self,label = 'Check for system Updates')
gs.Add(update,28,wx.EXPAND)
update.Bind(wx.EVT_BUTTON, self.OnUpdate)
self.SetSizer(gs)
def OnUpdate(self, e):
t1 = myThread(1, "Thread-1")
t1.start()
counter = 0
dlg = wx.ProgressDialog('Test', 'Please wait..', style=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_CAN_ABORT | wx.STAY_ON_TOP)
while t1.isAlive():
print('HEEYY')
wx.MilliSleep(300)
dlg.Pulse("Doing computation %d"%counter)
wx.GetApp().Yield()
counter += 1
del dlg
t1.join()
def main():
app = wx.App()
f1 = OtherFrame(title='frame')
f1.Show()
app.MainLoop()
if __name__ == '__main__':
main()

Related

PyQt Progress Bar Update using Thread

I've been writing a program that used a MyWindow(QTableWidget) with a thread. A progress bar is displayed above the sub-window(self.win) displayed as a pop-up.
I want a green bar on the status bar to be displayed consecutively, however after resetting the Spyder-kernel, the green bar does not output continuously. And I want to run the 'stop'/'continue' alternately every time I click the push button. This hasn't been resolved for almost three days.
import sys, time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot, QRect
from PyQt5.QtWidgets import *
progVal = 0
class thread(QThread):
signalTh = pyqtSignal(int)
def __init__(self, *args):
super().__init__()
self.flag = True
def run(self):
global progVal
if self.flag:
self.signalTh.emit(progVal)
time.sleep(0.1)
def stop(self):
self.flag = False
self.quit()
self.wait(2)
class MyWindow(QTableWidget):
def __init__(self):
global progVal
super().__init__()
self.setupUi()
self.show()
self.test = thread(None)
self.test.signalTh.connect(self.signal_function)
self.test.run()
self.saveData()
def saveData(self):
global progVal
counts = range(1, 51)
for row in counts:
progVal = int(row/len(counts)*100)
self.test.signalTh.emit(progVal)
time.sleep(0.1)
def click1_function(self):
if self.test.flag:
self.test.stop()
self.pb_start.setText('Start!')
else:
self.test.flag = True
self.test.run()
self.pb_start.setText('Stop!')
#pyqtSlot(int)
def signal_function(self, val):
self.progress.setValue(val)
self.progress.update()
self.win.update()
self.update()
def setupUi(self):
self.resize(500, 400)
self.pb_start = QPushButton(self)
self.pb_start.setGeometry(QRect(80, 20, 100, 50))
self.pb_start.setText("Start")
self.pb_start.clicked.connect(self.click1_function)
self.win = QDialog(self)
self.win.resize(330, 100)
self.progress = QProgressBar(self.win)
self.progress.setGeometry(10, 10, 300, 30)
self.progress.setMaximum(100)
self.win.show()
def closeEvent(self, event):
quit_msg = "Are you sure you want to exit the program?"
reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No)
if reply == QMessageBox.Yes:
self.test.stop()
event.accept()
else:
event.ignore()
if __name__ == "__main__":
app = QApplication(sys.argv)
myApp = MyWindow()
myApp.show()
app.exec_()

Connecting external threaded log to PyQt5 QPlainTextEdit

I'm new to PyQt and handlers in general, I tried to read from every repo I found but I can't figure out how to fix my issue, as you can see in my code, I'm executing logging thread in the background and I'm trying to show the logs in my QPlainTextEdit console - for some reason I can see the logs in my terminal and the text_box doesn't get the logs at all,
I will appreciate a lot your smart help.
import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import os
import threading
import json
class ConsolePanelHandler(logging.Handler):
def __init__(self, stream):
# super().__init__()
logging.Handler.__init__(self)
# logging.StreamHandler.__init__(self, stream)
self.stream = stream
def handle(self, record):
rv = self.filter(record)
if rv:
self.acquire()
try:
self.emit(record)
finally:
self.release()
return rv
def emit(self, record):
try:
stream = self.stream
stream(self.format(record))
except RecursionError:
raise
except Exception:
self.handleError(self.format(record))
def thread():
for index in range(20):
logging.warning('scheiBe '+str(index))
time.sleep(1)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.continue_ = QPushButton("Continue")
self.continue_.setStyleSheet("background-color: green")
self.continue_.setFont(QFont('SansSerif', 10))
self.continue_.setFixedSize(QSize(300, 22))
self.pause = QPushButton("Pause")
self.pause.setStyleSheet("background-color: orange")
self.pause.setFont(QFont('SansSerif', 10))
self.pause.setFixedSize(QSize(300, 22))
self.stop = QPushButton("Stop")
self.stop.setStyleSheet("background-color: #FD4B4B")
self.stop.setFont(QFont('SansSerif', 10))
self.stop.setFixedSize(QSize(300, 22))
self.text_box = QPlainTextEdit()
self.text_box.setPlaceholderText("Bugs will be printed here")
self.text_box.setReadOnly(True)
logging.getLogger().addHandler(self.text_box)
logging.getLogger().setLevel(logging.DEBUG)
ConsolePanelHandler(self.appendDebug , logging.DEBUG)
self.text_box.moveCursor(QTextCursor.End)
layout.addWidget(self.continue_)
layout.addWidget(self.pause)
layout.addWidget(self.stop)
layout.addWidget(self.text_box)
self.w = QWidget()
self.w.setLayout(layout)
self.setCentralWidget(self.w)
thread1 = threading.Thread(target=thread, args=(), daemon=True)
thread1.start()
self.show()
def closeEvent(self, event):
close = QMessageBox()
close.setText("Are you sure want to stop and exit?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close = close.exec()
if close == QMessageBox.Yes:
sys.exit()
else:
event.ignore()
def appendDebug(self, string):
self.text_box.appendPlainText(string +'\n')
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
sys.exit(app.exec())
First, you should not pass the function that updates the text_area instead you should create a pyqtSignal which updates the text_area and pass it to ConsolePanelHandler.
Add ConsolePanelHandler as handler not text_area to logging.getLogger().addHandler()
and it is recommended to use QThread instead of threading.Thread
here is the complete updated code.
# import pandas as pd
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import os
import sys
import threading
import json
import logging
class ConsolePanelHandler(logging.Handler):
def __init__(self, sig):
# super().__init__()
logging.Handler.__init__(self)
# logging.StreamHandler.__init__(self, stream)
self.stream = sig
def handle(self, record):
rv = self.filter(record)
if rv:
self.acquire()
try:
self.emit(record)
finally:
self.release()
return rv
def emit(self, record):
try:
self.stream.emit(self.format(record))
except RecursionError:
raise
except Exception:
self.handleError(record)
class thread(QThread):
def run(self) -> None:
for index in range(20):
logging.warning('scheiBe ' + str(index))
self.sleep(1)
class MainWindow(QMainWindow):
sig = pyqtSignal(str)
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.continue_ = QPushButton("Continue")
self.continue_.setStyleSheet("background-color: green")
self.continue_.setFont(QFont('SansSerif', 10))
self.continue_.setFixedSize(QSize(300, 22))
self.pause = QPushButton("Pause")
self.pause.setStyleSheet("background-color: orange")
self.pause.setFont(QFont('SansSerif', 10))
self.pause.setFixedSize(QSize(300, 22))
self.stop = QPushButton("Stop")
self.stop.setStyleSheet("background-color: #FD4B4B")
self.stop.setFont(QFont('SansSerif', 10))
self.stop.setFixedSize(QSize(300, 22))
self.c = ConsolePanelHandler(self.sig)
self.text_box = QPlainTextEdit()
self.text_box.setPlaceholderText("Bugs will be printed here")
self.text_box.setReadOnly(True)
logging.getLogger().addHandler(self.c)
logging.getLogger().setLevel(logging.DEBUG)
self.sig.connect(self.appendDebug)
self.text_box.moveCursor(QTextCursor.End)
self.layout.addWidget(self.continue_)
self.layout.addWidget(self.pause)
self.layout.addWidget(self.stop)
self.layout.addWidget(self.text_box)
self.w = QWidget()
self.w.setLayout(self.layout)
self.setCentralWidget(self.w)
self.thread1 = thread(self) # self is parent for Qthread so Qthread will be destroyed when it's parent no longer exist
self.thread1.start()
self.show()
def closeEvent(self, event):
close = QMessageBox()
close.setText("Are you sure want to stop and exit?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close = close.exec()
if close == QMessageBox.Yes:
self.thread1.terminate()
sys.exit()
else:
event.ignore()
#pyqtSlot(str)
def appendDebug(self, string):
self.text_box.appendPlainText(string + '\n')
if __name__ == "__main__":
app = QApplication([])
window = MainWindow()
sys.exit(app.exec())

Pyqt5 stop QThread worker on QAction

hello I have QTheard worker that start with click at QAction.
....
self.start_update = QAction('&Start', self)
self.start_update.triggered.connect(self._start_thread)
self.stop_update.setVisible(True)
self.stop_update.triggered.connect(self._stop_thread)
self.stop_update.setVisible(False)
...
...
def _start_thread(self):
self.start_update.setVisible(False)
self.stop_update.setVisible(True)
self.myworker.start()
...
...
def _stop_thread(self):
self.myworker.stop() # That close app with error
self.stop_update.setVisible(False)
self.start_update.setVisible(True)
...
Please help how to close terminate Worker correctly. Atm worker have __del__ and run (logic) method. Maybe need to add some method for correct worker closing?
Your application might look like this:
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class AThread(QThread):
threadSignalAThread = pyqtSignal(int)
def __init__(self):
super().__init__()
def run(self):
count = 0
while count < 1000:
QThread.msleep(200)
count += 1
self.threadSignalAThread.emit(count)
class MsgBoxAThread(QDialog):
def __init__(self):
super().__init__()
layout = QVBoxLayout(self)
self.label = QLabel("")
layout.addWidget(self.label)
close_btn = QPushButton("Close window")
layout.addWidget(close_btn)
close_btn.clicked.connect(self.close)
self.setGeometry(900, 300, 400, 80)
self.setWindowTitle('MsgBox AThread(QThread)')
class Example(QMainWindow):
def __init__(self, parent=None, *args):
super().__init__(parent, *args)
self.setWindowTitle("Pyqt5 stop QThread worker on QAction")
self.setGeometry(550, 300, 300, 300)
centralWidget = QWidget(self)
self.setCentralWidget(centralWidget)
layout = QVBoxLayout(centralWidget)
self.lbl = QLabel("Start")
layout.addWidget(self.lbl)
bar = self.menuBar()
barThread = bar.addMenu('Thread')
quit = bar.addMenu('Quit')
quit.aboutToShow.connect(app.quit)
self.start_update = QAction('&Start', self)
self.start_update.setShortcut('Ctrl+S')
self.start_update.triggered.connect(self._start_thread)
self.stop_update = QAction('Sto&p', self)
self.stop_update.setShortcut('Ctrl+P')
self.stop_update.setVisible(False)
self.stop_update.triggered.connect(self._stop_thread)
barThread.addAction(self.start_update)
barThread.addAction(self.stop_update)
self.msg = MsgBoxAThread()
self.myworker = None
self.counter = 0
self.timer = QTimer()
self.timer.setInterval(1000)
self.timer.timeout.connect(self.recurring_timer)
self.timer.start()
self.show()
def recurring_timer(self):
self.counter += 1
self.lbl.setText(" Do something in the GUI: <b> %d </b>" % self.counter)
def _start_thread(self):
self.start_update.setVisible(False)
self.stop_update.setVisible(True)
self.myworker = AThread()
self.myworker.threadSignalAThread.connect(self.on_threadSignalAThread)
self.myworker.finished.connect(self.finishedAThread)
self.myworker.start()
def finishedAThread(self):
self.myworker = None
self.start_update.setVisible(True)
self.stop_update.setVisible(False)
def on_threadSignalAThread(self, value):
self.msg.label.setText(str(value))
if not self.msg.isVisible():
self.msg.show()
def _stop_thread(self):
self.stop_update.setVisible(False)
self.start_update.setVisible(True)
self.myworker.terminate()
self.myworker = None
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Question',
"Are you sure you want to close the application?",
QMessageBox.Yes,
QMessageBox.No)
if reply == QMessageBox.Yes:
if self.myworker:
self.myworker.quit()
del self.myworker
self.msg.close()
super(Example, self).closeEvent(event)
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
#ex.show()
sys.exit(app.exec_())

PySide QThread moveToThread subclass locks up main thread

I'm having an issue when I try to subclass my worker class the main UI thread locks up and becomes unresponsive until the Worker Thread has finished. I'm at a loss here and suspect something with how the GIL interacts with inheritance?
In MainWindow.clicked() these two lines:
#self.worker = Worker() # This works
self.worker = SubWorker() # This locks up main thread
Here is my sample code that reproduces this:
from PySide import QtGui, QtCore
import sys
import time
class Worker(QtCore.QObject):
started = QtCore.Signal()
progress = QtCore.Signal(int)
finished = QtCore.Signal(bool)
def __init__(self, parent=None):
QtCore.QObject.__init__(self, parent)
self.lock = QtCore.QMutex()
#QtCore.Slot()
def start(self):
self.flag_to_quit = False
try:
self.started.emit()
time.sleep(5)
time.sleep(0.5)
for i in range(10):
self.progress.emit(i)
time.sleep(1)
with QtCore.QMutexLocker(self.lock):
print(self.flag_to_quit)
if self.flag_to_quit:
raise RuntimeError("Requested to quit.")
self.finished.emit(True)
except Exception as ex:
print(ex)
self.finished.emit(False)
finally:
print("start() finished!")
##QtCore.Slot()
def stop(self):
print("Stopping...")
with QtCore.QMutexLocker(self.lock):
self.flag_to_quit = True
#QtCore.Slot()
def __quit_handler(self):
self.flag_to_quit = True
class SubWorker(Worker):
def __init__(self):
Worker.__init__(self)
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setLayout(QtGui.QVBoxLayout())
self.label = QtGui.QLabel("")
self.layout().addWidget(self.label)
self.button = QtGui.QPushButton("Start Thread")
self.layout().addWidget(self.button)
self.button.clicked.connect(self.clicked)
def closeEvent(self, event):
if hasattr(self, "_thread") and self._thread:
self.worker.flag_to_quit = True
self._thread.quit()
print("waiting for stop...")
self._thread.wait()
self._thread.deleteLater()
#QtCore.Slot()
def worker_started(self):
self.label.setText("Started!")
#QtCore.Slot(int)
def worker_progress(self, interval):
self.label.setText(str(interval))
#QtCore.Slot()
def worker_finished(self, success):
msg = "Finished "
msg += "successfully!" if success else "with errors"
self.label.setText(msg)
#QtCore.Slot()
def clicked(self):
if hasattr(self, "_thread") and self._thread:
self.worker.stop()
self._thread.quit()
print("waiting for stop...")
self._thread.wait()
self._thread.quit()
self._thread.deleteLater()
self._thread = QtCore.QThread()
#self.worker = Worker() # This works
self.worker = SubWorker() # This locks up main thread
self.worker.started.connect (self.worker_started, QtCore.Qt.QueuedConnection)
self.worker.progress.connect(self.worker_progress, QtCore.Qt.QueuedConnection)
self.worker.finished.connect(self.worker_finished, QtCore.Qt.QueuedConnection)
self.worker.moveToThread(self._thread)
self._thread.started.connect(self.worker.start)
self._thread.finished.connect(self.worker.stop)
self._thread.start()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
app.exec_()
sys.exit()
Version information:
Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
edit:
Looks like QThread::moveToThread() is failing with Subclasses. this is output of QtCore.QThread.currentThread() in various places:
#self.worker = Worker():
Main:<PySide.QtCore.QThread object at 0x7ff89df384d0>
Real thread: <PySide.QtCore.QThread object at 0x7ff89df383f8>
Worker:<PySide.QtCore.QThread object at 0x7ff89df384d0>
#self.worker = SubWorker()
Main:<PySide.QtCore.QThread object at 0x7f968602c3b0>
Real thread: <PySide.QtCore.QThread object at 0x7f968602c488>
Worker:<PySide.QtCore.QThread object at 0x7f968602c488>
Okay I managed to fix this by doing it the "Wrong" way by inheriting QThread and overriding the run method. I'm not sure why or how but it works.
from PySide import QtGui, QtCore
import sys
import time
class Worker(QtCore.QThread):
_started = QtCore.Signal()
progress = QtCore.Signal(int)
_finished = QtCore.Signal(bool)
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
self.lock = QtCore.QMutex()
#QtCore.Slot()
def run(self):
self.flag_to_quit = False
print("Worker:" + str(QtCore.QThread.currentThread()))
try:
self._started.emit()
time.sleep(2)
for i in range(10):
self.progress.emit(i)
time.sleep(1)
with QtCore.QMutexLocker(self.lock):
if self.flag_to_quit:
raise RuntimeError("Requested to quit.")
self._finished.emit(True)
except Exception as ex:
print(ex)
self._finished.emit(False)
finally:
print("start() finished!")
#QtCore.Slot()
def stop(self):
with QtCore.QMutexLocker(self.lock):
self.flag_to_quit = True
#QtCore.Slot()
def __quit_handler(self):
self.flag_to_quit = True
class SubWorker(Worker):
def __init__(self, parent=None):
Worker.__init__(self, parent)
#QtCore.Slot()
def start(self):
Worker.start(self)
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setLayout(QtGui.QVBoxLayout())
self.label = QtGui.QLabel("")
self.layout().addWidget(self.label)
self.button = QtGui.QPushButton("Start Thread")
self.layout().addWidget(self.button)
self.button.clicked.connect(self.clicked)
def closeEvent(self, event):
self.hide()
if hasattr(self, "worker") and self.worker:
self.worker.stop()
self.worker.quit()
self.worker.wait()
self.worker.deleteLater()
#QtCore.Slot()
def worker_started(self):
self.label.setText("Started!")
#QtCore.Slot(int)
def worker_progress(self, interval):
self.label.setText(str(interval))
#QtCore.Slot()
def worker_finished(self, success):
msg = "Finished "
msg += "successfully!" if success else "with errors!"
self.label.setText(msg)
def clicked(self):
if hasattr(self, "worker") and self.worker:
self.worker.stop()
self.worker.quit()
self.worker.wait()
self.worker.deleteLater()
print("Main:" + str(QtCore.QThread.currentThread()))
#self.worker = Worker() # This works
self.worker = SubWorker() # This locks up main thread
self.worker._started.connect (self.worker_started)
self.worker.progress.connect(self.worker_progress)
self.worker._finished.connect(self.worker_finished)
self.worker.start()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
app.exec_()
sys.exit()

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 ?
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_())
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()?

Resources