简体   繁体   English

单击按钮后 Pyqt5 冻结

[英]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当我点击一个按钮 inf 它的工作并且它将进入无限循环并且我想点击另一个按钮来停止程序但是我无法点击另一个按钮(停止按钮)的问题因为我的 GUI 正在冻结我的代码

    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这个图像用于我的 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但我不明白如何解决这个问题,因为我的代码中没有使用 class

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.要绕过这个问题,您必须使用threading将计算传递给另一个线程。

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. while True循环阻止 GUI 更新和响应更改。 Basically you have to use threading or if you have a CPU intensive algorithm, multiprocessing , however, with GUIs I still recommend threading.基本上你必须使用threading ,或者如果你有一个 CPU 密集型算法, multiprocessing ,但是,对于 GUI,我仍然建议使用线程。 I don't know a lot about pyqt5 but here is the same code in tkinter:我不太了解 pyqt5,但这是 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.一些注意事项:将start_threading function 绑定到您的按钮。 Second, pass your function into the target= without any parentheses, you are not calling it, you are just passing it .其次,将你的 function 传递到target=中,不带任何括号,你不是在调用它,你只是在传递它 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,) .第三,如果你的 function 有任何 arguments,在target=参数类型args=之后将你的 arguments 作为一个元组传递,如果你的 function 只有一个参数,像这样传递它这样 python 就会知道它是在一个 tuplearg 中传递的: (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.第四,我将daemon=设置为True以便线程会自动结束你的 GUI,如果你希望你的线程在 GUI 被销毁后继续运行,你可以将其关闭。 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).最后,我使用threading.Event在线程之间进行安全通信,它们有点像布尔值,如果您想将其设置为 True,请输入: your_event.set() ,将其设置为 False,请输入: your_event.clear()并检查它是否已设置,键入: your_event.is_set() (如代码中所述,您也可以使用普通布尔值)。 I hope this has helped you!我希望这对你有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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