What I intended
- when I click 'start' button on Subwindow then loading logo animation starts, and RSC function(Long running function) works separately.
Real work
- when I click the "start" button, the RSC function works but gui freezes.
I'm trying to use QThread for offloading the RSC function... but it looks not working.
Below is my code ↓
Main Window(1st window)
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets from Sub import SubWindow from Last import LastWindow from functools import partial import sys class Main_Window(QtWidgets.QMainWindow) : def __init__(self): super().__init__() self.resize(800, 600) self.initUI() def initUI(self): # next pushbutton self.pb_next = QtWidgets.QPushButton(self) self.pb_next.setGeometry(QtCore.QRect(540, 480, 112, 34)) self.pb_next.setText('Next') self.pb_next.clicked.connect(self.CallSub) # quit pushbutton self.pb_quit = QtWidgets.QPushButton(self) self.pb_quit.setGeometry(QtCore.QRect(660, 480, 112, 34)) self.pb_quit.setText('Quit') self.pb_quit.clicked.connect(QtCore.QCoreApplication.instance().quit) def CallSub(self): self.hide() self.SW = SubWindow() self.SW.show() print('call sub') self.SW.PB.clicked.connect(self.SW.Loading) print('loading') self.SW.PB.clicked.connect(self.RSC) print('rsc') def RSC(self): print('start rsc') self.text1 = 'host.txt' self.text2 = 'access.txt' self.thread = QtCore.QThread() self.SW.moveToThread(self.thread) self.thread.started.connect(partial(self.SW.RunSecurityCheck,self.text1,self.text2)) self.SW.finished.connect(self.thread.quit) self.SW.finished.connect(self.SW.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.SW.finished.connect(self.CallLast) self.thread.start() def CallLast(self): self.LW = LastWindow() self.SW.hide() self.LW.show() self.LW.pb_next.clicked.connect(self.CallMain) def CallMain(self): self.LW.hide() self.show() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) mw = Main_Window() mw.show() sys.exit(app.exec_())
Sub Window(2nd window)
# -*- coding: utf-8 -*- from time import sleep from PyQt5 import QtCore, QtWidgets, QtGui class SubWindow(QtWidgets.QWidget) : finished = QtCore.pyqtSignal() def __init__(self): super().__init__() self.resize(800, 600) self.initUI() def initUI(self): # Quit PushButton self.pb_quit = QtWidgets.QPushButton(self) self.pb_quit.setGeometry(QtCore.QRect(660, 480, 112, 34)) self.pb_quit.setText('Quit') self.pb_quit.clicked.connect(QtCore.QCoreApplication.instance().quit) # start push button self.PB = QtWidgets.QPushButton(self) self.PB.setGeometry(QtCore.QRect(280, 240, 100, 25)) self.PB.setText('Start') # loading animation self.LB_loading = QtWidgets.QLabel(self) self.LB_loading.setGeometry(QtCore.QRect(250, 210, 200, 100)) self.loading = QtGui.QMovie("loading.gif") self.LB_loading.setMovie(self.loading) self.LB_loading.hide() def Loading(self): self.PB.hide() self.LB_loading.show() self.loading.start() def RunSecurityCheck(self,t1,t2): sleep(10) self.finished.emit()
Last window(3rd window)
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets class LastWindow(QtWidgets.QWidget) : def __init__(self): super().__init__() self.resize(800, 600) self.initUI() def initUI(self): # Next PushButton self.pb_next = QtWidgets.QPushButton(self) self.pb_next.setGeometry(QtCore.QRect(540, 480, 112, 34)) self.pb_next.setText('Back to Main') # Quit PushButton self.pb_quit = QtWidgets.QPushButton(self) self.pb_quit.setGeometry(QtCore.QRect(660, 480, 112, 34)) self.pb_quit.setText('Quit') self.pb_quit.clicked.connect(QtCore.QCoreApplication.instance().quit) # complete label self.LB1 = QtWidgets.QLabel(self) self.LB1.setGeometry(QtCore.QRect(140, 220, 221, 18)) self.LB1.setText('Complete.')
and below is my loading.gif file
how could I fix the gui freezing?
CodePudding user response:
As stated in musicamante's comment routines run in a separate thread need to be independent of the GUI. So what probably makes the most sense in your situation would be to subclass QThread
and make RunSecurityCheck
a method of the QThread
, and pass in your two text parameters to the constructor of the thread. Then the code that is responsible for freezing the GUI will be run separately and will no longer cause freezing/stalling.
For Example:
in your 1st window file you can make some minor changes to RSC
method and import the Thread subclass
from Sub import SubWindow, Thread
...
def RSC(self):
print('start rsc')
self.text1 = 'host.txt'
self.text2 = 'access.txt'
self.thread = Thread(self.text1, self.text2)
self.thread.finished.connect(self.thread.quit)
self.thread.finished.connect(self.SW.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.finished.connect(self.CallLast)
self.thread.start()
...
Then in your Sub.py
class SubWindow(QtWidgets.QWidget) :
finished = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
self.resize(800, 600)
self.initUI()
def initUI(self):
# Quit PushButton
self.pb_quit = QtWidgets.QPushButton(self)
self.pb_quit.setGeometry(QtCore.QRect(660, 480, 112, 34))
self.pb_quit.setText('Quit')
self.pb_quit.clicked.connect(QtCore.QCoreApplication.instance().quit)
# start push button
self.PB = QtWidgets.QPushButton(self)
self.PB.setGeometry(QtCore.QRect(280, 240, 100, 25))
self.PB.setText('Start')
# loading animation
self.LB_loading = QtWidgets.QLabel(self)
self.LB_loading.setGeometry(QtCore.QRect(250, 210, 200, 100))
self.loading = QtGui.QMovie("loading.gif")
self.LB_loading.setMovie(self.loading)
self.LB_loading.hide()
def Loading(self):
self.PB.hide()
self.LB_loading.show()
self.loading.start()
class Thread(QtCore.QThread):
def __init__(self, t1, t2):
super().__init__()
self.t1 = t1
self.t2 = t2
def RunSecurityCheck(self,t1,t2):
sleep(10)
def run(self):
self.RunSecurityCheck(self.t1, self.t2)
self.finished.emit()
Your last file doesn't require any changes.
All you need to do is make those few minor changes and Bob's your uncle. It should work fine.