2017-12-27 528 views
1

我想知道,我怎麼能我按一下按鈕self.runButton.clicked.connect(self.iniciar)Pyqt5如何避免由while循環無限凍結程序?

程序凍結每次停止功能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 [email protected] 
# 
# 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

+0

從我可以告訴你的方法'iniciar'將花費其大部分時間都在睡覺,並會,因此,阻止'Qt'事件循環。更好的方法可能是利用['QTimer'](http://doc.qt.io/qt-5/qtimer.html)進行計時事件和['QProcess'](http:// doc .qt.io/QT-5/qprocess.html),用於處理執行/控制。這樣,你可以使用'Qt'的信號/槽機制,以避免阻塞事件循環。 –

回答

1

阻斷循環一樣,而真正的你使用不適合一個GUI,因爲他們不會讓你做的典型像檢查事件,信號和插槽一樣的GUI任務。

在Qt,因此也PyQt的,有方法來避免這些問題,你的情況可能的解決方案是使用線程,一個簡單的方法來實現它們使用QRunnable和QThreadPool,但在此之前,這是可取改變你的代碼。

Qt設計提供了可實現小部件設計一個類,但它不是一個小部件,它是適當的創建從相應的控件繼承的類,並使用初始類來填充它。

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) 

完整的代碼可以在以下link找到。

PS

如果你想添加一個停止,我們必須改變一些事情,例如替代的,而真正的你應該使用一個標誌,並更改標誌的狀態:

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

感謝您的工作!我加'self.runButton1.clicked.connect(self。detener)'和機能的研究'DEF detener(個體): \t self.runButton.setEnabled(真) \t self.runButton1.setEnabled(假) \t self.runnable =可運行(個體) \t QtCore.QThreadPool.globalInstance( ).stop(self.runnable)'但不停止存在? – laur

+0

如果你已經閱讀了文檔,你會看到QThreadPool沒有停止方法,在一會兒我會告訴你如何停止執行: – eyllanesc

+0

謝謝@eyllanesc – laur