自定义的部件库原则上尽量做到前后端分离,接口方便,复制简单。
单选框部件
# encoding: utf-8
###################################################
# 自定义的单选框
###################################################
# 对外接口:
# stateNum = Signal(int) 状态号,从1开始,是几就几被选中
# customSetup(): # 定制的初始化程序
import PySide6
from PySide6.QtCore import Signal
from PySide6.QtWidgets import QWidget, QGroupBox, QFrame
class PysideCustomRadiobutton(QFrame):
stateNum = Signal(int) # 状态号,从1开始,是几就几被选中
def __init__(self, parent=None):
super().__init__(parent)
self.RadioButtons = []
def customSetupUi(self): # 定制的初始化程序
self.RadioButtons = self.findChildren(PySide6.QtWidgets.QRadioButton) # 部件中所有的单选按钮
self.RadioButtons.sort(key=lambda child: child.objectName()) # 按名称排序
for i in range(len(self.RadioButtons)):
def callback(idx):
return lambda: self.stateNum.emit(idx+1)
self.RadioButtons[i].clicked.connect(callback(i)) # 单击按钮后发射信号
self.stateNum.connect(self.changeState) # 状态号信号的连接
self.stateNum.emit(1) # 初始化状态下,状态1被选中
def changeState(self, thisTurnOn): # 改变状态
self.RadioButtons[thisTurnOn-1].setChecked(True)
前端的范例:
框架的建立和调用
# 阶段v1的调用
import sys
from time import strftime
from PySide6.QtCore import QObject, Signal, QTimer
from PySide6.QtWidgets import QWidget, QApplication, QMainWindow
import template_rc # 导入需要显示的画面
# ############导入并需要显示的画面集中在这里定义#############################
# ############template.ui的显示#############################
class MainWindow(QMainWindow, template_rc.Ui_MainWindow): # 定义需要显示的画面类
def __int__(self):
super().__init__()
# ########################部件初始化的通用函数###################################
def init_widgets(widget): # 画面里的部件的初始化
sons = widget.children() # 儿辈部件
def find_child(child): # 查找子部件
try:
child.customSetupUi() # 自定义的初始化
except AttributeError:
pass
if child.children():
for grandson in child.children():
find_child(grandson) # 递归查找
for son in sons:
find_child(son)
# #############################主程序###################################
if __name__ == '__main__':
app = QApplication(sys.argv)
# #######################本项目的定义###################################
class UI(QObject):
# ##########项目范围内的信号#############
sysClock_1S = Signal() # 秒时钟信号
# ##########定时器#############
timer_1s = QTimer() # 定义全局0.1s的周期定时器
timer_1s.start(1000)
# ###########__init__###############
def __init__(self):
super().__init__()
self.widgets = [] # 所有的视窗列表
# ########################本项目的实例化###################################
ui = UI()
# #######################画面实例化和初始化#################################
# ########################实例化模板画面#################################
mainWindow = MainWindow()
mainWindow.setupUi(mainWindow) # 模板画面的本体初始化
init_widgets(mainWindow) # 模板画面的部件初始化
mainWindow.show()
ui.widgets.append(mainWindow) # 将画面加入视窗列表,方便管理
# ###########################信号的连接####################################
# ###########################项目级别信号的连接###############################
ui.timer_1s.timeout.connect(ui.sysClock_1S.emit)
ui.sysClock_1S.connect(lambda: mainWindow.labelSystemClock.setText(strftime('%Y-%m-%d %H:%M:%S')))
# ###########################mainWindow画面信号的连接######################
mainWindow.RadioButtons_1.stateNum.connect(lambda x: mainWindow.label_1.setText(str(x)))
mainWindow.pushButton_1.clicked.connect(lambda: mainWindow.RadioButtons_1.stateNum.emit(1))
mainWindow.doubleSpinBox_1.valueChanged.connect(lambda x: mainWindow.label_22.setText(str(x)))
# ###########################槽函数####################################
sys.exit(app.exec())
运行截图:
本阶段的资源链接:(v1)https://download.csdn.net/download/xulibo5828/89120987?spm=1001.2101.3001.9499
自定义功能的仪表盘
一个具有设定值输入、微调,实时值显示,历史曲线实时显示的仪表盘。
在CAD软件中大致规划一下功能区的尺寸和排列:
功能和分工规划:编程阶段可视的部件在QT designer中完成部署和设置,运行阶段可视的动态部件在程序中根据QT designer中的设置值自动计算和部署。
对外接口:外部传入设定值和实时值。
画面设计:在QT Designer里面完成画面的组态,布置和复制部件也仅在QT Designer中进行。部件的总容器和历史数据显示窗口用QFrame,进度条和历史曲线的显示在程序里用QPainter实现。历史曲线尝试过用专门的绘图库matplotlib,这个库在嵌入pyside6的部件时无法做到0边距无缝衔接,左右两边无法布满pyside6的部件。如下图:
所以,还是决定用QPainter的 drawline来实现。
在QT Designer里设计好部件的各个组件:
为之配套编写代码,命名为PysideCustomDashboard.py,并将部件“提升为”这个自定义的类。
部件的代码:
# encoding: utf-8
###################################################
# 自定义的仪表盘
###################################################
# 对外接口:
# ActualValueInput = Signal(float) # 从外部传入的实时值
# customSetup(): # 定制的初始化程序
import PySide6
from PySide6.QtCore import Signal, Qt, QPoint
from PySide6.QtGui import QColor, QPen, QPainter
from PySide6.QtWidgets import QFrame
class PysideCustomDashboard(QFrame):
ActualValueInput = Signal(float) # 从外部传入的实时值
PresetValueInput = Signal(float) # 从外部传入的设定值
PresetValueOutput = Signal(float) # 向外部传出的设定值
def __init__(self, parent=None):
super().__init__(parent)
# self.preset_value = 0.0 # 预设值的value
self.processBar_preset_width = 0 # 预设值进度条的宽度
self.processBar_preset_radius = 0 # 预设值进度条的半径
self.processBar_actual_radius = 0 # 实时值进度条的半径
self.processBar_y_start = 0 # 进度条的外轮廓距y方向边缘距离
self.processBar_x_start = 0 # 进度条的外轮廓距x方向边缘距离
self.center_point = QPoint(0, 0) # 部件的中心坐标
self.actual_text_color = QColor() # 实时值窗口文字颜色
self.spinBox_preset_text_color = QColor() # 预设值窗口文字颜色
self.progressBar_backColor = QColor('#515d80') # 进度条背景色
self.frame_history_Palette = None # 历史曲线显示窗口的调色板
self.frame_history_styleSheet = None # 历史曲线显示窗口的样式表
self.frame_history_geometry = None # 历史曲线显示窗口的几何特征
self.label_name = None # 仪表盘名称文字框
self.label_unit = None # 显示单位文字框
self.label_actual = None # 实时值的显示文字框
self.spinBox_preset = None # 带微调的设置值输入部件
self.frame_history = None # 历史曲线显示窗口
self.begin_degree = 225 # 进度条总的起始角度
self.span_degree = -225 # 进度条总的跨度角度
self.actual_begin_degree = 225 # 实时值的进度条起始角度
self.actual_span_degree = 0 # 实时值的进度条跨度始角度
self.preset_begin_degree = 225 # 设定值的进度条起始角度
self.preset_span_degree = 0 # 设定值的进度条跨度始角度
self.min_value = 0.0 # 最小值
self.max_value = 100.0 # 最大值
self.processBar_actual_width = 0 # 进度条的宽度
self.processBar_center = QPoint(0, 0) # 进度条的中心
self.points = 10 # 显示的点数
# #######################定制的初始化程序###########################
def customSetupUi(self): # 定制的初始化程序
# ######################子部件的定义############################
children = self.children()
for child in children:
# ##############历史曲线显示窗口#####################
if 'frame_history' in child.objectName():
self.frame_history_geometry = child.geometry() # 几何数据
self.frame_history_styleSheet = child.styleSheet() # 样式表
self.frame_history_Palette = child.palette() # 颜色表
# #################带微调的设置值输入部件################
elif 'spinBox_preset' in child.objectName():
self.spinBox_preset = child
p = child.palette() # 颜色表
self.spinBox_preset_text_color = p.color(p.ColorRole.Text) # 获取预设值窗口文字颜色
self.min_value = child.minimum() # 最小值
self.max_value = child.maximum() # 最大值
# ###################实时值的显示文字框###################
elif 'label_actual' in child.objectName():
self.label_actual = child
p = child.palette() # 颜色表
self.actual_text_color = p.color(p.ColorRole.Text) # 获取实时值窗口文字颜色
# #################显示单位文字#######################
elif 'label_unit' in child.objectName():
self.label_unit = child
# ##############仪表盘名称文字####################
elif 'label_name' in child.objectName(): #
self.label_name = child
# ##################本体几何参数########################
self.center_point = QPoint(int(self.width() / 2), int((self.height() / 2))) # 中心点坐标
# ####################历史曲线显示窗口的定义###################
self.frame_history = CustomLineChart(self.spinBox_preset_text_color, self.actual_text_color, self.min_value,
self.max_value, self.points, self) # 实体化历史曲线显示窗口
self.frame_history.setGeometry(self.frame_history_geometry) # 克隆几何尺寸
self.frame_history.setStyleSheet(self.frame_history_styleSheet) # 克隆样式表
self.frame_history.setPalette(self.frame_history_Palette) # 克隆颜色表
self.frame_history.show() # 显示
# self.frame_history.customSetupUi() # 历史曲线显示窗口初始化
# ####################进度条的定义##############################
self.processBar_actual_width = int((self.width() / 50)) # 实时值进度条的宽度
# self.processBar_preset_width = self.processBar_actual_width # 预设值进度条的宽度
self.processBar_preset_width = int(self.processBar_actual_width * 0.66) # 预设值进度条的宽度
# self.processBar_preset_width = int(self.processBar_actual_width / 3)
self.processBar_x_start = int(self.width() / 20) # 进度条的外轮廓距x方向边缘距离
self.processBar_y_start = int(self.width() / 20) # 进度条的外轮廓距y方向边缘距离
self.processBar_actual_radius = int(
(self.width() / 2) - self.processBar_x_start - (self.processBar_actual_width / 2) * 0.9) # 实时值进度条的半径
self.processBar_preset_radius = int(
self.processBar_actual_radius - self.processBar_actual_width) # 预设值进度条的半径
self.signal_handing([self.spinBox_preset.value(), 'preset']) # 初始化一下预设值进度条的显示
# ######################信号的连接############################
self.ActualValueInput.connect(lambda x: self.signal_handing([x, 'actual'])) # 接收到外部传入实时数据后的信号处理
self.PresetValueInput.connect(self.spinBox_preset.setValue) # 接收到外部传入设置值后的信号处理
self.spinBox_preset.valueChanged.connect(lambda x: self.signal_handing([x, 'preset'])) # 设置值发生改变后的信号处理
# #######################发射信号的处理############################
def signal_handing(self, args):
if args[1] == 'actual': # 如果是实时值发射的信号
self.frame_history.PointValues.emit(self.spinBox_preset.value(), args[0]) # 将预设值和实际值打包发送到历史曲线的部件的输入信号
self.label_actual.setText(str(args[0])) # 实时显示实际值的数字
self.actual_span_degree = int(
(args[0] - self.min_value) / (self.max_value - self.min_value) * self.span_degree) # 计算实时值进度条的角度
self.update() # 刷新画面
else: # 如果是设定值发射的信号
self.frame_history.PointValues.emit(self.spinBox_preset.value(),
float(self.label_actual.text())) # 将预设值和实际值打包发送到历史曲线的部件的输入信号
self.preset_span_degree = int(
(args[0] - self.min_value) / (self.max_value - self.min_value) * self.span_degree) # 计算设定值进度条的角度
self.update() # 刷新画面
# ########################绘制进度条圆弧###########################
def draw_arc(self, color, center, startAngle, spanAngle, width, radius):
painter = QPainter(self) # 设定画板
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
painter.setPen(QPen(color, width, Qt.SolidLine)) # 设置画笔颜色、粗细和线型
painter.drawArc(center[0] - radius, center[1] - radius, radius * 2, radius * 2, startAngle * 16, spanAngle * 16)
# #########################重写paintEvent########################
def paintEvent(self, event):
# ##################绘制实时值背景进度条###############################
self.draw_arc(self.progressBar_backColor, (self.center_point.x(), self.center_point.y()), self.begin_degree,
self.span_degree, self.processBar_actual_width, self.processBar_actual_radius)
# ##################绘制设置值背景进度条###############################
self.draw_arc(self.progressBar_backColor, (self.center_point.x(), self.center_point.y()), self.begin_degree,
self.span_degree, self.processBar_preset_width, self.processBar_preset_radius)
# ##################绘制实时值的显示进度条###############################
self.draw_arc(self.actual_text_color, (self.center_point.x(), self.center_point.y()), self.actual_begin_degree,
self.actual_span_degree, self.processBar_actual_width, self.processBar_actual_radius)
# ##################绘制设置值的显示进度条###############################
self.draw_arc(self.spinBox_preset_text_color, (self.center_point.x(), self.center_point.y()),
self.preset_begin_degree,
self.preset_span_degree, self.processBar_preset_width, self.processBar_preset_radius)
# #########################历史曲线显示窗口的class定义########################
class CustomLineChart(QFrame): # 自定义的折线表
PointValues = Signal(float, float) # 点值,设置值在前,实时值在后
def __init__(self, preset_color, actual_color, min_value, max_value, points, parent=None):
super().__init__(parent)
self.points = points # 显示的点数
self.preset_value_points = [0.0] # 设置值的数据点集
self.actual_value_points = [0.0] # 实时值的数据点集
self.overflow = False # 数据超量程
self.background_color = QColor() # 背景色
self.preset_color = preset_color # 预置值颜色
self.actual_color = actual_color # 实时值颜色
self.preset_pen = QPen() # 预设值波形的画笔
self.actual_pen = QPen() # 实时值波形的画笔
self.min_value = min_value # 最小值
self.max_value = max_value # 最大值
self.x_points = [] # X轴的分度
self.x_step = 0 # X轴的步调节拍
def customSetupUi(self): # 定制的初始化程序
# #####################建立x轴的分度表############################
x = 0
s = self.width() / (self.points - 1)
for i in range(self.points):
self.x_points.append(int(x))
x += s
# #####################初始化颜色特征############################
p = self.palette() # 获取调色板
self.background_color = p.color(p.ColorRole.Window) # 获取背景色
self.preset_pen = QPen(self.preset_color, 1) # 预置值的笔
self.actual_pen = QPen(self.actual_color, 1) # 实时值的笔
# #####################信号的连接############################
self.PointValues.connect(self.pretreat) # 当传入值以后预处理数据
self.PointValues.connect(self.update) # 当传入值以后更新画面
def pretreat(self, preset_value, actual_value): # 数据的预处理
# #####################预设值数据的预处理############################
k = (preset_value - self.min_value) / (self.max_value - self.min_value)
v = int(self.height() * (1 - k))
self.preset_value_points.append(v)
if len(self.preset_value_points) > self.points:
del self.preset_value_points[0]
# #####################实时值数据的预处理############################
if actual_value < self.min_value: # 输入值超出量程
actual_value = self.min_value
self.overflow = True
elif actual_value > self.max_value:
actual_value = self.max_value
self.overflow = True
else:
self.overflow = False
k = (actual_value - self.min_value) / (self.max_value - self.min_value) # 显示比例转换
v = int(self.height() * (1 - k))
self.actual_value_points.append(v)
if len(self.actual_value_points) > self.points:
del self.actual_value_points[0]
# ############################绘图事件####################################
def paintEvent(self, event): # 重新定义paintEvent
painter = QPainter(self) # 设定画板
painter.setPen(Qt.NoPen) # 设定画笔
# #########################重画背景###################################
if self.overflow:
color = QColor('#363636')
else:
color = self.background_color
painter.setBrush(color) # 设置笔刷
painter.drawRect(0, 0, self.width(), self.height()) # 重画背景
# #########################绘制预设值的折线#############################
pen = QPen(self.preset_color)
pen.setWidth(1)
painter.setPen(pen)
if len(self.preset_value_points) > 1:
i = 1
while i < len(self.preset_value_points):
painter.drawLine(self.x_points[i - 1], int(self.preset_value_points[i - 1]), self.x_points[i],
int(self.preset_value_points[i]))
i += 1
# #########################绘制实时值的折线#############################
pen = QPen(self.actual_color)
pen.setWidth(1)
painter.setPen(pen)
if len(self.actual_value_points) > 1:
i = 1
while i < len(self.actual_value_points):
painter.drawLine(self.x_points[i - 1], int(self.actual_value_points[i - 1]),
self.x_points[i], int(self.actual_value_points[i]))
i += 1
编写调用程序:基本的调用框架.py
# 阶段v1的调用
import random
import sys
from time import strftime
from PySide6.QtCore import QObject, Signal, QTimer
from PySide6.QtWidgets import QApplication, QMainWindow
import template_rc # 导入需要显示的画面
import 按钮图标_rc
# ############导入并需要显示的画面集中在这里定义#############################
# ############template.ui的显示#############################
class MainWindow(QMainWindow, template_rc.Ui_MainWindow): # 定义需要显示的画面类
def __int__(self):
super().__init__()
# ########################部件初始化的通用函数###################################
def init_widgets(widget): # 画面里的部件的初始化
sons = widget.children() # 儿辈部件
def find_child(child): # 查找子部件
try:
child.customSetupUi() # 自定义的初始化
except AttributeError:
pass
if child.children():
for grandson in child.children():
find_child(grandson) # 递归查找
for son in sons:
find_child(son)
def test(): # 测试程序
n1 = random.randint(-300, 300)
window1.dashboard_1.ActualValueInput.emit(float(n1 / 100.0 + 80))
# #############################主程序###################################
if __name__ == '__main__':
app = QApplication(sys.argv)
# #######################项目级别的定义###################################
class UI(QObject): # 将项目定义为QObject,用来管理项目级别的信号和变量
# ##########项目范围内的信号#############
sysClock_1S = Signal() # 秒时钟信号
# ##########定时器#############
timer_1s = QTimer() # 定义全局0.1s的周期定时器
timer_1s.start(300)
# ###########__init__###############
def __init__(self):
super().__init__()
self.widgets = [] # 所有的视窗列表
# ########################本项目的实例化###################################
ui = UI()
# #######################画面实例化和初始化#################################
# ########################实例化模板画面#################################
window1 = MainWindow()
window1.setupUi(window1) # 模板画面的本体初始化
window1.show() # 显示画面
ui.widgets.append(window1) # 将画面加入视窗列表,方便管理
# ###########################信号的连接####################################
# # ###########################项目级别信号的连接###############################
ui.timer_1s.timeout.connect(ui.sysClock_1S.emit)
ui.timer_1s.timeout.connect(test)
ui.sysClock_1S.connect(lambda: window1.labelSystemClock.setText(strftime('%Y-%m-%d %H:%M:%S')))
# ###########################Window1画面信号的连接######################
# ###########################槽函数####################################
init_widgets(window1) # 画面的子部件初始化
sys.exit(app.exec())
运行截图:
进一步的,在组态画面里按ctrl拖动复制一份 ,并改变一些几何和颜色特征,增加一个外部设定部件:
编写调用程序:仪表盘调用demo.py
# 阶段v1的调用
import random
import sys
from time import strftime
from PySide6.QtCore import QObject, Signal, QTimer
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QDoubleSpinBox
import template_rc # 导入需要显示的画面
import 按钮图标_rc
# ############导入并需要显示的画面集中在这里定义#############################
# ############template.ui的显示#############################
class MainWindow(QMainWindow, template_rc.Ui_MainWindow): # 定义需要显示的画面类
def __int__(self):
super().__init__()
# ########################部件初始化的通用函数###################################
def init_widgets(widget): # 画面里的部件的初始化
sons = widget.children() # 儿辈部件
def find_child(child): # 查找子部件
try:
child.customSetupUi() # 自定义的初始化
except AttributeError:
pass
if child.children():
for grandson in child.children():
find_child(grandson) # 递归查找
for son in sons:
find_child(son)
def test(): # 测试程序
n1 = random.randint(-300, 300)
n2 = random.randint(-300, 300)
window1.dashboard_1.ActualValueInput.emit(float(n1 / 100.0 + 80))
window1.dashboard_2.ActualValueInput.emit(float(n2 / 100.0 + 150))
# #############################主程序###################################
if __name__ == '__main__':
app = QApplication(sys.argv)
# #######################项目级别的定义###################################
class UI(QObject): # 将项目定义为QObject,用来管理项目级别的信号和变量
# ##########项目范围内的信号#############
sysClock_1S = Signal() # 秒时钟信号
# ##########定时器#############
timer_1s = QTimer() # 定义全局0.1s的周期定时器
timer_1s.start(1000)
# ###########__init__###############
def __init__(self):
super().__init__()
self.widgets = [] # 所有的视窗列表
# ########################本项目的实例化###################################
ui = UI()
# #######################画面实例化和初始化#################################
# ########################实例化模板画面#################################
window1 = MainWindow()
window1.setupUi(window1) # 模板画面的本体初始化
window1.show() # 显示画面
ui.widgets.append(window1) # 将画面加入视窗列表,方便管理
# ###########################信号的连接####################################
# # ###########################项目级别信号的连接###############################
ui.timer_1s.timeout.connect(ui.sysClock_1S.emit)
ui.timer_1s.timeout.connect(test)
ui.sysClock_1S.connect(lambda: window1.labelSystemClock.setText(strftime('%Y-%m-%d %H:%M:%S')))
# ###########################Window1画面信号的连接######################
window1.doubleSpinBox.valueChanged.connect(window1.dashboard_1.PresetValueInput.emit)
# ###########################槽函数####################################
init_widgets(window1) # 画面的子部件初始化
# QLabel
# QDoubleSpinBox
sys.exit(app.exec())
运行截图:
基本实现了设计初衷 ,前后端图像和代码分离,接口和调用简单,复制部署方便。
资源链接:(本阶段为v2)https://download.csdn.net/download/xulibo5828/89148225?spm=1001.2101.3001.9499
20240501,增加了进度条的渐变色效果:
改进后的仪表盘部件代码:
# encoding: utf-8
###################################################
# 自定义的仪表盘
###################################################
# 对外接口:
# ActualValueInput = Signal(float) # 从外部传入的实时值
# customSetup(): # 定制的初始化程序
import PySide6
from PySide6.QtCore import Signal, Qt, QPoint, QPointF
from PySide6.QtGui import QColor, QPen, QPainter, QConicalGradient
from PySide6.QtWidgets import QFrame
class PysideCustomDashboard(QFrame):
ActualValueInput = Signal(float) # 从外部传入的实时值
PresetValueInput = Signal(float) # 从外部传入的设定值
PresetValueOutput = Signal(float) # 向外部传出的设定值
def __init__(self, parent=None):
super().__init__(parent)
# self.preset_value = 0.0 # 预设值的value
self.processBar_preset_width = 0 # 预设值进度条的宽度
self.processBar_preset_radius = 0 # 预设值进度条的半径
self.processBar_actual_radius = 0 # 实时值进度条的半径
self.processBar_y_start = 0 # 进度条的外轮廓距y方向边缘距离
self.processBar_x_start = 0 # 进度条的外轮廓距x方向边缘距离
self.center_point = QPoint(0, 0) # 部件的中心坐标
self.actual_text_color = QColor() # 实时值窗口文字颜色
self.spinBox_preset_text_color = QColor() # 预设值窗口文字颜色
self.progressBar_backColor = QColor('#515d80') # 进度条背景色
self.frame_history_Palette = None # 历史曲线显示窗口的调色板
self.frame_history_styleSheet = None # 历史曲线显示窗口的样式表
self.frame_history_geometry = None # 历史曲线显示窗口的几何特征
self.label_name = None # 仪表盘名称文字框
self.label_unit = None # 显示单位文字框
self.label_actual = None # 实时值的显示文字框
self.spinBox_preset = None # 带微调的设置值输入部件
self.frame_history = None # 历史曲线显示窗口
self.begin_degree = 225 # 进度条总的起始角度
self.span_degree = -225 # 进度条总的跨度角度
self.actual_begin_degree = 225 # 实时值的进度条起始角度
self.actual_span_degree = 0 # 实时值的进度条跨度始角度
self.preset_begin_degree = 225 # 设定值的进度条起始角度
self.preset_span_degree = 0 # 设定值的进度条跨度始角度
self.min_value = 0.0 # 最小值
self.max_value = 100.0 # 最大值
self.processBar_actual_width = 0 # 进度条的宽度
self.processBar_center = QPoint(0, 0) # 进度条的中心
self.points = 10 # 显示的点数
# #######################定制的初始化程序###########################
def customSetupUi(self): # 定制的初始化程序
# ######################子部件的定义############################
children = self.children()
for child in children:
# ##############历史曲线显示窗口#####################
if 'frame_history' in child.objectName():
self.frame_history_geometry = child.geometry() # 几何数据
self.frame_history_styleSheet = child.styleSheet() # 样式表
self.frame_history_Palette = child.palette() # 颜色表
# #################带微调的设置值输入部件################
elif 'spinBox_preset' in child.objectName():
self.spinBox_preset = child
p = child.palette() # 颜色表
self.spinBox_preset_text_color = p.color(p.ColorRole.Text) # 获取预设值窗口文字颜色
self.min_value = child.minimum() # 最小值
self.max_value = child.maximum() # 最大值
# ###################实时值的显示文字框###################
elif 'label_actual' in child.objectName():
self.label_actual = child
p = child.palette() # 颜色表
self.actual_text_color = p.color(p.ColorRole.Text) # 获取实时值窗口文字颜色
# #################显示单位文字#######################
elif 'label_unit' in child.objectName():
self.label_unit = child
# ##############仪表盘名称文字####################
elif 'label_name' in child.objectName(): #
self.label_name = child
# ##################本体几何参数########################
self.center_point = QPoint(int(self.width() / 2), int((self.height() / 2))) # 中心点坐标
# ####################历史曲线显示窗口的定义###################
self.frame_history = CustomLineChart(self.spinBox_preset_text_color, self.actual_text_color, self.min_value,
self.max_value, self.points, self) # 实体化历史曲线显示窗口
self.frame_history.setGeometry(self.frame_history_geometry) # 克隆几何尺寸
self.frame_history.setStyleSheet(self.frame_history_styleSheet) # 克隆样式表
self.frame_history.setPalette(self.frame_history_Palette) # 克隆颜色表
self.frame_history.show() # 显示
# self.frame_history.customSetupUi() # 历史曲线显示窗口初始化
# ####################进度条的定义##############################
self.processBar_actual_width = int((self.width() / 50)) # 实时值进度条的宽度
# self.processBar_preset_width = self.processBar_actual_width # 预设值进度条的宽度
self.processBar_preset_width = int(self.processBar_actual_width * 0.66) # 预设值进度条的宽度
# self.processBar_preset_width = int(self.processBar_actual_width / 3)
self.processBar_x_start = int(self.width() / 20) # 进度条的外轮廓距x方向边缘距离
self.processBar_y_start = int(self.width() / 20) # 进度条的外轮廓距y方向边缘距离
self.processBar_actual_radius = int(
(self.width() / 2) - self.processBar_x_start - (self.processBar_actual_width / 2) * 0.9) # 实时值进度条的半径
self.processBar_preset_radius = int(
self.processBar_actual_radius - self.processBar_actual_width) # 预设值进度条的半径
self.signal_handing([self.spinBox_preset.value(), 'preset']) # 初始化一下预设值进度条的显示
# ######################信号的连接############################
self.ActualValueInput.connect(lambda x: self.signal_handing([x, 'actual'])) # 接收到外部传入实时数据后的信号处理
self.PresetValueInput.connect(self.spinBox_preset.setValue) # 接收到外部传入设置值后的信号处理
self.spinBox_preset.valueChanged.connect(lambda x: self.signal_handing([x, 'preset'])) # 设置值发生改变后的信号处理
# #######################发射信号的处理############################
def signal_handing(self, args):
if args[1] == 'actual': # 如果是实时值发射的信号
self.frame_history.PointValues.emit(self.spinBox_preset.value(), args[0]) # 将预设值和实际值打包发送到历史曲线的部件的输入信号
self.label_actual.setText(str(args[0])) # 实时显示实际值的数字
self.actual_span_degree = int(
(args[0] - self.min_value) / (self.max_value - self.min_value) * self.span_degree) # 计算实时值进度条的角度
self.update() # 刷新画面
else: # 如果是设定值发射的信号
self.frame_history.PointValues.emit(self.spinBox_preset.value(),
float(self.label_actual.text())) # 将预设值和实际值打包发送到历史曲线的部件的输入信号
self.preset_span_degree = int(
(args[0] - self.min_value) / (self.max_value - self.min_value) * self.span_degree) # 计算设定值进度条的角度
self.update() # 刷新画面
# ########################绘制进度条圆弧###########################
def draw_arc(self, color, center, startAngle, spanAngle, width, radius):
painter = QPainter(self) # 设定画板
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
painter.setPen(QPen(color, width, Qt.SolidLine)) # 设置画笔颜色、粗细和线型
painter.drawArc(center[0] - radius, center[1] - radius, radius * 2, radius * 2, startAngle * 16, spanAngle * 16)
# #########################重写paintEvent########################
def paintEvent(self, event):
# ##################绘制实时值背景进度条###############################
self.draw_arc(self.progressBar_backColor, (self.center_point.x(), self.center_point.y()), self.begin_degree,
self.span_degree, self.processBar_actual_width, self.processBar_actual_radius)
# print(self.preset_begin_degree, self.preset_span_degree)
# ##################绘制设置值背景进度条###############################
self.draw_arc(self.progressBar_backColor, (self.center_point.x(), self.center_point.y()), self.begin_degree,
self.span_degree, self.processBar_preset_width, self.processBar_preset_radius)
# ##################绘制实时值的显示进度条###############################
# self.draw_arc(self.actual_text_color, (self.center_point.x(), self.center_point.y()), self.actual_begin_degree,
# self.actual_span_degree, self.processBar_actual_width, self.processBar_actual_radius) # 选择1:画单色的圆弧
gradient = QConicalGradient(self.center_point.x(), self.center_point.y(), self.actual_begin_degree + self.actual_span_degree) # 创建锥形梯度
color = self.actual_text_color # 定义临时颜色
gradient.setColorAt(0, color) # 定义渐变色的起点颜色
color.setAlpha(120) # 定义渐变色的中点颜色
k = abs(self.actual_span_degree) / 360
gradient.setColorAt(0.2*k, color)
color.setAlpha(10) # 定义渐变色的终点颜色
gradient.setColorAt(k, color)
self.draw_arc(gradient, (self.center_point.x(), self.center_point.y()), self.actual_begin_degree, # 选择2:画渐变色的圆弧
self.actual_span_degree, self.processBar_actual_width, self.processBar_actual_radius)
color.setAlpha(255) # 复位颜色
# ##################绘制设置值的显示进度条###############################
# self.draw_arc(self.spinBox_preset_text_color, (self.center_point.x(), self.center_point.y()),
# self.preset_begin_degree,
# self.preset_span_degree, self.processBar_preset_width, self.processBar_preset_radius) # 选择1:画单色的圆弧
gradient = QConicalGradient(self.center_point.x(), self.center_point.y(),
self.preset_begin_degree + self.preset_span_degree) # 创建锥形梯度
color = self.spinBox_preset_text_color # 定义临时颜色
gradient.setColorAt(0, color) # 定义渐变色的起点颜色
color.setAlpha(120) # 定义渐变色的中点颜色
k = abs(self.preset_span_degree) / 360
gradient.setColorAt(0.2 * k, color)
color.setAlpha(10)
k = abs(self.preset_span_degree) / 360
gradient.setColorAt(k, color) # 定义渐变色的终点颜色
self.draw_arc(gradient, (self.center_point.x(), self.center_point.y()), self.preset_begin_degree, # 选择2:画渐变色的圆弧
self.preset_span_degree, self.processBar_preset_width, self.processBar_preset_radius)
color.setAlpha(255) # 复位颜色
# #########################历史曲线显示窗口的class定义########################
class CustomLineChart(QFrame): # 自定义的折线表
PointValues = Signal(float, float) # 点值,设置值在前,实时值在后
def __init__(self, preset_color, actual_color, min_value, max_value, points, parent=None):
super().__init__(parent)
self.points = points # 显示的点数
self.preset_value_points = [0.0] # 设置值的数据点集
self.actual_value_points = [0.0] # 实时值的数据点集
self.overflow = False # 数据超量程
self.background_color = QColor() # 背景色
self.preset_color = preset_color # 预置值颜色
self.actual_color = actual_color # 实时值颜色
self.preset_pen = QPen() # 预设值波形的画笔
self.actual_pen = QPen() # 实时值波形的画笔
self.min_value = min_value # 最小值
self.max_value = max_value # 最大值
self.x_points = [] # X轴的分度
self.x_step = 0 # X轴的步调节拍
def customSetupUi(self): # 定制的初始化程序
# #####################建立x轴的分度表############################
x = 0
s = self.width() / (self.points - 1)
for i in range(self.points):
self.x_points.append(int(x))
x += s
# #####################初始化颜色特征############################
p = self.palette() # 获取调色板
self.background_color = p.color(p.ColorRole.Window) # 获取背景色
self.preset_pen = QPen(self.preset_color, 1) # 预置值的笔
self.actual_pen = QPen(self.actual_color, 1) # 实时值的笔
# #####################信号的连接############################
self.PointValues.connect(self.pretreat) # 当传入值以后预处理数据
self.PointValues.connect(self.update) # 当传入值以后更新画面
def pretreat(self, preset_value, actual_value): # 数据的预处理
# #####################预设值数据的预处理############################
k = (preset_value - self.min_value) / (self.max_value - self.min_value)
v = int(self.height() * (1 - k))
self.preset_value_points.append(v)
if len(self.preset_value_points) > self.points:
del self.preset_value_points[0]
# #####################实时值数据的预处理############################
if actual_value < self.min_value: # 输入值超出量程
actual_value = self.min_value
self.overflow = True
elif actual_value > self.max_value:
actual_value = self.max_value
self.overflow = True
else:
self.overflow = False
k = (actual_value - self.min_value) / (self.max_value - self.min_value) # 显示比例转换
v = int(self.height() * (1 - k))
self.actual_value_points.append(v)
if len(self.actual_value_points) > self.points:
del self.actual_value_points[0]
# ############################绘图事件####################################
def paintEvent(self, event): # 重新定义paintEvent
painter = QPainter(self) # 设定画板
painter.setPen(Qt.NoPen) # 设定画笔
# #########################重画背景###################################
if self.overflow:
color = QColor('#666666')
else:
color = self.background_color
painter.setBrush(color) # 设置笔刷
painter.drawRect(0, 0, self.width(), self.height()) # 重画背景
# #########################绘制预设值的折线#############################
pen = QPen(self.preset_color)
pen.setWidth(1)
painter.setPen(pen)
if len(self.preset_value_points) > 1:
i = 1
while i < len(self.preset_value_points):
painter.drawLine(self.x_points[i - 1], int(self.preset_value_points[i - 1]), self.x_points[i],
int(self.preset_value_points[i]))
i += 1
# #########################绘制实时值的折线#############################
pen = QPen(self.actual_color)
pen.setWidth(1)
painter.setPen(pen)
if len(self.actual_value_points) > 1:
i = 1
while i < len(self.actual_value_points):
painter.drawLine(self.x_points[i - 1], int(self.actual_value_points[i - 1]),
self.x_points[i], int(self.actual_value_points[i]))
i += 1