我用PYQT5做的第一个实用的上位机项目(五)

制作一个动态仪表盘。

我用PYQT5做的第一个实用的上位机项目(五)_第1张图片

 具体过程参照前面技术储备阶段的文章:

PYQT制作动态时钟-CSDN博客

使用PYQT5简单制作动态仪表盘-CSDN博客

仪表盘由以下部件构成:背景

我用PYQT5做的第一个实用的上位机项目(五)_第2张图片

指针 

我用PYQT5做的第一个实用的上位机项目(五)_第3张图片

 表盘

我用PYQT5做的第一个实用的上位机项目(五)_第4张图片

 进度条(设定值)

我用PYQT5做的第一个实用的上位机项目(五)_第5张图片

 遮罩

我用PYQT5做的第一个实用的上位机项目(五)_第6张图片

 设定和显示

我用PYQT5做的第一个实用的上位机项目(五)_第7张图片

其中表盘、 进度条和指针的外形尺寸以及几何位置相同,背景色都是透明色。通过旋转指针和进度条的角度来实现显示。遮罩的作用是把进度条的下半部分遮住。

总结一下,目前有两个画面:主画面和数据设置画面,一个选择器,一个仪表盘,一个指示灯,几个功能按钮。程序在之前的基础上进行了一些规划上的优化,基本框架也已经建立,结构如下:

我用PYQT5做的第一个实用的上位机项目(五)_第8张图片

如上图,每个画面对应一个同名的首字母大写的类,用来补充定义画面。

我用PYQT5做的第一个实用的上位机项目(五)_第9张图片

 同样的,画面中的部件,每个部件对应一个同名的首字母大写的类,用来补充定义部件。

所有代码:

from sys import exit, argv
from time import strftime

from PyQt5.QtCore import Qt, QCoreApplication, pyqtSignal, QObject
from PyQt5.QtGui import QTransform
from PyQt5.QtWidgets import QApplication
from PyQt5 import uic
import buttons  # 按钮的内嵌图片资源
# import dash     # 仪表盘的内嵌图片资源
from PYS.MyButton import MyButton
from PYS.MyDash import *
from PYS.MyLabel import MyLabel
from PYS.MyLamp import MyLamp
from PYS.MySelectBox import *


############################################
# 公共的函数
class PublicFunction:  # 公共函数
    @staticmethod
    def normal_button_init(button):  # 通常规格按钮的初始化
        # button.button.isEntered = False  # 鼠标焦点是否在内
        button.setImage()  # 获取按钮上的图片
        button.style_normal = f'background-color:#4b5075;border-radius:8px;border:2px solid  rgb(43, 78, 140);color:#e6e6e6;image:{button.image};'  # 常态style
        button.style_enter = f'background-color:#4b5075;border-radius:8px;border:3px solid  #e6e6e6;color:#e6e6e6;image:{button.image};'  # 鼠标悬停后的style
        button.style_clicked = f'background-color:#4b5075;border:2px solid  #039806;border-radius:8px;color:#e6e6e6;image:{button.image};'  # 鼠标点击后的style
        button.style_on = f'background-color:#039806;border:4px solid  #e6e6e6;border-radius:8px;color:#e6e6e6;image:{button.image};'  # ON状态的style
        button.style_disable = f'background-color:#767676;border:2px solid  rgb(43, 78, 140);border-radius:8px;color:#c6c6c6;image:{button.image};'  # 禁用状态下的style

    @staticmethod
    def green_lamp_init(lamp):  # 绿色指示灯
        lamp.rad = str(round(lamp.width() / 2))
        lamp.off_color = '#767676'  # 默认off颜色
        lamp.on_color = '#039806'  # 默认on颜色
        lamp.border_color = '#2b4e8c'  # 默认的边框颜色

    @staticmethod
    def red_lamp_init(lamp):  # 红色指示灯
        lamp.rad = str(round(lamp.width() / 2))
        lamp.off_color = '#767676'  # 默认off颜色
        lamp.on_color = '#da1c1c'  # 默认on颜色
        lamp.border_color = '#2b4e8c'  # 默认的边框颜色

    @staticmethod
    def normal_label_init(label):  # 通常标签的初始化
        label.isEntered = False  # 鼠标焦点是否在内
        label.style_normal = 'background-color:#000d47;border:2px solid #4b5075;border-radius:8px;color:#f3da83;'  # 常态style
        label.style_enter = 'background-color:#4b5075;border-radius:8px;border:3px solid  #e6e6e6;color:#e6e6e6;'  # 鼠标悬停后的style
        label.style_clicked = 'background-color:#4b5075;border:2px solid  #039806;border-radius:8px;color:#e6e6e6;'  # 鼠标点击后的style

    @staticmethod
    def normal_selectorBox_init(selector):  # 通常选择box的初始化
        selector.start_on = 0  # 起始状态为on的序号
        selector.controls_normal_style = 'color: #e6e6e6;background-color: rgba(255, 255, 255, 0);border-radius:2px;border:0px solid #1e2557;'  # 默认控制器常态style
        selector.controls_enter_style = 'color: #e6e6e6;background-color: rgba(255, 255, 255, 0);border-radius:2px;border:1px solid #e6e6e6;'  # 默认控制器鼠标悬停style
        selector.controls_clicked_style = 'color: #e6e6e6;background-color: rgba(255, 255, 255, 0);border-radius:2px;border:1px solid #039806;'  # 默认控制器鼠标点击style

        selector.states_off_style = 'border:2px solid  rgb(43, 78, 140);background-color:#4b5075;border-radius:2px;'  # 默认指示器off状态style
        selector.states_on_style = 'border:2px solid  rgb(43, 78, 140);background-color:#039806;border-radius:2px;'  # 默认指示器on状态style

        for c in selector.controls:  # 初始化控制器
            c.style_normal = selector.controls_normal_style
            c.style_enter = selector.controls_enter_style
            c.style_clicked = selector.controls_clicked_style

        for i in range(len(selector.states)):  # 初始化指示器
            selector.states[i].states_on_style = selector.states_on_style
            selector.states[i].states_off_style = selector.states_off_style
            if i == selector.start_on:
                selector.states[i].setStyleSheet(selector.states_on_style)
            else:
                selector.states[i].setStyleSheet(selector.states_off_style)

    @staticmethod
    def normal_dash_init(dash):  # 通常仪表盘的初始化
        dash.adjusts_normal_style = 'background-color:#000d47;border:2px solid #4b5075;border-radius:8px;color:#f3da83;'  # “微调”按钮常态style
        dash.adjusts_clicked_style = 'background-color:#000d47;border:2px solid #039806;border-radius:8px;color:#f3da83;'  # “微调”按钮点击后的style
        dash.adjusts_enter_style = 'background-color:#000d47;border:1px solid #e6e6e6;border-radius:8px;color:#f3da83;'  # “微调”按钮鼠标悬停的style
        dash.setting_normal_style = 'background-color:#000d47;border:2px solid #4b5075;border-radius:8px;color:#f3da83;'  # “设置”标签常态style
        dash.setting_clicked_style = 'background-color:#000d47;border:2px solid #039806;border-radius:8px;color:#f3da83;'  # “设置”标签点击后的style
        dash.setting_enter_style = 'background-color:#000d47;border:1px solid #e6e6e6;border-radius:8px;color:#f3da83;'  # “设置”标签鼠标悬停的style

        dash.panel_image = normal_dash_panel_image
        dash.pointer_image = normal_dash_pointer_image
        dash.preset_image = normal_dash_preset_image

        dash.panel.setPixmap(dash.panel_image)
        dash.pointer.setPixmap(dash.pointer_image)
        dash.preset.setPixmap(dash.preset_image)

        dash.pointer.setAlignment(Qt.AlignCenter)
        dash.panel.setAlignment(Qt.AlignCenter)
        dash.preset.setAlignment(Qt.AlignCenter)

        dash.label_setting.style_normal = dash.setting_clicked_style  # “设置”标签常态style
        dash.label_setting.style_clicked = dash.setting_clicked_style  # “设置”标签点击后的style
        dash.label_setting.style_enter = dash.setting_enter_style  # “设置”标签点击后的style

        dash.adjust_down.style_normal = dash.adjusts_normal_style  # “微调-”按钮常态style
        dash.adjust_down.style_clicked = dash.adjusts_clicked_style  # “微调-”按钮点击后的style
        dash.adjust_down.style_enter = dash.adjusts_enter_style  # “微调-”按钮点击后的style

        dash.adjust_up.style_normal = dash.adjusts_normal_style  # “微调-”按钮常态style
        dash.adjust_up.style_clicked = dash.adjusts_clicked_style  # “微调-”按钮点击后的style
        dash.adjust_up.style_enter = dash.adjusts_enter_style  # “微调-”按钮点击后的style


############################################
# 画面的类,每个画面对应一个同名的首字母大写的类,这个类补充定义了画面

class Form0:  # 画面form0的类(form0是主窗口)
    def __init__(self):
        # 画面中部件的类,每个部件对应一个同名的首字母大写的类,这个类补充定义了对应的部件
        self.LabelSystemClock = self.LabelSystemClock()
        self.Lamp_working_1 = self.Lamp_working_1()
        self.Btn_history = self.Btn_history()
        self.Btn_user = self.Btn_user()
        self.Btn_exit = self.Btn_exit()
        self.Btn_setting = self.Btn_setting()
        self.Selector_1 = self.Selector_1()
        self.Dash_1 = self.Dash_1()
        #  以下测试用   ######################################################
        form0.slider1.valueChanged.connect(lambda: self.Dash_1.preset.setPixmap(
            self.Dash_1.preset_image.transformed(QTransform().rotate(round(form0.slider1.value() * 0.3)))))
        form0.slider2.valueChanged.connect(lambda: self.Dash_1.pointer.setPixmap(
            self.Dash_1.pointer_image.transformed(QTransform().rotate(round(form0.slider2.value() * 0.3)))))
        #  以上测试用   ######################################################
        form0.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)  # 关掉边框,始终最前
        form0.menuBar().setVisible(False)  # 关闭顶部菜单栏
        form0.statusBar().setVisible(False)  # 关闭底部状态栏

    # 画面中的部件的类,每个部件对应一个同名的首字母大写的类,作为对部件的补充定义
    class LabelSystemClock(QLabel):  # 主画面时钟
        def __init__(self, parent=None):
            super().__init__(parent)
            self.label = form0.labelSystemClock  # 本class对应的实体部件
            # 本部件的所有特性已经在Qt Designer样式表里面定义,无需补充和再次初始化

    class Btn_exit(MyButton):  # “退出系统”按钮对应的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.button = form0.btn_exit  # 本class对应的实体部件
            PublicFunction.normal_button_init(self.button)  # 引用通常规格按钮的初始化
            self.button.Clicked.connect(self.beClicked)  # 本按钮单机后的连接

        def beClicked(self):  # 本按钮点击后的操作
            for f in forms:  # 关闭所有窗口
                f.close()

    class Btn_setting(MyButton):  # “参数设置”按钮对应的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.button = form0.btn_setting  # 本class对应的实体部件
            PublicFunction.normal_button_init(self.button)  # 引用通常规格按钮的初始化
            #  以下测试用   ######################################################
            self.button.Clicked.connect(lambda: Form0.Lamp_working_1.lamp.color_on_bool(False))  # 这两种方法的作用是相同的
            form0.btn_setting.Clicked.connect(lambda: form0.lamp_working_1.color_on_bool(False))
            #  以上测试用   ######################################################

    class Btn_user(MyButton):  # “用户管理”按钮对应的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.button = form0.btn_user  # 本class对应的实体部件
            PublicFunction.normal_button_init(self.button)  # 引用通常规格按钮的初始化

    class Btn_history(MyButton):  # “历史数据”按钮对应的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.button = form0.btn_history  # 本class对应的实体部件
            PublicFunction.normal_button_init(self.button)  # 引用通常规格按钮的初始化

    class Lamp_working_1(MyLamp):  # “工作指示1”指示灯对应的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.lamp = form0.lamp_working_1  # 本class对应的实体部件
            PublicFunction.green_lamp_init(self.lamp)  # 初始化为绿色指示灯
            self.lamp.color_on_bool(True)  # 初始化为on状态

    class Selector_1(MySelectorBox):  # 选择器1对应的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.control0 = form0.control0_selector_1  # 本class对应的实体部件
            self.control1 = form0.control1_selector_1
            self.state0 = form0.state0_selector_1
            self.state1 = form0.state1_selector_1
            self.controls = [self.control0, self.control1]  # 选择器们的集合
            self.states = [self.state0, self.state1]  # 状态指示灯的集合
            PublicFunction.normal_selectorBox_init(self)  # 引用通常选择器的初始化

            self.control0.Clicked.connect(lambda: self.control_clicked(0))
            self.control1.Clicked.connect(lambda: self.control_clicked(1))

        def control_clicked(self, n):
            for i in range(len(self.states)):
                if i == n:
                    self.states[i].setStyleSheet(self.states_on_style)
                else:
                    self.states[i].setStyleSheet(self.states_off_style)

    class Dash_1(MyDash):  # 仪表盘1对应的类

        def __init__(self, parent=None):
            super().__init__(parent)
            self.panel = form0.panel_dash_1  # 仪表面板
            self.pointer = form0.pointer_dash_1  # 仪表指针
            self.preset = form0.preset_dash_1  # 预设值指示

            self.label_setting = form0.label_setting_dash_1  # "设置值“标签
            self.label_actual = form0.label_actual_dash_1  # "实际值“标签

            self.adjust_down = form0.adjust_down_dash_1  # 微调-按钮
            self.adjust_up = form0.adjust_up_dash_1  # 微调+按钮

            PublicFunction.normal_dash_init(self)  # 引用通常仪表盘的初始化

            self.label_setting.DoubleClicked.connect(self.label_setting_double_clicked)  # “设定值”标签双击后的连接

        def label_setting_double_clicked(self):  # “设定值”标签双击后的动作
            form_setting.move(self.label_setting.pos())  # 将数据设置画面移动至标签所在位置
            form_setting.label_setting.setText(self.label_setting.text())  # 将 “设定值”标签的内容显示在数据设置画面的“设置”标签内
            form_setting.show()  # 显示设置画面
            Form_setting.Btn_OK.todo = self.todo1  # 定义数据设置画面“确定”按钮按下后执行的函数名

        def todo1(self):  # 数据设置画面“确定”按钮按下后执行的函数内容
            self.label_setting.setText(form_setting.label_setting.text())


class Form_setting:  # 画面form_setting的类(form_setting是共用的数据设置窗口)
    def __init__(self):  # 画面form_setting的类的初始化
        form_setting.setWindowFlags(Qt.WindowStaysOnTopHint)  # 始终最前
        self.Btn_OK = self.Btn_OK()
        self.Btn_cancel = self.Btn_cancel()
        self.Label_setting = self.Label_setting()

    class Btn_OK(MyButton):  # “确定”按钮的类
        todo = None  # 这是一个共用的画面,todo是本画面确定键按下后将要执行的函数
        args = []  # todo函数的参数

        def __init__(self, parent=None):
            super().__init__(parent)
            self.button = form_setting.btn_OK  # 本class对应的实体部件
            PublicFunction.normal_button_init(self.button)  # 引用通常规格按钮的初始化
            self.button.Clicked.connect(self.beClicked)  # “确定”按钮 点击后的连接

        def beClicked(self):  # “确定”按钮 点击后的动作
            self.todo(*self.args)  # 点击OK后执行预置的函数
            form_setting.close()  # 关闭画面

    class Btn_cancel(MyButton):  # “取消”按钮的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.button = form_setting.btn_cancel  # 本class对应的实体部件
            PublicFunction.normal_button_init(self.button)  # 引用通常规格按钮的初始化

            self.button.Clicked.connect(form_setting.close)  # 关闭画面

    class Label_setting(MyLabel):  # “设定值”标签的类
        def __init__(self, parent=None):
            super().__init__(parent)
            self.label = form_setting.label_setting  # 本class对应的实体部件
            PublicFunction.normal_label_init(self.label)  # 引用通常规格标签的初始化


############################################
# 主函数
if __name__ == '__main__':
    app = QApplication(argv)
    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)  # 解决显示比例不同时的部件变形问题
    # 全局公用图片资源  ###################################
    normal_dash_panel_image = QPixmap("../UIS/表盘.png")
    normal_dash_pointer_image = QPixmap("../UIS/指针.png")
    normal_dash_preset_image = QPixmap("../UIS/预设.png")

    # 界面相关  ###################################
    forms = []  # 所有界面的集合
    form0 = uic.loadUi('../UIS/form0.ui')  # 生成并加载画面,form0是主画面
    forms.append(form0)
    Form0 = Form0()  # form0对应的类是Form0,将类Form0实体化

    form0.show()

    form_setting = uic.loadUi('../UIS/设定值.ui')
    forms.append(form_setting)
    Form_setting = Form_setting()  # form_setting对应的类是Form_setting,将类Form_setting实体化

    #           全局的类              #
    class Ui(QObject):  # 作用全局的所有变量和信号在这里定义
        signal_1S = pyqtSignal()  # 秒周期信号
        sys_counter = 0  # 系统计数器,用以控制节拍
        timer_1S = QTimer()   # 秒周期定时器
        timer_1S.start(1000)

        def connects(self):   # 作用全局的连接在这里定义
            self.timer_1S.timeout.connect(Ui.signal_1S.emit)  # 秒周期定时器超时后,秒周期信号emit
            self.signal_1S.connect(lambda: Form0.LabelSystemClock.label.setText(strftime('%Y-%m-%d %H:%M:%S')))    # 秒周期信号的连接

    Ui = Ui()   # 实体化
    Ui.connects()  # 定义全局连接

    exit(app.exec_())

运行截图:

我用PYQT5做的第一个实用的上位机项目(五)_第10张图片

你可能感兴趣的:(pyqt)