用python做一个10分钟倒计时QT界面

该代码实现了一个QT界面的10分钟倒计时器,开始时显示答辩开始,剩余2分钟时背景变黄,最后10秒变红,结束时显示答辩结束。窗口可自适应屏幕大小,字体大小与屏幕宽度成比例调整。

    用python做一个10分钟倒计时QT界面,倒计时开始要显示2秒钟‘答辩开始’,剩余俩分钟的时候屏幕变成黄色,最后十秒钟变成红色,计时结束后要显示‘答辩结束’,QT窗口要能自适应屏幕大小。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QDesktopWidget
from PyQt5.QtGui import QFont
from PyQt5.QtCore import QTimer, Qt


class Countdown(QWidget):

    def __init__(self):
        super().__init__()

        self.setWindowTitle('倒计时')
        self.setWindowIcon(self.style().standardIcon(1))
        self.resize(self.width(), self.height())  # 默认大小
        # 窗口居中显示
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

        # 垂直布局
        layout = QVBoxLayout()

        # 显示文字标签
        self.label = QLabel('答辩开始
<think>我们需要使用PySide6来创建图形界面,使用pymodbus来与PLC通信。这里,我们将设计一个简单的倒计时界面,它每隔30秒触发一次(类似于节拍器),同时通过Modbus监控PLC的输出信号。 步骤: 1. 设计一个界面,包含一个倒计时显示(例如,一个LCD数字显示或标签)和一个开始/停止按钮。 2. 使用QTimer来实现倒计时功能,每30秒重置一次。 3. 同时,使用pymodbus定期(例如每秒)读取PLC的输出信号状态,并显示在界面上。 注意:由于Modbus通信可能会阻塞界面,我们将在单独的线程中执行Modbus操作。 我们将创建两个线程: - 一个用于处理倒计时的定时器(在主线程中,因为QTimer需要在主线程中运行)。 - 另一个用于Modbus通信(使用QThread或线程池)。 但是,由于我们只是需要定期读取PLC,我们可以使用一个单独的QTimer,然后在每次超时时启动一个线程去读取PLC(避免阻塞界面)。 设计思路: - 主窗口类:包含倒计时显示、PLC状态显示、开始/停止按钮。 - 使用一个QTimer用于倒计时(30秒循环)。 - 使用另一个QTimer用于定期读取PLC(比如每1秒读取一次)。 - 使用一个工作线程(或使用QThreadPool和QRunnable)来执行Modbus读取操作,以避免阻塞主线程。 由于pymodbus是同步的,所以我们将Modbus读取操作放在一个单独的线程中执行,然后通过信号将读取结果传回主线程更新界面。 我们将创建一个工作类(继承自QRunnable)来执行Modbus读取任务。 注意:在PySide6中,我们可以使用QThreadPool来管理线程,这样避免频繁创建和销毁线程。 实现步骤: 1. 导入必要的模块。 2. 创建一个ModbusWorker类(继承自QRunnable),用于在后台读取PLC输出信号。 3. 创建主窗口类,包含: - 一个倒计时显示(QLCDNumber或QLabel) - 一个状态显示区域(例如QLabel)用于显示PLC的输出状态 - 开始/停止按钮 - 两个定时器:一个用于倒计时一个用于触发Modbus读取 - 一个线程池(QThreadPool)用于执行Modbus任务 4. 在倒计时定时器超时时,重置倒计时(30秒)并执行一次节拍动作(比如打印或触发某个操作)。 5. 在Modbus定时器超时时,启动Modbus工作线程。 6. Modbus工作线程读取完成后,通过自定义信号将结果发送给主窗口更新界面。 但是,QRunnable不能直接发射信号,因此我们需要使用一个辅助对象(QObject)来定义信号,并在QRunnable中持有该对象。或者,我们可以使用pyqtSignal,但QRunnable本身不支持信号。因此,我们可以采用另一种方式:在ModbusWorker中,我们执行完读取后,通过主窗口的回调函数来更新数据(或者使用QMetaObject.invokeMethod)。 这里为了简单,我们可以在ModbusWorker中执行完任务后,通过主窗口提供的更新函数(通过传递回调函数)来更新界面。但是跨线程更新UI需要小心,我们可以使用信号槽机制。因此,我们创建一个单独的Signaler类(继承自QObject),用于发射信号。 我们这样设计: class Signaler(QObject): plc_data_signal = Signal(dict) # 或者根据数据类型定义 class ModbusWorker(QRunnable): def __init__(self, signaler): super().__init__() self.signaler = signaler def run(self): # 执行Modbus读取 data = ... # 读取的数据 self.signaler.plc_data_signal.emit(data) 然后在主窗口中,将signaler的信号连接到更新界面的槽函数。 但是,这样我们需要在主窗口创建Signaler对象,并将它传递给ModbusWorker。同时,注意Signaler对象必须属于主线程(因为信号需要连接到主线程的槽)。 另一种更简单的方式:在主窗口中定义一个槽函数,然后在ModbusWorker中通过信号发射数据。但是ModbusWorker不是QObject,所以不能直接定义信号。因此,我们采用Signaler辅助对象。 具体代码结构: 1. 导入模块 2. 定义Signaler类 3. 定义ModbusWorker类(QRunnable) 4. 定义主窗口类 注意:Modbus连接参数(如IP地址、端口等)需要根据实际情况设置。这里我们假设使用TCP。 由于我们只是监控输出信号,假设我们读取一个保持寄存器(或线圈,具体看PLC)的地址。这里假设我们读取线圈0(输出0)的状态。 我们使用pymodbus的同步客户端,因为异步客户端在非主线程中使用可能更复杂。在ModbusWorker的run方法中,我们创建临时的Modbus客户端,读取数据。 注意:每次读取都创建和关闭连接,这样避免长连接问题。 开始编写代码: 我们将使用以下pymodbus的同步客户端: from pymodbus.client.sync import ModbusTcpClient 步骤: - 在ModbusWorker的run方法中: client = ModbusTcpClient(host, port) client.connect() result = client.read_coils(address, count) # 处理结果,然后关闭client # 通过signaler发送结果 在主窗口的槽函数中,将PLC的状态更新到界面上。 另外,倒计时功能: - 初始倒计时时间为30秒。 - 使用一个QTimer,间隔设为1000毫秒(每秒更新一次)。 - 每次超时,倒计时减1,并更新显示。 - 当倒计时为0时,执行一次节拍动作(比如播放声音或触发PLC操作),然后重置倒计时(30秒)。 我们还可以添加一个按钮用于开始和停止倒计时。 下面开始写代码:</think>下面是一个使用 PySide6 和 pymodbus 实现的 PLC 输出信号监控器,包含 30 秒倒计时功能。这个应用会定期读取 PLC 输出状态,并在倒计时结束时触发节拍器效果。 ```python import sys import time from PySide6.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QPushButton, QLCDNumber, QProgressBar ) from PySide6.QtCore import QTimer, Qt, QTime from pymodbus.client import ModbusTcpClient class PLCMonitorApp(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("PLC 输出监控器") self.setGeometry(100, 100, 400, 400) # 初始化 Modbus 客户端 self.plc_client = ModbusTcpClient("192.168.1.10", port=502) # 替换为你的 PLC IP self.connected = False # 创建 UI self.central_widget = QWidget() self.setCentralWidget(self.central_widget) layout = QVBoxLayout(self.central_widget) # PLC 状态显示 self.status_label = QLabel("PLC 状态: 未连接") self.status_label.setAlignment(Qt.AlignCenter) layout.addWidget(self.status_label) # 倒计时显示器 self.lcd = QLCDNumber() self.lcd.setDigitCount(5) self.lcd.display("30.00") self.lcd.setSegmentStyle(QLCDNumber.Filled) self.lcd.setStyleSheet("background-color: black; color: green;") layout.addWidget(self.lcd) # 进度条 self.progress = QProgressBar() self.progress.setRange(0, 3000) # 30秒 * 100 self.progress.setValue(3000) layout.addWidget(self.progress) # 输出状态显示 self.output_label = QLabel("输出状态: 未知") self.output_label.setAlignment(Qt.AlignCenter) layout.addWidget(self.output_label) # 控制按钮 self.btn_start = QPushButton("开始监控") self.btn_start.clicked.connect(self.toggle_monitoring) layout.addWidget(self.btn_start) # 初始化定时器 self.timer = QTimer() self.timer.timeout.connect(self.update_display) self.countdown_timer = QTimer() self.countdown_timer.timeout.connect(self.update_countdown) # 倒计时变量 self.remaining_time = 30.0 # 30秒倒计时 self.is_running = False self.last_update_time = time.time() def toggle_monitoring(self): """切换监控状态""" if not self.is_running: # 连接 PLC if not self.connected: self.connected = self.plc_client.connect() if not self.connected: self.status_label.setText("PLC 状态: 连接失败!") return self.status_label.setText("PLC 状态: 已连接") # 启动定时器 self.timer.start(500) # 每500ms读取一次PLC self.countdown_timer.start(10) # 10ms更新一次倒计时 self.btn_start.setText("停止监控") self.is_running = True else: # 停止定时器 self.timer.stop() self.countdown_timer.stop() self.btn_start.setText("开始监控") self.is_running = False # 断开PLC连接 if self.connected: self.plc_client.close() self.connected = False self.status_label.setText("PLC 状态: 已断开") def update_display(self): """读取并显示PLC输出状态""" if not self.connected: return try: # 读取保持寄存器 (示例地址: 0) result = self.plc_client.read_holding_registers(0, 1) if not result.isError(): output_state = result.registers[0] status = "激活" if output_state else "关闭" self.output_label.setText(f"输出状态: {status} (值: {output_state})") else: self.output_label.setText("读取错误") except Exception as e: self.output_label.setText(f"通信错误: {str(e)}") def update_countdown(self): """更新倒计时显示""" current_time = time.time() elapsed = current_time - self.last_update_time self.last_update_time = current_time # 更新倒计时 self.remaining_time -= elapsed if self.remaining_time <= 0: self.remaining_time = 30.0 # 重置倒计时 self.trigger_beep() # 触发节拍器效果 # 更新显示 self.lcd.display(f"{self.remaining_time:.2f}") self.progress.setValue(int(self.remaining_time * 100)) def trigger_beep(self): """倒计时结束时的节拍器效果""" # 这里可以添加声音效果或视觉反馈 self.lcd.setStyleSheet("background-color: black; color: red;") QTimer.singleShot(300, lambda: self.lcd.setStyleSheet( "background-color: black; color: green;" )) print("节拍器触发!") # 实际应用中可替换为声音或PLC操作 def closeEvent(self, event): """窗口关闭时清理资源""" if self.connected: self.plc_client.close() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) window = PLCMonitorApp() window.show() sys.exit(app.exec()) ``` ### 代码解释: 1. **Modbus 连接**: - 使用 `ModbusTcpClient` 连接 PLC(需要替换为实际 PLC IP) - 定时读取保持寄存器(示例地址为 0) 2. **倒计时系统**: - 30 秒倒计时显示在 LCD 数字面板 - 进度条直观显示剩余时间 - 倒计时结束后触发 `trigger_beep()` 方法 3. **节拍器功能**: - 倒计时归零时 LCD 短暂变红(视觉反馈) - 实际应用中可添加声音提示或 PLC 操作 4. **状态监控**: - 显示 PLC 连接状态 - 实时显示输出寄存器值 - 错误处理机制 5. **控制逻辑**: - 开始/停止按钮控制监控状态 - 自动重连机制 - 窗口关闭时自动断开 PLC ### 使用说明: 1. 安装依赖: ```bash pip install PySide6 pymodbus ``` 2. 修改 PLC 连接参数: ```python self.plc_client = ModbusTcpClient("192.168.1.10", port=502) # 替换为实际PLC IP ``` 3. 调整寄存器地址(根据实际 PLC 配置修改): ```python result = self.plc_client.read_holding_registers(0, 1) # 地址0,读取1个寄存器 ``` 4. 扩展节拍器功能: - 在 `trigger_beep()` 中添加声音播放 - 添加 PLC 写入操作控制外部设备
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值