PyQt5 interface unresponsive when waiting too long - python

I am working on a GUI in python 3.5 with PyQt5 for a small chat bot. The problem i have is that the pre-processing, post-processing and brain are taking too much time to give back the answer for the user provided input.
The GUI is very simple and looks like this: http://prntscr.com/dsxa39 it loads very fast without connecting it to other modules. I mention that using sleep before receiving answer from brain module will still make it unresponsive.
self.conversationBox.append("You: "+self.textbox.toPlainText())
self.textbox.setText("")
time.sleep(20)
self.conversationBox.append("Chatbot: " + "message from chatbot")
this is a small sample of code, the one that i need to fix.
And this is the error I encounter: http://prnt.sc/dsxcqu
I mention that I've searched for the solution already and everywhere I've found what I've already tried, to use sleep. But again, this won't work as it makes the program unresponsive too.

Slow functions, such as sleep, will always block unless they are running asynchronously in another thread.
If you want to avoid threads a workaround is to break up the slow function. In your case it might look like:
for _ in range(20):
sleep(1)
self.app.processEvents()
where self.app is a reference to your QApplication instance. This solution is a little hacky as it will simply result in 20 short hangs instead of one long hang.
If you want to use this approach for your brain function then you'll need it to break it up in a similar manner. Beyond that you'll need to use a threaded approach.

import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QMainWindow, QGridLayout, QLabel, QApplication, QWidget, QTextBrowser, QTextEdit, \
QPushButton, QAction, QLineEdit, QMessageBox
from PyQt5.QtGui import QPalette, QIcon, QColor, QFont
from PyQt5.QtCore import pyqtSlot, Qt
import threading
import time
textboxValue = ""
FinalAnsw = ""
class myThread (threading.Thread):
print ("Start")
def __init__(self):
threading.Thread.__init__(self)
def run(self):
def getAnswer(unString):
#do brain here
time.sleep(10)
return unString
global textboxValue
global FinalAnsw
FinalAnsw = getAnswer(textboxValue)
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'ChatBot'
self.left = 40
self.top = 40
self.width = 650
self.height = 600
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
pal = QPalette();
pal.setColor(QPalette.Background, QColor(40, 40, 40));
self.setAutoFillBackground(True);
self.setPalette(pal);
font = QtGui.QFont()
font.setFamily("FreeMono")
font.setBold(True)
font.setPixelSize(15)
self.setStyleSheet("QTextEdit {color:#3d3838; font-size:12px; font-weight: bold}")
historylabel = QLabel('View your conversation history here: ')
historylabel.setStyleSheet('color: #82ecf9')
historylabel.setFont(font)
messagelabel = QLabel('Enter you message to the chat bot here:')
messagelabel.setStyleSheet('color: #82ecf9')
messagelabel.setFont(font)
self.conversationBox = QTextBrowser(self)
self.textbox = QTextEdit(self)
self.button = QPushButton('Send message', self)
self.button.setStyleSheet(
"QPushButton { background-color:#82ecf9; color: #3d3838 }" "QPushButton:pressed { background-color: black }")
grid = QGridLayout()
grid.setSpacing(10)
self.setLayout(grid)
grid.addWidget(historylabel, 1, 0)
grid.addWidget(self.conversationBox, 2, 0)
grid.addWidget(messagelabel, 3, 0)
grid.addWidget(self.textbox, 4, 0)
grid.addWidget(self.button, 5, 0)
# connect button to function on_click
self.button.clicked.connect(self.on_click)
self.show()
def on_click(self):
global textboxValue
textboxValue = self.textbox.toPlainText()
self.conversationBox.append("You: " + textboxValue)
th = myThread()
th.start()
th.join()
global FinalAnsw
self.conversationBox.append("Rocket: " + FinalAnsw)
self.textbox.setText("")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
app.exec_()
So creating a simple thread solved the problem, the code above will still freeze because of the sleep function call, but if you replace that with a normal function that lasts long it won't freeze anymore. It was tested by the brain module of my project with their functions.
For a simple example of building a thread use https://www.tutorialspoint.com/python/python_multithreading.htm
and for the PyQt GUI I've used examples from this website to learn http://zetcode.com/gui/pyqt5/

Related

How to debug PyQt5 threads in Visual Studio Code?

I am right now developing a PyQT5 application an use multithreading to avoid freezing of the GUI. Unfortuneately the Visual Studio Code debugger does not stop on breakpoints inside the executed thread. I tried all suggestions from the following page without fixing the problem. https://github.com/microsoft/ptvsd/issues/428. I think VS Code switched debugger from ptvsd to debugpy so all the suggestions do not hold any more. Maybe somebody has an idea how to fix this issue.
import time
import sys
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QPushButton, QTextEdit, QVBoxLayout, QWidget, QLabel
class Worker(QObject):
sig_msg = pyqtSignal(str) # message to be shown to user
def __init__(self):
super().__init__()
#pyqtSlot()
def work(self):
self.sig_msg.emit('Hello from inside the thread!')
result = 1 + 1
result2 = 1 + 2
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Thread Example")
form_layout = QVBoxLayout()
self.setLayout(form_layout)
self.resize(400, 200)
self.button_start_threads = QPushButton("Start")
self.button_start_threads.clicked.connect(self.start_threads)
self.label = QLabel()
form_layout.addWidget(self.label)
form_layout.addWidget(self.button_start_threads)
QThread.currentThread().setObjectName('main')
self.__threads = None
def start_threads(self):
self.__threads = []
worker = Worker()
thread = QThread()
thread.setObjectName('thread')
self.__threads.append((thread, worker)) # need to store worker too otherwise will be gc'd
worker.moveToThread(thread)
worker.sig_msg.connect(self.label.setText)
thread.started.connect(worker.work)
thread.start()
if __name__ == "__main__":
app = QApplication([])
form = MyWidget()
form.show()
sys.exit(app.exec_())
You can reproduce the error by setting a breakpoint at self.sig_msg.emit('Hello from inside the thrad!') in my case the debugger does not stop at this position. I use VS Code Version 1.65.2. The code is taken from the post mentioned above.
I have recently experienced the same issue with VS Code and PyQt5. Following the advice at https://code.visualstudio.com/docs/python/debugging#_troubleshooting, I was able to hit the breakpoint in your example code by importing debugpy and adding debugpy.debug_this_thread() in the work method e.g.
def work(self):
debugpy.debug_this_thread()
self.sig_msg.emit('Hello from inside the thread!')
result = 1 + 1
result2 = 1 + 2
Hopefully that can help others facing the same issue.

threading queue blocks main pyqt5 GUI window

Although I read a ton of posts on the web, but couldn't find a solution for my self.
Basically, I am using pyqt5 for making a GUI application and am using threading for creating threads and lastly using queue I tried to send signals between main and child thread.
I have a qt5 progress bar in which it is value needs to updated by the child thread progress. When I try to use progressbar.setValue(x) I get below error:
QObject::setParent: Cannot set parent, new parent is in a different thread
The reason for above is that I cannot update the progress bar value from child thread, it needs to happen from main thread.
So I tried to use queue and send a message to the main thread to do it.
I tried below:
def buttonclicked():
global progressQueue
progressQueue = Queue()
thread = threading.Thread(target=childfunc, daemon=True, name="nemo", args=())
thread.start()
progressQueue.join()
while True:
if not progressQueue.empty():
msg = progressQueue.get()
pellow.setValue(msg)
return 0
def childfunc():
for i in range(1,100):
progressQueue.put(i)
Here the problem is that, the while loop freezes the mainwindow/gui app from interaction. Can anyone suggest, what do I need to do here?
A complete working example:
import queue
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from threading import Thread
app = QApplication(sys.argv)
class mainwindow1(QMainWindow):
def __init__(self):
super().__init__()
mainwindow = QWidget()
mainwindow.setObjectName("mainwindow")
mainwindow.setContentsMargins(100, 100, 100, 100)
self.setCentralWidget(mainwindow)
global pellow
global scanProgressbar
scanProgressbar = QProgressBar()
pellow = QPushButton('Click Here')
pellow.setObjectName("defaultbutton")
cpscanlayout = QVBoxLayout(mainwindow)
cpscanlayout.addWidget(scanProgressbar, alignment=Qt.AlignCenter, stretch=10)
cpscanlayout.addWidget(pellow, alignment=Qt.AlignCenter, stretch=10)
cpscanlayout.setAlignment(Qt.AlignCenter)
# cpscanlayout.setContentsMargins(0, 0, 0, 0);
cpscanlayout.setSpacing(5);
pellow.setCursor(QCursor(Qt.PointingHandCursor))
pellow.clicked.connect(buttonclicked)
self.show()
app.exec_()
def buttonclicked():
global progressQueue
progressQueue = Queue()
thread = threading.Thread(target=childfunc, daemon=True, name="nemo", args=())
thread.start()
progressQueue.join()
while True:
if not progressQueue.empty():
msg = progressQueue.get()
scanProgressbar.setValue(msg)
return 0
The code has several errors such as imports (import queue but it doesn't look like it uses Queue, it imports Thread but it uses threading.Thread, etc).
On the other hand, the misconception is that in Qt you should not use code that blocks the eventloop, such as while True. If you want to exchange information between threads then in the case of Qt you should not use Queue since it does not notify when there is a new data, instead you must use the signals that are also thread-safe and do notify when there is new data.
import sys
import threading
import time
from PyQt5.QtCore import pyqtSignal, QObject, Qt
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QProgressBar,
QPushButton,
QVBoxLayout,
QWidget,
)
class Signaller(QObject):
progress_changed = pyqtSignal(int)
class mainwindow1(QMainWindow):
def __init__(self):
super().__init__()
mainwindow = QWidget()
mainwindow.setObjectName("mainwindow")
mainwindow.setContentsMargins(100, 100, 100, 100)
self.setCentralWidget(mainwindow)
scanProgressbar = QProgressBar()
pellow = QPushButton("Click Here")
pellow.setObjectName("defaultbutton")
cpscanlayout = QVBoxLayout(mainwindow)
cpscanlayout.addWidget(scanProgressbar, alignment=Qt.AlignCenter, stretch=10)
cpscanlayout.addWidget(pellow, alignment=Qt.AlignCenter, stretch=10)
cpscanlayout.setAlignment(Qt.AlignCenter)
# cpscanlayout.setContentsMargins(0, 0, 0, 0);
cpscanlayout.setSpacing(5)
pellow.setCursor(QCursor(Qt.PointingHandCursor))
pellow.clicked.connect(self.buttonclicked)
self.signaller = Signaller()
self.signaller.progress_changed.connect(scanProgressbar.setValue)
def buttonclicked(self):
thread = threading.Thread(
target=childfunc, args=(self.signaller,), daemon=True, name="nemo"
)
thread.start()
def childfunc(signaller):
for i in range(1, 100):
signaller.progress_changed.emit(i)
time.sleep(0.1)
app = QApplication(sys.argv)
w = mainwindow1()
w.show()
app.exec_()

Timers cannot be stopped from another thread - Remove Focus

import sys
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit
class Worker(QThread):
def __init__(self, textBox):
super().__init__()
self.textBox = textBox
def run(self):
while True:
if self.textBox.text() == "close":
app.quit()
break
if self.textBox.text() == "removeFocus":
self.textBox.clearFocus()
class window(QWidget):
def __init__(self):
super().__init__()
vBox = QVBoxLayout()
self.setLayout(vBox)
self.resize(600, 400)
textBox = QLineEdit()
vBox.addWidget(textBox)
worker = Worker(textBox)
worker.start()
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = window()
sys.exit(app.exec())
When I type "close" in the textBox it works very fine but when I type "removeFocus", it still works but I get this error:
QObject::killTimer: Timers cannot be stopped from another thread
Why am I getting such an error even though the program is running?
(Since the process I want to do is very simple, I don't think I can go into much detail. I've just started learning Python. This is the first time I use this site. I'm sorry if I made a mistake while creating a post. Thank you)
In Qt you must not access or modify the GUI information from another thread (see this for more information) since it does not guarantee that it works (the GUI elements are not thread-safe), in your case luckily you have no problems but It is dangerous to use your approach in real.
In your case it is also unnecessary to use threads since it is enough to use the textChanged signal from QLineEdit.
import sys
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit
class Window(QWidget):
def __init__(self):
super().__init__()
vBox = QVBoxLayout(self)
self.resize(600, 400)
self.textBox = QLineEdit()
vBox.addWidget(self.textBox)
self.textBox.textChanged.connect(self.on_text_changed)
#pyqtSlot(str)
def on_text_changed(self, text):
if text == "close":
QApplication.quit()
elif text == "removeFocus":
self.textBox.clearFocus()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())

How to structure large pyqt5 GUI without subclassing QThread and using QPushButtons to do long-running tasks

I'm looking at creating a program with a PyQt5 GUI. The program will start with a UI with numerous buttons. These buttons will be used to open other programs/completed long running tasks. I know I need to use QThread, but I am unsure how to structure the programs so that it scales properly.
I've been at this for ages and have read numerous posts/tutorials. Most lean down the subclassing route. In the past, I have managed to create a working program subclassing QThread, but I have since read that this metholodogy is not preferred.
I have a feeling I should be creating a generic worker and passing in a function with *args and **kwargs, but that is not in my skillset yet.
I originally created a thread for each button during the GUI init, but that seemed like it was going to get out of hand quickly.
I am currently at the stage of creating a thread under the slot connected to the button.clicked signal. I am not sure if I then have to have a worker for each button or if I can/should make a generic worker and pass in a function. Note: I have tried to do this but have not been able to do it.
#Import standard modules
import sys
#Import third-party modles
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QVBoxLayout, QWidget
class Worker(QObject):
#Custom signals?? or built-in QThread signals?
started = pyqtSignal()
finished = pyqtSignal()
def __init__(self):
super().__init__()
self.started.emit()
#pyqtSlot()
def do_something(self):
for _ in range(3):
print('Threading...')
QThread.sleep(1)
self.finished.emit()
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.initUi()
def initUi(self):
#Create GUI
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget )
self.vertical_layout = QVBoxLayout(self.centralWidget)
self.setWindowTitle('QThread Test')
self.setGeometry(300, 300, 300, 50)
self.button1=QPushButton("Task 1", self, clicked=self._task1_clicked)
self.button2=QPushButton("Task 2", self, clicked=self._task2_clicked)
self.vertical_layout.addWidget(self.button1)
self.vertical_layout.addWidget(self.button2)
self.vertical_layout.addStretch()
def _task1_clicked(self):
print('task1 clicked')
#Create the worker
self.my_worker = Worker()
#Create thread; needs to be done before connecting signals/slots
self.task1_thread = QThread()
#Move the worker to the thread
self.my_worker.moveToThread(self.task1_thread)
#Connect worker and thread signals to slots
self.task1_thread.started.connect(self._thread_started)
self.task1_thread.started.connect(self.my_worker.do_something)
self.my_worker.finished.connect(self._thread_finished)
#Start thread
self.task1_thread.start()
def _task2_clicked(self):
print('task2 clicked')
def _thread_started(self):
print('thread started')
def _thread_finished(self):
print('thread finished')
self.my_worker.isRunning = False
self.task1_thread.quit()
self.task1_thread.wait()
print('The thread is running: ' + str(self.task1_thread.isRunning()))
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Window()
form.show()
app.exec_()
The above seems to work, but I feel like I have stumbled on to it and it is not the correct way of doing this. I do not want this to be my 'go-to' method if it is completely wrong. I'd like to be able to generate more complicated (more buttons doing things) programs compared to a one button/one task program.
In addition, I can't seem to get the QThread started and finished signals to fire without basically making them custom built signals. This is one reason I think I am going about this wrong.
from PyQt5 import QtCore
class AsyncTask(QtCore.QThread):
taskDone = QtCore.pyqtSignal(dict)
def __init__(self, *, task, callback=None, parent = None):
super().__init__(parent)
self.task = task
if callback != None:
self.taskDone.connect(callback)
if callback == None:
callback = self.callback
self.start()
def run(self):
try:
result = self.task()
print(result)
self.taskDone.emit(result)
except Exception as ex:
print(ex)
def callback(self):
print('callback')
Please try code above, call like this:
AsyncTask(task=yourTaskFunction, callback=yourCallbackFunction)

Python pyqt pulsing progress bar with multithreading

Please bear with my question as I am a beginner. I have been having problems implementing the progress bar in pyqt and all of the example I have seen doesn't really explain on how to implement it properly and from this example and this example I somewhat partially made it work but it still hangs. I have this code:
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(750, 450, 400, 200)
self.setFixedSize(self.size())
btn1 = QtGui.QPushButton("Convert", self)
btn1.move(210,171)
btn1.clicked.connect(self.progbar)
def progbar (self):
self.prog_win = QDialog()
self.prog_win.resize(400, 100)
self.prog_win.setFixedSize(self.prog_win.size())
self.prog_win.setWindowTitle("Processing request")
self.lbl = QLabel(self.prog_win)
self.lbl.setText("Please Wait. . .")
self.lbl.move(15,18)
self.progressBar = QtGui.QProgressBar(self.prog_win)
self.progressBar.resize(410, 25)
self.progressBar.move(15, 40)
self.progressBar.setRange(0,1)
self.myLongTask = TaskThread()
#I think this is where I am wrong
#because all of the answers here is very specific
#or just not for beginners
self.prog_win.show()
self.myLongTask.taskFinished.connect(self.onStart)
self.output_settings()
def onStart(self):
self.progressBar.setRange(0,0)
self.myLongTask.start()
def output_convert(self):
#very long process to convert a txt file to excel
#My Thread
class TaskThread(QtCore.QThread):
taskFinished = QtCore.pyqtSignal()
def run(self):
time.sleep(3)
self.taskFinished.emit()
def run():
app = QtGui.QApplication(sys.argv)
GUI = Window()
app.exec_()
run()
All of the examples and posts here have been very helpful on understanding progress bar implementation but with all the example having specific answers for a specific problem I can't understand the implementation of progress bar in a standard pyqt app. could you guys at least point me in the right direction? Would be appreciated.
This is a very basic progress bar that only uses what is needed at the bare minimum.
It would be wise to read this whole example to the end.
import sys
import time
from PyQt5.QtWidgets import (QApplication, QDialog,
QProgressBar, QPushButton)
TIME_LIMIT = 100
class Actions(QDialog):
"""
Simple dialog that consists of a Progress Bar and a Button.
Clicking on the button results in the start of a timer and
updates the progress bar.
"""
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.progress = QProgressBar(self)
self.progress.setGeometry(0, 0, 300, 25)
self.progress.setMaximum(100)
self.button = QPushButton('Start', self)
self.button.move(0, 30)
self.show()
self.button.clicked.connect(self.onButtonClick)
def onButtonClick(self):
count = 0
while count < TIME_LIMIT:
count += 1
time.sleep(1)
self.progress.setValue(count)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Actions()
sys.exit(app.exec_())
The progress bar is first imported like so from PyQt5.QtWidgets import QProgressBar
Then it is initialized like any other widget in QtWidgets
The line self.progress.setGeometry(0, 0, 300, 25) method defines the x,y positions on the dialog and width and height of the progress bar.
We then move the button using .move() by 30px downwards so that there will be a gap of 5px between the two widgets.
Here self.progress.setValue(count) is used to update the progress. Setting a maximum value using .setMaximum() will also automatically calculated the values for you. For example, if the maximum value is set as 50 then since TIME_LIMIT is 100 it will hop from 0 to 2 to 4 percent instead of 0 to 1 to 2 every second. You can also set a minimum value using .setMinimum() forcing the progress bar to start from a given value.
Executing this program will produce a GUI similar to this.
As you can see, the GUI will most definitely freeze and be unresponsive until the counter meets the TIME_LIMIT condition. This is because time.sleep causes the OS to believe that program has become stuck in an infinite loop.
QThread
So how do we overcome this issue ? We can use the threading class that PyQt5 provides.
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
QProgressBar, QPushButton)
TIME_LIMIT = 100
class External(QThread):
"""
Runs a counter thread.
"""
countChanged = pyqtSignal(int)
def run(self):
count = 0
while count < TIME_LIMIT:
count +=1
time.sleep(1)
self.countChanged.emit(count)
class Actions(QDialog):
"""
Simple dialog that consists of a Progress Bar and a Button.
Clicking on the button results in the start of a timer and
updates the progress bar.
"""
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.progress = QProgressBar(self)
self.progress.setGeometry(0, 0, 300, 25)
self.progress.setMaximum(100)
self.button = QPushButton('Start', self)
self.button.move(0, 30)
self.show()
self.button.clicked.connect(self.onButtonClick)
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Actions()
sys.exit(app.exec_())
Let's break down these modifications.
from PyQt5.QtCore import QThread, pyqtSignal
This line imports Qthread which is a PyQt5 implementation to divide and run some parts(eg: functions, classes) of a program in the background(also know as multi-threading). These parts are also called threads. All PyQt5 programs by default have a main thread and the others(worker threads) are used to offload extra time consuming and process intensive tasks into the background while still keeping the main program functioning.
The second import pyqtSignal is used to send data(signals) between worker and main threads. In this instance we will be using it to tell the main thread to update the progress bar.
Now we have moved the while loop for the counter into a separate class called External.
class External(QThread):
"""
Runs a counter thread.
"""
countChanged = pyqtSignal(int)
def run(self):
count = 0
while count < TIME_LIMIT:
count +=1
time.sleep(1)
self.countChanged.emit(count)
By sub-classing QThread we are essentially converting External into a class that can be run in a separate thread. Threads can also be started or stopped at any time adding to it's benefits.
Here countChanged is the current progress and pyqtSignal(int) tells the worker thread that signal being sent is of type int. While, self.countChanged.emit(count) simply sends the signal to any connections in the main thread(normally it can used to communicate with other worker threads as well).
def onButtonClick(self):
self.calc = External()
self.calc.countChanged.connect(self.onCountChanged)
self.calc.start()
def onCountChanged(self, value):
self.progress.setValue(value)
When the button is clicked the self.onButtonClick will run and also start the thread. The thread is started with .start(). It should also be noted that we connected the signal self.calc.countChanged we created earlier to the method used to update the progress bar value. Every time External::run::count is updated the int value is also sent to onCountChanged.
This is how the GUI could look after making these changes.
It should also feel much more responsive and will not freeze.
The answer to my own question. It is not that hard if you can understand the concept of threading and passing variables through classes. My first mistake was really the lack of knowledge about Worker threads, second is I thought that once you declare the Thread it means that you just have to call it so that it would run the function inside the main class so I was searching on how you would implement that and all I thought was wrong.
Solution
All the hard/Long processes SHOULD be in the subclassed QThread under def run and should be called in your class Window(QtGui.QMainWindow): or main loop and this is what my code look like now
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(750, 450, 400, 200)
self.setFixedSize(self.size())
btn1 = QtGui.QPushButton("Convert", self)
btn1.move(210,171)
btn1.clicked.connect(self.progbar)
def progbar (self):
self.prog_win = QDialog()
self.prog_win.resize(400, 100)
self.prog_win.setFixedSize(self.prog_win.size())
self.prog_win.setWindowTitle("Processing request")
self.lbl = QLabel(self.prog_win)
self.lbl.setText("Please Wait. . .")
self.lbl.move(15,18)
self.progressBar = QtGui.QProgressBar(self.prog_win)
self.progressBar.resize(410, 25)
self.progressBar.move(15, 40)
self.progressBar.setRange(0,1)
self.myLongTask = TaskThread(var = DataYouWantToPass) #initializing and passing data to QThread
self.prog_win.show()
self.onStart() #Start your very very long computation/process
self.myLongTask.taskFinished.connect(self.onFinished) #this won't be read until QThread send a signal i think
def onStart(self):
self.progressBar.setRange(0,0)
self.myLongTask.start()
#added this function to close the progress bar
def onFinished(self):
self.progressBar.setRange(0,1)
self.prog_win.close()
#My Thread
class TaskThread(QtCore.QThread):
taskFinished = QtCore.pyqtSignal()
#I also added this so that I can pass data between classes
def __init__(self, var, parent=None):
QThread.__init__(self, parent)
self.var = var
def run(self):
#very long process to convert a txt file to excel
def run():
app = QtGui.QApplication(sys.argv)
GUI = Window()
app.exec_()
run()
If something in this answer is wrong then please correct me as it would be a great help to understand it more or maybe some dos and don't

Categories

Resources