繁体   English   中英

Pyqt5 如何避免无限while循环冻结程序?

[英]Pyqt5 How to avoid freezing program by an infinite while loop?

我想知道,我怎样才能停止函数iniciar

每次我点击按钮self.runButton.clicked.connect(self.iniciar)

程序冻结,我无法执行其他操作。

我希望计时器继续工作,同时函数iniciar无限重复。

还有按钮self.runButton1停止函数iniciar

我的代码:

#!/usr/bin/env python3

# Program created for play audios of time in zapoteco'
#
# Created by: Python 3.6, PyQt5 5.9.2.
#
# Author: Raul Espinosa raul@ninja-code.de
#
# WARNING! All changes made in this file will be lost!
# 
# Version 0.2 GUI

import time
import subprocess

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(383, 263)
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(164, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)
        brush = QtGui.QBrush(QtGui.QColor(138, 226, 52))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Light, brush)
        brush = QtGui.QBrush(QtGui.QColor(164, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
        brush = QtGui.QBrush(QtGui.QColor(173, 127, 168))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(114, 159, 207))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Shadow, brush)
        brush = QtGui.QBrush(QtGui.QColor(164, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)
        brush = QtGui.QBrush(QtGui.QColor(138, 226, 52))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Light, brush)
        brush = QtGui.QBrush(QtGui.QColor(164, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
        brush = QtGui.QBrush(QtGui.QColor(173, 127, 168))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(114, 159, 207))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Shadow, brush)
        brush = QtGui.QBrush(QtGui.QColor(46, 52, 54))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)
        brush = QtGui.QBrush(QtGui.QColor(138, 226, 52))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Light, brush)
        brush = QtGui.QBrush(QtGui.QColor(190, 190, 190))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
        brush = QtGui.QBrush(QtGui.QColor(114, 159, 207))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
        brush = QtGui.QBrush(QtGui.QColor(114, 159, 207))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Shadow, brush)
        Form.setPalette(palette)
        Form.setPalette(palette)
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(10, 0, 361, 181))
        self.label.setObjectName("label")
        self.horizontalSlider = QtWidgets.QSlider(Form)
        self.horizontalSlider.setGeometry(QtCore.QRect(110, 240, 160, 16))
        self.horizontalSlider.setOrientation(QtCore.Qt.Horizontal)
        self.horizontalSlider.setObjectName("horizontalSlider")
        self.horizontalSlider.setRange(0,100)
        self.horizontalSlider.setSingleStep(1)
        self.horizontalSlider.valueChanged.connect(self.valueHandler)
        self.runButton = QtWidgets.QPushButton(Form)
        self.runButton.setGeometry(QtCore.QRect(50, 180, 80, 25))
        self.runButton.setObjectName("runButton")
        self.runButton.clicked.connect(self.iniciar)
        self.runButton1 = QtWidgets.QPushButton(Form)
        self.runButton1.setGeometry(QtCore.QRect(250, 180, 80, 25))
        self.runButton1.setObjectName("runButton1")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(160, 220, 55, 17))
        self.label_2.setObjectName("label_2")
        self.timer = QtCore.QTimer(Form)
        self.timer.timeout.connect(self.Time)
        self.timer.start(1000)
        self.lcdNumber = QtWidgets.QLCDNumber(Form)
        self.lcdNumber.setGeometry(QtCore.QRect(280, 0, 101, 61))
        self.lcdNumber.setInputMethodHints(QtCore.Qt.ImhNone)
        self.lcdNumber.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.lcdNumber.setFrameShadow(QtWidgets.QFrame.Raised)
        self.lcdNumber.setSmallDecimalPoint(True)
        self.lcdNumber.setDigitCount(5)
        self.lcdNumber.setMode(QtWidgets.QLCDNumber.Dec)
        self.lcdNumber.setSegmentStyle(QtWidgets.QLCDNumber.Flat)
        self.lcdNumber.display(time.strftime("%H"+":"+"%M"))
        #tiempo = time.strftime("%H"+":"+"%M")
        #print (tiempo)
        #self.lcdNumber.setProperty("value", 12:20)
        self.lcdNumber.setObjectName("lcdNumber")
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def Time(self):
        self.lcdNumber.display(time.strftime("%H"+":"+"%M"))

    def valueHandler(self,value):   
        scaledValue = float(value)/100
        print (scaledValue) , type(scaledValue)
        return scaledValue

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "XIGABA"))
        Form.setToolTip(_translate("Form", "<html><head/><body><pre style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;\"><span style=\" font-family:\'monospace\'; background-color:#ffffff;\">Creado con Software Libre.</span></pre></body></html>"))
        self.label.setToolTip(_translate("Form", "<html><head/><body><p>Dictador de horario.</p></body></html>"))
        self.label.setText(_translate("Form", "<html><head/><body><pre align=\"center\" style=\" margin-top:15px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><a name=\"taag_output_text\"/><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\">)</span><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\"> (                               </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\"> ( /( )\\ ) (       (      (    (      </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\"> )\\()|()/( )\\ )    )\\   ( )\\   )\\     </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\">((_)\\ /(_)|()/( ((((_)( )((_|(((_)(   </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\">__((_|_))  /(_))_)\\ _ )((_)_ )\\ _ )\\  </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\">\\ \\/ /_ _|(_)) __(_)_\\(_) _ )(_)_\\(_) </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\"> &gt;  &lt; | |   | (_ |/ _ \\ | _ \\ / _ \\   </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; color:#555753; background-color:#729fcf;\">/_/\\_\\___|   \\___/_/ \\_\\|___//_/ \\_\\  </span></pre><pre align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#729fcf;\"><span style=\" font-family:\'monospace\'; font-size:6pt; color:#555753; background-color:#729fcf;\">version 0.2 GUI</span></pre></body></html>"))
        self.runButton.setText(_translate("Form", "Iniciar"))
        self.runButton1.setText(_translate("Form", "Detener"))
        self.label_2.setText(_translate("Form", "<html><head/><body><pre align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><a name=\"taag_output_text\"/><span style=\" font-family:\'monospace\'; color:#ef2929; background-color:#000000;\">VOLUMEN</span></pre></body></html>"))

    def iniciar(self):
        self.runButton1.setEnabled(True)
        position = self.horizontalSlider.value()
        scaledValue = float(position)/100
        print (scaledValue) , type(scaledValue)

        while (True):
            time.sleep(0.5)
            second_test = time.strftime('%S')
            minute_test = time.strftime('%M')
            hour_test = time.strftime('%H')
            tiempo = time.strftime("%H"+":"+"%M")
            print (tiempo)
            self.lcdNumber.setProperty("value", tiempo)
            if int(minute_test) == int(00) and int(second_test) == int(00):
                print ('llego al hora exacta')
                filen = 'HRS' + hour_test + '_O.mp3.mp3'
                print (filen)
                subprocess.Popen(["play", filen, "vol", scaledValue]).communicate()
            elif int(second_test) == int(00):
                print ('llego al minuto')
                filen = 'HRS' + hour_test + '.mp3'
                filen2 = 'MIN' + minute_test + '.mp3.mp3'
                print (filen)
                print (filen2)
                subprocess.Popen(["play", filen, "vol", str(scaledValue)]).communicate()
                subprocess.Popen(["play", filen2, "vol", str(scaledValue)]).communicate()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

我用的是python3.6和pyqt5

您使用的 while true 之类的阻塞循环不适合 GUI,因为它们不允许您执行 GUI 的典型任务,例如检查事件、信号和插槽。

在 Qt 和 PyQt 中,有一些方法可以避免这些问题,针对您的情况的一种可能解决方案是使用线程,实现它们的一种简单方法是使用 QRunnable 和 QThreadPool,但在此之前建议您修改代码.

Qt Designer 提供了一个可以在widget 中实现设计的类,但它不是一个widget,创建一个从相应widget 继承的类并使用初始类来填充它是合适的。

class Widget(QtWidgets.QWidget, Ui_Form):
    def __init__(self, *args, **kwargs):
        QtWidgets.QWidget.__init__(self, *args, **kwargs)
        self.setupUi(self)
        self.runButton.clicked.connect(self.iniciar)
        self.timer.timeout.connect(self.update_time)
        self.horizontalSlider.valueChanged.connect(self.valueHandler)

    def update_time(self):
        self.lcdNumber.display(time.strftime("%H" + ":" + "%M"))

    def valueHandler(self, value):
        scaledValue = float(value) / 100
        print(scaledValue), type(scaledValue)
        return scaledValue

    def iniciar(self):
        self.runButton1.setEnabled(True)
        position = self.horizontalSlider.value()
        scaledValue = float(position) / 100
        print(scaledValue), type(scaledValue)
        self.runnable = Runnable(self)
        QtCore.QThreadPool.globalInstance().start(self.runnable)

在下一节中,我实现了QRunnable并传递了小部件,该小部件将用于通信和更新 GUI 数据,因为 Qt 的规则是不应从另一个线程更新 GUI,对此的解决方案是使用QMetaObject.invokeMethod :

class Runnable(QtCore.QRunnable):
    def __init__(self, w, *args, **kwargs):
        QtCore.QRunnable.__init__(self, *args, **kwargs)
        self.w = w
        self.position_initial = self.w.horizontalSlider.value()

    def run(self):
        scaledValue = float(self.position_initial) / 100

        print(scaledValue)
        while True:
            time.sleep(0.5)
            second_test = time.strftime('%S')
            minute_test = time.strftime('%M')
            hour_test = time.strftime('%H')
            tiempo = time.strftime("%H" + ":" + "%M")
            print(tiempo)
            QtCore.QMetaObject.invokeMethod(self.w.lcdNumber, "display",
                                            QtCore.Qt.QueuedConnection,
                                            QtCore.Q_ARG(str, tiempo))
            if int(minute_test) == int(00) and int(second_test) == int(00):
                print('llego al hora exacta')
                filen = 'HRS' + hour_test + '_O.mp3.mp3'
                print(filen)
                subprocess.Popen(["play", filen, "vol", scaledValue]).communicate()
            elif int(second_test) == int(00):
                print('llego al minuto')
                filen = 'HRS' + hour_test + '.mp3'
                filen2 = 'MIN' + minute_test + '.mp3.mp3'
                print(filen)
                print(filen2)
                subprocess.Popen(["play", filen, "vol", str(scaledValue)]).communicate()
                subprocess.Popen(["play", filen2, "vol", str(scaledValue)]).communicate()

然后,在实施iniciar方法,我们通过调用运行的QThreadPool

self.runnable = Runnable(self)
QtCore.QThreadPool.globalInstance().start(self.runnable)

可以在以下链接中找到完整的代码。

附注

如果你想添加一个止损,我们必须改变一些东西,例如你应该使用一个标志而不是 True ,并改变标志的状态:

class Runnable(QtCore.QRunnable):
    def __init__(self, w, *args, **kwargs):
        QtCore.QRunnable.__init__(self, *args, **kwargs)
        self.w = w
        self.position_initial = self.w.horizontalSlider.value()
        self.m_stopped = False

    def run(self):
        scaledValue = float(self.position_initial) / 100

        print(scaledValue)
        while not self.m_stopped:
            [...]

    def stop(self):
        self.m_stopped = True

然后我们创建了detener方法:

def detener(self): 
    self.runButton.setEnabled(True) 
    self.runButton1.setEnabled(False)
    self.runnable.stop()

暂无
暂无

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

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