新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于QtPy (PySide6) 的PLC-HMI工程实战记录(八)创建适合项目的进度条

发布时间:2026/8/31 5:08:22来源:尧图网络
基于QtPy (PySide6) 的PLC-HMI工程实战记录(八)创建适合项目的进度条
用于推焦和装煤的行程指示。1、安全色为绿色危险色为橙色越界色为红色随着行程控制点的接近颜色由安全色向危险色过度。2、炉前减速为橙色。中限停车和前限停车位越界色。3、所有的行程和设置为以米为单位的实数进度条的value数字为厘米单位的实数显示值为以米为单位的实数。4、显示数字随进度条移动颜色为背景的反色。################################################################################ # 定制的窗口部件 ################################################################################ import sys from PySide6.QtCore import Signal, Qt, Slot from PySide6.QtGui import QPainter, QFontMetrics, QColor from PySide6.QtWidgets import QLineEdit, QWidget, QSpinBox, QDoubleSpinBox, QProgressBar, QApplication, QVBoxLayout, \ QSlider, QLabel # 自定义的QLineEdit class HmiLineEdit(QLineEdit): hmi_textChanged Signal(str) def __init__(self, arg1None, parentNone): 兼容Qt Designer提升控件两种调用形式 HmiLineEdit(text:str, parent) HmiLineEdit(parent) if isinstance(arg1, str): # 第一个参数是文本 super().__init__(arg1, parent) else: # 第一个参数是parent控件 super().__init__(parentarg1) def focusInEvent(self, event): 获得焦点开始编辑会话保存原始内容 super().focusInEvent(event) self._original_text self.text() self._is_editing True def setText(self, text: str): 重写setText 用户正在编辑时外部调用setText直接忽略 内部提交确认时先关闭编辑标记再调用父类setText if self._is_editing: # 处于编辑模式外来信号/代码调用setText不生效 return super().setText(text) def keyPressEvent(self, event): key event.key() if key Qt.Key_Escape: # Esc放弃修改恢复原始内容结束编辑 self._is_editing False super().setText(self._original_text) self.clearFocus() event.accept() return elif key in (Qt.Key_Return, Qt.Key_Enter): # 回车确认接受当前输入内容结束编辑触发editConfirmed new_text self.text() self._is_editing False super().setText(new_text) self.hmi_textChanged.emit(new_text) self.clearFocus() event.accept() return super().keyPressEvent(event) def focusOutEvent(self, event): 失去焦点回退原始值取消编辑 if self._is_editing: self._is_editing False super().setText(self._original_text) super().focusOutEvent(event) # 自定义的QSpinBox class HmiSpinBox(QSpinBox): hmi_valueChanged Signal(int) def __init__(self, parentNone): super().__init__(parent) self._is_editing False def focusInEvent(self, event): 获得焦点开始编辑会话保存原始内容 super().focusInEvent(event) self._original_value self.value() self._is_editing True def setValue(self, value: int): 重写setValue 用户正在编辑时外部调用setValue直接忽略 内部提交确认时先关闭编辑标记再调用父类setValue if self._is_editing: # 处于编辑模式外来信号/代码调用setValue不生效 return super().setValue(value) def keyPressEvent(self, event): key event.key() if key Qt.Key_Escape: # Esc放弃修改恢复原始内容结束编辑 self._is_editing False super().setValue(self._original_value) self.clearFocus() event.accept() return elif key in (Qt.Key_Return, Qt.Key_Enter): # 回车确认接受当前输入内容结束编辑触发editConfirmed new_value self.value() self._is_editing False super().setValue(new_value) self.hmi_valueChanged.emit(new_value) self.clearFocus() event.accept() return super().keyPressEvent(event) def focusOutEvent(self, event): 失去焦点回退原始值取消编辑 if self._is_editing: self._is_editing False super().setValue(self._original_value) super().focusOutEvent(event) # 自定义的QSpinBox class HmiDoubleSpinBox(QDoubleSpinBox): hmi_valueChanged Signal(float) def __init__(self, parentNone): super().__init__(parent) self._is_editing False def focusInEvent(self, event): 获得焦点开始编辑会话保存原始内容 super().focusInEvent(event) self._original_value self.value() self._is_editing True def setValue(self, value: float): 重写setValue 用户正在编辑时外部调用setValue直接忽略 内部提交确认时先关闭编辑标记再调用父类setValue if self._is_editing: # 处于编辑模式外来信号/代码调用setValue不生效 return super().setValue(value) def keyPressEvent(self, event): key event.key() if key Qt.Key_Escape: # Esc放弃修改恢复原始内容结束编辑 self._is_editing False super().setValue(self._original_value) self.clearFocus() event.accept() return elif key in (Qt.Key_Return, Qt.Key_Enter): # 回车确认接受当前输入内容结束编辑触发editConfirmed new_value self.value() self._is_editing False super().setValue(new_value) self.hmi_valueChanged.emit(new_value) self.clearFocus() event.accept() return super().keyPressEvent(event) def focusOutEvent(self, event): 失去焦点回退原始值取消编辑 if self._is_editing: self._is_editing False super().setValue(self._original_value) super().focusOutEvent(event) # 自定义的进度条 class HmiProgressBar(QProgressBar): 槽函数 set_intial_danger(initial_danger: float) 炉前减速米数 set_mid_limit(mid_limit: float) 中限位置米数 set_minimum(minimum: float) 起点米数 set_maximum(maximum: float) 前限米数 set_value(value: float) 设置实时行程值米数 def __init__(self, parentNone): super().__init__(parent) self.safe_color_h 120 # 安全色绿色 self.danger_color_h 30 # 危险色橙色 self.over_color_h 0 # 超限色红色 self.Initial_danger 0 # 起步的危险阶段炉前减速 self.mid_limit 0 # 回退的中限值 self.is_mid_limit False # 回退的中限 self._color_h self.safe_color_h # 背景色的色系 self._last_val self.value() # 最后一次值 self._real_value 0.0 self.valueChanged.connect(self.refresh) # self.label QLabel(aaaaaaaaa,self) # self.label.setGeometry(0, 0 ,100, self.height()) Slot() def set_intial_danger(self, initial_danger: float): self.Initial_danger int(initial_danger * 100.0) Slot() def set_mid_limit(self, mid_limit: float): self.mid_limit int(mid_limit * 100.0) Slot() def set_maximum(self, maximum: float): self.setMaximum(int(maximum * 100.0)) Slot() def set_minimum(self, minimum: float): self.setMinimum(int(minimum * 100.0)) Slot() def set_value(self, value: float): self._real_value value * 100.0 self.setValue(max(min(int(self._real_value), self.maximum()), self.minimum())) # 限制self.value()不越界 self.update() # 这行是必需的否则无法显示超限后的数字 def paintEvent(self, event): self.setTextVisible(False) super().paintEvent(event) painter QPainter(self) color QColor() h (self._color_h 180) % 360 print(self._color_h, h) color.setHsl(h, 200, 122) painter.setPen(color) text self.text() fm QFontMetrics(self.font()) text_width fm.horizontalAdvance(text) # 计算进度块末端 x 坐标 ratio self.value() / self.maximum() if self.maximum() 0 else 0 chunk_end_x int(self.width() * ratio) # 文字放在进度块末端右侧 6px x chunk_end_x - 120 # 防止超出控件右边界 if x text_width self.width() - 4: x self.width() - text_width - 4 if x 2: x 2 # x max(x, 60) y (self.height() - fm.height()) // 2 fm.ascent() painter.drawText(x, y, text) painter.end() Slot() def refresh(self): s self.value() - self._last_val # 本次增量 range_val self.maximum() - self.minimum() # 数值范围 range_h self.safe_color_h - self.danger_color_h # 颜色范围 if s 0: # 增量方向 self._color_h self.safe_color_h - (self.value() - self.Initial_danger) / range_val * range_h else: self._color_h self.safe_color_h - (self.maximum() - self.value()) / range_val * range_h self._color_h min(max(self._color_h, self.danger_color_h), self.safe_color_h) color_h int(self._color_h) # 起步段 if self.value() self.Initial_danger: color_h self.danger_color_h self._last_val self.value() contrast_color abs(color_h 180) self.setStyleSheet(fQProgressBar::chunk {{background-color:hsl({color_h},85%,50%);}}) # print(fQProgressBar {{color:hsl({contrast_color},85%,50%);}} # QProgressBar::chunk {{background-color:hsl({color_h},85%,50%);}}) self.style().unpolish(self) self.style().polish(self) # 超上限或超中限 if self.value() self.maximum() or self.is_mid_limit: self.setStyleSheet(fQProgressBar::chunk {{background-color:hsl({self.over_color_h},85%,50%);}});)) self.style().unpolish(self) self.style().polish(self) def text(self): # 增加工况提示 v self._real_value / 100.0 return f{v:.2f} m if __name__ __main__: def on_value_changed(value): value value / 100.0 form.progressBar.set_value(value) app QApplication(sys.argv) form QWidget() with open(../styles/style_base_setting.qss, r, encodingutf-8) as f: stylesheet f.read() app.setStyleSheet(stylesheet) layout QVBoxLayout() form.setLayout(layout) form.progressBar HmiProgressBar() form.slider QSlider() form.slider.setOrientation(Qt.Horizontal) form.slider.setRange(-200, 12000) form.slider.setValue(0) form.progressBar.set_minimum(0.0) form.progressBar.set_maximum(100.0) form.progressBar.set_intial_danger(10.26) form.progressBar.set_mid_limit(13.23) form.progressBar.setFixedSize(500,60) form.slider.valueChanged.connect(on_value_changed) layout.addWidget(form.progressBar) layout.addWidget(form.slider) form.show() sys.exit(app.exec())
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

基于LVGL的STM32圆屏音频播放器UI设计与嵌入式实现 2026/8/31 5:48:26

基于LVGL的STM32圆屏音频播放器UI设计与嵌入式实现

最近在做一个智能手表项目,客户要求实现一个圆形的音乐播放器界面,既要美观流畅,还得在资源有限的STM32单片机上跑起来。这让我想起了LVGL这个强大的嵌入式图形库,它原生支持圆屏,但要把音频播放的完整逻辑&#xff08…

阅读更多 →
Claude Code接入DeepSeek Flash:配置流程与性价比实测对比 2026/8/31 5:48:26

Claude Code接入DeepSeek Flash:配置流程与性价比实测对比

最近“DeepSeek Flash 正式版”“Claude Code 接入第三方模型”“GPT 系 Luna 新版本”这几个词在开发者社区反复出现,甚至被冠以“核弹级更新”的说法。如果你正在用 Claude Code 做日常编码,又对模型 API 的费用越来越敏感,那么这次的关注点…

阅读更多 →
有刷电机与无刷电机选型指南:从野外工地到数据中心 2026/8/31 5:48:26

有刷电机与无刷电机选型指南:从野外工地到数据中心

你有没有遇到过这种情况:一个设备上用的电机,在实验室里跑得好好的,一到野外工地就三天两头罢工;或者数据中心的风机,明明一直开着,却总觉得电费高得离谱、散热效果还跟不上。其实很多问题不是电机质量不好…

阅读更多 →
三模机械键盘GSK1 PRO深度解析:从轴体到Gasket的编程之选 2026/8/31 5:48:26

三模机械键盘GSK1 PRO深度解析:从轴体到Gasket的编程之选

你每天打开编辑器之前,最先碰到的东西是什么?不是鼠标,不是显示器,而是键盘。对于写代码的人来说,键盘就是生产力工具本身。写得久了,你会感受到普通薄膜键盘的键位反馈越来越模糊,键帽打油&…

阅读更多 →
HyperMesh 2022入门:网格质量检查与材料单位设置全攻略 2026/8/31 5:48:26

HyperMesh 2022入门:网格质量检查与材料单位设置全攻略

不少刚开始接触 HyperMesh 的朋友都会陷入同一种困境:软件界面里面板极多、按钮密集,跟着视频操作每一步都对得上,但一旦脱离教程自己建模,立刻不知道下一步该点什么。尤其是“3D 网格质量怎么检查”“Materials 里怎么设置单位”…

阅读更多 →
PySide6通用化GUI框架:模块化设计与部署实践 2026/8/31 5:43:26

PySide6通用化GUI框架:模块化设计与部署实践

简介:这是一套面向Python中高级开发者与GUI应用工程师的通用化PySide6 GUI框架,旨在解决传统桌面应用开发中界面复用性低、主题切换繁琐、组件扩展困难等痛点,适用于工具类软件、内部管理系统及教学演示项目快速搭建。资源包共268个文件&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞