PyQt5中带有计时器范围的问题

问题描述 投票:0回答:1

我正在创建烤箱监控程序,该程序可以通过Modbus TCP到达某些PID控制器。我正在尝试实现一个电子邮件警报部件,该部件将监视温度以及温度是否在允许范围内。如果超出容忍范围,则发送一封电子邮件,然后每隔10分钟再发送一封电子邮件,然后再超出容忍范围。我确定我的工作范围有些混乱,但是对于我的一生,我无法弄清楚是什么。当烤箱超出公差范围时,我的“ inTolerance”功能将起作用。它发送1封电子邮件,应该启动计时器,但我的“ is_alive”调用未返回true。因此,当“ inTolerance”再次呼叫时,它会发送另一封电子邮件,然后炸裂,因为我认为它会尝试启动另一个“ t”计时器。

任何帮助和健全性检查将非常有帮助和赞赏。

from PyQt5 import QtCore, QtGui, QtWidgets
from modbusTest import Oven
from emailModule import emailer
import time
from threading import Timer




class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(170, 260)
        self.spinBox = QtWidgets.QSpinBox(Form)
        self.spinBox.setGeometry(QtCore.QRect(10, 90, 61, 20))
        self.spinBox.setObjectName("setpoint")
        self.lcdNumber = QtWidgets.QLCDNumber(Form)
        self.lcdNumber.setGeometry(QtCore.QRect(10, 10, 150, 60))
        self.lcdNumber.setObjectName("lcdNumber")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(120, 89, 41, 22))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setGeometry(QtCore.QRect(10, 130, 105, 20))
        font = QtGui.QFont()
        font.setPointSize(8)
        self.lineEdit.setFont(font)
        self.lineEdit.setObjectName("lineEdit")
        self.spinBox_2 = QtWidgets.QSpinBox(Form)
        self.spinBox_2.setGeometry(QtCore.QRect(77, 90, 35, 20))
        self.spinBox_2.setObjectName("tolerance")
        self.spinBox_2.setValue(5)
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(20, 70, 41, 15))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(10, 112, 71, 16))
        self.label_2.setObjectName("label_2")
        self.listWidget = QtWidgets.QListWidget(Form)
        self.listWidget.setGeometry(QtCore.QRect(10, 160, 150, 91))
        self.listWidget.setObjectName("listWidget")
        self.label_3 = QtWidgets.QLabel(Form)
        self.label_3.setGeometry(QtCore.QRect(70, 70, 51, 16))
        self.label_3.setObjectName("label_3")
        self.pushButton_2 = QtWidgets.QPushButton(Form)
        self.pushButton_2.setGeometry(QtCore.QRect(120, 129, 40, 22))
        self.pushButton_2.setObjectName("pushButton_2")



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


        self.p1 = Oven('IP')
        self.p1.connect()
        self.lcdNumber.display(self.p1.readTemp())

        #print(self.t.is_alive())
        #self.t.start()
        #print(self.t.is_alive())


        #TODO set spinbox values to database table values
        ########################################################################################################

        self.tolerance =  float(self.spinBox_2.value())
        self.spinBox.setValue(self.p1.readSP())
        self.setPoint = float(self.spinBox.value())

        ########################################################################################################

        self.pushButton.clicked.connect(self.setter)
        QtCore.QTimer.singleShot(1000, self.displayer)

        self.pushButton_2.clicked.connect(self.emailerList)
        self.emailList = []
        self.t = Timer(10.0, None)


    def emailerList(self):
        if len(self.lineEdit.text()) == 0:
            None
        else:
            self.emailList.append(self.lineEdit.text())
            self.listWidget.addItem(self.lineEdit.text())
            self.lineEdit.clear()



    def displayer(self):
        temp = self.p1.readTemp()
        self.lcdNumber.display(temp)
        self.inTolerance(self.tolerance, temp, self.setPoint)
        QtCore.QTimer.singleShot(1000, self.displayer)

    def setter(self):
        self.setPoint = float(self.spinBox.value())
        self.p1.writeSP(self.setPoint)
        self.tolerance = float(self.spinBox_2.value())

    def inTolerance(self, tolerance, temp, setPoint):
        if temp > (setPoint + tolerance) or temp < (setPoint - tolerance):
            self.lcdNumber.setStyleSheet("background-color: rgb(255, 0, 0);")
            print(self.t.is_alive())
            if not self.t.is_alive():
                emailer(self.emailList, 'Test Oven', temp, setPoint)
                print('Email Sent')
                self.t.start()
                time.sleep(1)
                print(self.t.is_alive())
        else:
            self.t.cancel()
            self.lcdNumber.setStyleSheet("background-color: rgb(255, 255, 255);")

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButton.setText(_translate("Form", "Set"))
        self.label.setText(_translate("Form", "Setpoint"))
        self.label_2.setText(_translate("Form", "Alarm Emails:"))
        self.label_3.setText(_translate("Form", "Tolerance"))
        self.pushButton_2.setText(_translate("Form", "Add"))


if __name__ == "__main__":
    import sys
    sys_argv = sys.argv
    sys_argv += ['--style', 'Fusion']
    app = QtWidgets.QApplication(sys_argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())
python pyqt pyqt5
1个回答
0
投票

您的问题的主要原因是您正在调用cancel(),这会导致计时器使其自身无效[[即使尚未启动],并且结果是在此之后计时器将永远不再实际开始。此后还有另一个问题:线程对象只能启动一次,并且每次需要再次启动它时都需要创建一个新的Timer对象。

也就是说,您不应混合使用计时器对象,在处理线程时,通常最好使用Qt提供的内容。

在您的情况下,解决方案是使用QElapsedTimer,该对象可以返回自(重新)启动以来经过的时间。

请注意,我使用的是QWidget类(仅在此示例中简化了ui),有关代码之后的内容更多。

class Window(QtWidgets.QWidget): def __init__(self, parent=None): super(Window, self).__init__(parent) self.resize(170, 260) layout = QtWidgets.QGridLayout(self) self.lcdNumber = QtWidgets.QLCDNumber(self) layout.addWidget(self.lcdNumber, 0, 0, 1, 2) self.spinBox = QtWidgets.QSpinBox(self) layout.addWidget(self.spinBox, 1, 0) self.spinBox_2 = QtWidgets.QSpinBox(self) layout.addWidget(self.spinBox_2, 1, 1) self.spinBox_2.setValue(5) self.p1 = Oven('P1') self.p1.connect() self.lcdNumber.display(self.p1.readTemp()) self.tolerance = float(self.spinBox_2.value()) self.setPoint = float(self.spinBox.value()) self.emailList = [] # create a timer that will call displayer each second; having a reference # to the timer allows to stop it if required self.displayerTimer = QtCore.QTimer(interval=1000, timeout=self.displayer) self.displayerTimer.start() self.elapsedTimer = QtCore.QElapsedTimer() def displayer(self): temp = self.p1.readTemp() self.lcdNumber.display(temp) self.inTolerance(self.tolerance, temp, self.setPoint) def inTolerance(self, tolerance, temp, setPoint): if temp > (setPoint + tolerance) or temp < (setPoint - tolerance): self.lcdNumber.setStyleSheet("background-color: rgb(255, 0, 0);") if not self.elapsedTimer.isValid(): # the timer has not been started or has been invalidated self.elapsedTimer.start() elif self.elapsedTimer.elapsed() > 10000: # ten seconds have passed, send the email emailer(self.emailList, 'Test Oven', temp, setPoint) # restart the timer, otherwise another mail could possibly be # sent again the next cycle self.elapsedTimer.start() # in any other case, the elapsed time is less than the limit, just # go on else: # temperature is within tolerance, invalidate the timer so that it can # be restarted when necessary self.elapsedTimer.invalidate() self.lcdNumber.setStyleSheet("background-color: rgb(255, 255, 255);") if __name__ == "__main__": import sys sys_argv = sys.argv sys_argv += ['--style', 'Fusion'] app = QtWidgets.QApplication(sys_argv) window = Window() window.show() sys.exit(app.exec_())

如上所述,我正在使用QWidget类。似乎您正在使用pyuic实用程序的输出来创建程序,您应该

never

这样做。您应该在单独的脚本中创建程序,并将生成的文件用作导入的模块。从pyuic创建的py文件应NEVER进行编辑。在这种情况下,我完全通过代码创建了接口,但是您仍然可以在设计器中重新创建ui并使用生成的py文件,如the documentation中所述(第三个方法,即多重继承方法,通常是最好的)。
© www.soinside.com 2019 - 2024. All rights reserved.