【问题标题】:Pyqt5 freezes after button clickPyqt5 在按钮单击后冻结
【发布时间】:2020-11-13 16:46:23
【问题描述】:

当我单击其工作中的一个按钮并且它将进入无限循环并且我想单击另一个按钮以停止程序但问题我无法单击另一个按钮(停止按钮)因为我的 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_())

此图像用于我的 GUI

I try to follow this。但我不明白如何解决这个问题,因为我的代码中没有使用类

【问题讨论】:

  • 您好,@samxx123,您找到答案了吗?

标签: python


【解决方案1】:

您的程序冻结的原因是因为 gui 在计算完成之前不会响应。要绕过这个问题,您必须使用threading 将计算传递给另一个线程。

类似的东西

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

【讨论】:

  • 你好@Andy_ye,不确定sys.exit()是否是结束线程的好方法
【解决方案2】:

while True 循环阻止 GUI 更新和响应更改。基本上你必须使用threading,或者如果你有一个CPU密集型算法multiprocessing,但是,对于GUI,我仍然建议使用线程。我对 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()

几个注意事项:将start_threading 函数绑定到您的按钮。其次,将你的函数传递给target= 不带任何括号,你不是在调用它,你只是在传递它。第三,如果你的函数有任何参数,在 target= 参数类型 args= 之后并将你的参数作为元组传递,如果你的函数只有一个参数,像这样传递它,这样 python 就会知道它是在一个元组中传递的: (my_only_arg,)。注意最后一个逗号。第四,我将daemon= 设置为True,这样线程将自动以您的GUI 结束,如果您希望线程在GUI 销毁后继续运行,您可以将其关闭。最后,我使用threading.Event 在线程之间进行安全通信,它们有点像布尔值,如果要将其设置为 True,请键入:your_event.set(),将其设置为 False,请键入:your_event.clear() 和检查它是否已设置,输入:your_event.is_set()(如代码中所述,您也可以使用普通布尔值)。我希望这对你有所帮助!

【讨论】:

    猜你喜欢
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    相关资源
    最近更新 更多