Reputation: 13
When I click a button inf its work and it is going to an infinite loop and I want to click another button to stop the Program but the problem I can not click another button (stop button) because my GUI is freezing this my code
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
def retranslateUi( MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
infButton.setText(_translate("MainWindow", "inf"))
stopButton.setText(_translate("MainWindow", "stop"))
def inf_lp():
while True:
print (1)
def stop_lp():
exit(0)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
centralwidget = QtWidgets.QWidget(MainWindow)
centralwidget.setObjectName("centralwidget")
infButton = QtWidgets.QPushButton(centralwidget)
infButton.setGeometry(QtCore.QRect(160, 110, 89, 25))
infButton.setObjectName("infButton")
infButton.clicked.connect(inf_lp)
stopButton = QtWidgets.QPushButton(centralwidget)
stopButton.setGeometry(QtCore.QRect(400, 100, 89, 25))
stopButton.setObjectName("stopButton")
stopButton.clicked.connect(stop_lp)
MainWindow.setCentralWidget(centralwidget)
menubar = QtWidgets.QMenuBar(MainWindow)
menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
menubar.setObjectName("menubar")
MainWindow.setMenuBar(menubar)
statusbar = QtWidgets.QStatusBar(MainWindow)
statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(statusbar)
retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
This image for my GUI
I try to follow this. but I can not understand how to solve this problem because I do not use class in my code
Upvotes: 0
Views: 1393
Reputation: 144
The while True
loop is blocking the GUI from updating and responding to changes. Basically you have to use threading
or if you have a CPU intensive algorithm, multiprocessing
, however, with GUIs I still recommend threading. I don't know a lot about pyqt5 but here is the same code in tkinter:
from tkinter import *
import threading
root = Tk()
root.geometry("300x300")
# creating a thread event
event = threading.Event()
# You can also use a boolean: stopped = False
def start_inf():
# global stopped
# stopped = False
event.set()
# while not stopped:
while event.is_set():
print(1)
else:
print("Stopped")
def stop_loop():
# global stopped
# stopped = True
event.clear()
def start_threading():
threading.Thread(target=start_inf, daemon=True).start()
start_button = Button(root, text="Start loop", command=start_threading)
stop_button = Button(root, text="Stop loop", command=stop_loop)
start_button.pack(pady=10)
stop_button.pack()
root.mainloop()
A couple of notes: bind the start_threading
function to your button. Second, pass your function into the target=
without any parentheses, you are not calling it, you are just passing it. Thirdly, if your function has any arguments, after the target=
argument type args=
and pass your arguments as a tuple, if your function has only one argument, pass it like this so python would know it is passed in a tuple: (my_only_arg,)
. Pay attention to the last comma. Fourthly, I am setting the daemon=
to True
so that the thread would automatically end with your GUI, you can turn it off if you want your thread to continue after the GUI is destroyed. Lastly, I am using a threading.Event
to communicate safely between threads, they are kind of like booleans, if you want to set it to True, type: your_event.set()
, to set it to False, type: your_event.clear()
and to check if it is set, type: your_event.is_set()
(as mentioned in the code you can also use normal booleans). I hope this has helped you!
Upvotes: 0
Reputation: 570
The reason your program is freezing is because the gui won't respond until the calculation is done. To bypass this problem, you have to use threading
to pass the calculation to another thread.
Something like this
def main():
def clicked():
#your infinite loop
t = threading.Thread(target=clicked,daemon=True)
t.start()
#then connect your buttons
infButton.clicked.connect(main)
stopButton.clicked.connect(sys.exit())
Upvotes: 2