简体   繁体   中英

Pyqt5 freezes after button click

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

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

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM