【问题标题】:Led Blink how to interrupt time.sleep RPILed Blink 如何中断 time.sleep RPI
【发布时间】:2020-04-13 07:59:17
【问题描述】:

我在 qtdesigner 中设计了一个表单。它有“开”和“关”按钮。开启按钮应该开始闪烁 LED 并且关闭按钮应该停止它。所以,如果 time.sleep 持续时间很短没有问题,但是当我写 10 秒睡眠时,当我点击关闭按钮时它不会立即停止。程序等待 10 秒以停止 LED 闪烁。那么time.sleep怎么打断呢?


import time
import threading
import RPi.GPIO as GPIO
import sys
from time import sleep
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication, QLabel
from PyQt5 import QtCore, QtGui, QtWidgets


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)

switch = True  


def blink(self):  
        def run():  
            while (switch == True):
                print('BLINK...BLINK...')
                GPIO.output(17, GPIO.HIGH)
                time.sleep(10.0)
                GPIO.output(17, GPIO.LOW)
                time.sleep(10.0)
                if switch == False:  
                    break
        thread = threading.Thread(target=run)
        thread.start()



class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)


        self.pshbttn1 = QtWidgets.QPushButton(Form)
        self.pshbttn1.setGeometry(QtCore.QRect(60, 170, 125, 50))
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.pshbttn1.setFont(font)
        self.pshbttn1.setObjectName("pshbttn1")
        self.pshbttn1.clicked.connect(self.switchon)


        self.pshbttn2 = QtWidgets.QPushButton(Form)
        self.pshbttn2.setGeometry(QtCore.QRect(220, 170, 125, 50))
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.pshbttn2.setFont(font)
        self.pshbttn2.setObjectName("pshbttn2")
        self.pshbttn2.clicked.connect(self.switchoff)


        self.pshbttn3 = QtWidgets.QPushButton(Form)
        self.pshbttn3.setGeometry(QtCore.QRect(140, 230, 125, 50))
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.pshbttn3.setFont(font)
        self.pshbttn3.setObjectName("pshbttn3")
        self.pshbttn3.clicked.connect(app.exit)


        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(80, 80, 251, 51))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label.setFont(font)
        self.label.setObjectName("label")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "LED"))
        self.pshbttn1.setText(_translate("Form", "ON"))
        self.pshbttn2.setText(_translate("Form", "OFF"))
        self.pshbttn3.setText(_translate("Form", "EXIT"))
        self.label.setText(_translate("Form", "LED\'i açmak için butonları kullanın"))

    def switchon(self):    
        global switch  
        switch = True  
        print ('switch on')
        blink(self)

    def switchoff(self):    
        print ('switch off') 
        global switch  
        switch = False 

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

【问题讨论】:

  • 嗨,欢迎来到 OS。我建议简单地使用更短的时间间隔,但请查看此 post 以了解如何在 Python 中中断 time.sleep()

标签: python multithreading pyqt pyqt5


【解决方案1】:

在这种情况下,不需要使用睡眠,只需使用 QTimer。为了简化任务,我创建了一个处理 pin 的类。另外,PyQt5 建议不要修改 Qt Designer 生成的类。

import sys

from PyQt5 import QtCore, QtGui, QtWidgets

import RPi.GPIO as GPIO


class Led:
    def __init__(self, pin, timeout=1000):
        self._state = False
        self._pin = pin
        self._timeout = timeout

        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.pin, GPIO.OUT)

        self.blink_timer = QtCore.QTimer(
            interval=self.timeout, timeout=self._on_blink_timeout
        )

    def _on_blink_timeout(self):
        self.state = not self.state

    def _update_internal_state(self):
        GPIO.output(self.pin, GPIO.HIGH if self._state else GPIO.LOW)

    @property
    def pin(self):
        return self._pin

    @property
    def timeout(self):
        return self._timeout

    @timeout.setter
    def timeout(self, v):
        self._timeout = v
        is_active = self.blink_timer.isActive()
        self.blink_timer.setInterval(self.timeout)
        if is_active:
            self.blink_timer.start()

    def on(self):
        self.state = True

    def off(self):
        self.state = False

    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, s):
        self._state = s
        self._update_internal_state()

    def start(self):
        self.state = True
        self.blink_timer.start()

    def stop(self):
        self.state = False
        self.blink_timer.stop()


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)

        self.pshbttn1 = QtWidgets.QPushButton(Form)
        self.pshbttn1.setGeometry(QtCore.QRect(60, 170, 125, 50))
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.pshbttn1.setFont(font)
        self.pshbttn1.setObjectName("pshbttn1")
        self.pshbttn2 = QtWidgets.QPushButton(Form)
        self.pshbttn2.setGeometry(QtCore.QRect(220, 170, 125, 50))
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.pshbttn2.setFont(font)
        self.pshbttn2.setObjectName("pshbttn2")
        self.pshbttn3 = QtWidgets.QPushButton(Form)
        self.pshbttn3.setGeometry(QtCore.QRect(140, 230, 125, 50))
        font = QtGui.QFont()
        font.setPointSize(16)
        font.setBold(True)
        font.setWeight(75)
        self.pshbttn3.setFont(font)
        self.pshbttn3.setObjectName("pshbttn3")
        self.pshbttn3.clicked.connect(app.exit)

        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(80, 80, 251, 51))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label.setFont(font)
        self.label.setObjectName("label")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "LED"))
        self.pshbttn1.setText(_translate("Form", "ON"))
        self.pshbttn2.setText(_translate("Form", "OFF"))
        self.pshbttn3.setText(_translate("Form", "EXIT"))
        self.label.setText(_translate("Form", "LED'i açmak için butonları kullanın"))


class Widget(QtWidgets.QWidget, Ui_Form):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.setupUi(self)
        self.led = Led(17, timeout=10000)
        self.pshbttn1.clicked.connect(self.led.start)
        self.pshbttn2.clicked.connect(self.led.stop)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

【讨论】:

  • 首先,代码运行流畅,非常感谢。但是代码太复杂了,我现在无法理解,而且这不是我想要解决这个问题的方式。其实如果有线程的解决方案,你能帮我用线程写代码吗?
  • @nyiragongo 好吧,线程是不必要的。除了其他不必要的风险外,线程还引入了不必要的复杂性。不要让自己在寻找“线程的神奇解决方案”时过于复杂,您应该花一点时间分析我的稳定解决方案,并且基点是使用 QTimer。所以我的回答是:不,我不会把时间花在使用线程实现解决方案上,因为可能的答案不会比我提出的更好,使用 QTimer 的解决方案是最好的
  • 我标记了你的解决方案。好吧,我会试着理解这个。正如你提到的,最终它是稳定的。我的只是好奇和固执。我从线程开始,我真的很想用线程来解决它。无论如何,我真的很感谢你的帮助。
  • @nyiragongo 根据我使用 Qt 的经验,我总是使用线程作为最后的选择,我只在有一个消耗大量时间的任务的情况下使用它(并且在改变一个led的状态显然不是),在一般情况下,在Qt中,任务必须异步执行(例如,QTimer),并且只使用线程来防止耗时任务阻塞主线程。总之:当没有 Qt 解决方案(信号和插槽)时,只需尝试线程。
猜你喜欢
  • 2016-08-17
  • 2011-07-04
  • 1970-01-01
  • 2020-02-02
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
相关资源
最近更新 更多