实战PyQt5: 106-定制应用显示风格

为应用定制个性显示风格

在很多专业应用中,比如PhotoShop, VS Studio, VS Code等,都可以定制个性的显示风格,一旦指定某种风格之后,窗口及窗口的控件将随着风格的变化而变化。一个GUI程序最常见的两类风格方式就是浅色风格和深色风格。在Qt中,使用QApplication.setStyle()和QApplication.setPalette()可以定制出不同的风格,下面我们在前文<<设置应用的显示风格>>的演示代码基础上,实现一种浅色风格主题和一种深色风格主题。并通过菜单来动态切换这两种显示风格。

浅色风格和深色风格我们使用同一个主题'Fusion',对调色板QPalette中的颜色变量进行指定,就可以实现我们的目标。

测试代码

在主窗口的菜单条中添加"主题菜单", 主题菜单下有两个菜单项,分别为"浅色主题"和"深色主题",点击相应的菜单项,窗口的显示风格做相应切换。完整代码如下:

import sys
from PyQt5.QtCore import Qt, QTimer, QDateTime, QDate
from PyQt5.QtGui import QPalette, QColor
from PyQt5.QtWidgets import (QApplication, QWidget, QMainWindow, QPushButton, QTextEdit, 
                             QGroupBox, QCheckBox, QRadioButton, QComboBox, QLabel,
                             QVBoxLayout, QHBoxLayout, QGridLayout, QStyleFactory,
                             QTabWidget, QSizePolicy, QProgressBar, QTableWidget,
                             QLineEdit, QSpinBox, QDateTimeEdit, QSlider,
                             QScrollBar, QDial, QCalendarWidget,
                             QMenu, QMenuBar, QAction, QActionGroup)
 
#标记控制窗口
class WindowStyleDemo(QMainWindow):
    def __init__(self):
        super(WindowStyleDemo, self).__init__()
        
        # 设置窗口标题
        self.setWindowTitle('实战PyQt5: 定制显示风格演示')
        
        #应用的初始调色板
        self.origPalette = QApplication.palette()
        
        self.initUi()
        
    def initUi(self):
        self.initMenuBar()
               
        #生成要显示的部件
        self.createTopLeftGroupBox()
        self.createTopRightGroupBox()
        self.createBottomLeftTabWidget()
        self.createBottomRightGroupBox()
        self.createProgressBar()
        
        mainLayout = QGridLayout()
        mainLayout.addWidget(self.topLeftGroupBox, 1, 0) #1行0列
        mainLayout.addWidget(self.topRightGroupBox, 1, 1) #1行1列
        mainLayout.addWidget(self.bottomLeftTabWidget, 2, 0) #2行0列
        mainLayout.addWidget(self.bottomRightGroupBox, 2, 1) #2行1列
        mainLayout.addWidget(self.progressBar, 3, 0, 1, 2) ## 3行0列,占1行2列
        mainLayout.setRowStretch(1, 1)
        mainLayout.setRowStretch(2, 1)
        mainLayout.setColumnStretch(0, 1)
        mainLayout.setColumnStretch(1, 1)
        
        mainWidget = QWidget()
        mainWidget.setLayout(mainLayout)
        
        self.setCentralWidget(mainWidget)
    
    #菜单栏设置
    def initMenuBar(self):
        mBar = self.menuBar()
        
        menuFile = mBar.addMenu('文件(&F)')          
        aExit = QAction('退出(&X)', self)
        aExit.triggered.connect(self.close)
        menuFile.addAction(aExit)
        
        menuTheme = mBar.addMenu('主题(&T)')
        aLight = QAction('浅色主题(&L)')
        aLight.setCheckable(True)
        aLight.triggered.connect(lambda: self.onSetTheme('Light'))
        aDark = QAction('深色主题(&D)')
        aDark.setCheckable(True)
        aDark.triggered.connect(lambda: self.onSetTheme('Dark'))
        menuTheme.addAction(aLight)
        menuTheme.addAction(aDark)
        
        #行为组
        agTheme = QActionGroup(self)
        agTheme.addAction(aLight)
        agTheme.addAction(aDark)
        aLight.setChecked(True)
        
        #设置启动时的主题效果
        self.onSetTheme('Light')
    
    #创建左上角成组部件
    def createTopLeftGroupBox(self):
        self.topLeftGroupBox = QGroupBox('组 1')
        
        rad1 = QRadioButton('单选按钮1')
        rad2 = QRadioButton('单选按钮2')
        rad3 = QRadioButton('单选按钮3')
        rad1.setChecked(True)
        
        chk = QCheckBox('三态复选按钮')
        chk.setTristate(True)
        chk.setCheckState(Qt.PartiallyChecked)
        
        layout = QVBoxLayout()
        layout.addWidget(rad1)
        layout.addWidget(rad2)
        layout.addWidget(rad3)
        layout.addWidget(chk)
        layout.addStretch(1)
        
        self.topLeftGroupBox.setLayout(layout)
        
    #创建右上角成组部件
    def createTopRightGroupBox(self):
        self.topRightGroupBox = QGroupBox('组 2')
        
        btnDefault = QPushButton('Push Button:缺省模式')
        btnDefault.setDefault(True)
        
        btnToggle = QPushButton('Push Button: 切换模式')
        btnToggle.setCheckable(True)
        btnToggle.setChecked(True)
        
        btnFlat = QPushButton('Push Button: 扁平外观')
        btnFlat.setFlat(True)
        
        layout = QVBoxLayout()
        layout.addWidget(btnDefault)
        layout.addWidget(btnToggle)
        layout.addWidget(btnFlat)
        layout.addStretch(1)
        
        self.topRightGroupBox.setLayout(layout)
        
    #创建左下角Tab控件
    def createBottomLeftTabWidget(self):
        self.bottomLeftTabWidget = QTabWidget()
        self.bottomLeftTabWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Ignored)
        
        tab1 = QWidget()
        tableWidget = QTableWidget(10, 10)  #10行10列
        
        tab1Layout = QHBoxLayout()
        tab1Layout.setContentsMargins(5,5,5,5)
        tab1Layout.addWidget(tableWidget)
        tab1.setLayout(tab1Layout)
        
        tab2 = QWidget()
        textEdit = QTextEdit()
        textEdit.setPlainText("一闪一闪小星星,\n"
                              "我想知道你是什么.\n" 
                              "在整个世界之上, 如此的高,\n"
                              "像在天空中的钻石.\n"
                              "一闪一闪小星星,\n" 
                              "我多想知道你是什么!\n")
        
        tab2Layout = QHBoxLayout()
        tab2Layout.setContentsMargins(5, 5, 5, 5)
        tab2Layout.addWidget(textEdit)
        tab2.setLayout(tab2Layout)
        
        tab3 = QWidget()
        calendar = QCalendarWidget()
        #设置最小日期
        calendar.setMinimumDate(QDate(1900,1,1))
        #设置最大日期
        calendar.setMaximumDate(QDate(4046,1,1))
        #设置网格可见
        calendar.setGridVisible(True)
        tab3Layout = QHBoxLayout()
        tab3Layout.setContentsMargins(5, 5, 5, 5)
        tab3Layout.addWidget(calendar)
        tab3.setLayout(tab3Layout)
        
        self.bottomLeftTabWidget.addTab(tab1, '表格(&T)')
        self.bottomLeftTabWidget.addTab(tab2, '文本编辑(&E)')
        self.bottomLeftTabWidget.addTab(tab3, '日历(&C)')
          
    #创建右下角成组部件
    def createBottomRightGroupBox(self):
        self.bottomRightGroupBox = QGroupBox('组 3')
        self.bottomRightGroupBox.setCheckable(True)
        self.bottomRightGroupBox.setChecked(True)
        
        lineEdit = QLineEdit('s3cRe7')
        lineEdit.setEchoMode(QLineEdit.Password)
        
        spinBox = QSpinBox(self.bottomRightGroupBox)
        spinBox.setValue(50)
        
        dateTimeEdit = QDateTimeEdit(self.bottomRightGroupBox)
        dateTimeEdit.setDateTime(QDateTime.currentDateTime())
        
        slider = QSlider(Qt.Horizontal, self.bottomRightGroupBox)
        slider.setValue(40)
        
        scrollBar = QScrollBar(Qt.Horizontal, self.bottomRightGroupBox)
        scrollBar.setValue(60)
        
        dial = QDial(self.bottomRightGroupBox)
        dial.setValue(30)
        dial.setNotchesVisible(True)
        
        layout = QGridLayout()
        layout.addWidget(lineEdit, 0, 0, 1, 2)  #0行0列,占1行2列
        layout.addWidget(spinBox, 1, 0, 1, 2)   #1行0列,占1行2列
        layout.addWidget(dateTimeEdit, 2, 0, 1, 2) #2行0列,占1行2列
        layout.addWidget(slider, 3, 0)  #3行0列,占1行3列
        layout.addWidget(scrollBar, 4, 0) #4行0列,占1行1列
        layout.addWidget(dial, 3, 1, 2, 1)  #3行1列,占2行1列
        layout.setRowStretch(5, 1)
        
        self.bottomRightGroupBox.setLayout(layout)
        
    #禁止窗口上的组件
    def setWidgetsDisbaled(self, disable):
        self.topLeftGroupBox.setDisabled(disable)
        self.topRightGroupBox.setDisabled(disable)
        self.bottomLeftTabWidget.setDisabled(disable)
        self.bottomRightGroupBox.setDisabled(disable)
        
    #创建进度条
    def createProgressBar(self):
        self.progressBar = QProgressBar()
        self.progressBar.setRange(0, 10000)
        self.progressBar.setValue(0)
        
        # 定时器,定时更新进度条的值
        timer = QTimer(self)
        timer.timeout.connect(self.advanceProgressBar)
        timer.start(100)
        
    #设置进度条的值        
    def advanceProgressBar(self):
        curVal = self.progressBar.value()
        maxVal = self.progressBar.maximum()
        self.progressBar.setValue(curVal + (maxVal - curVal)//100)
        
    #设置主题样式
    def onSetTheme(self, theme):
        if(theme == 'Light'):
            style = QStyleFactory.create('Fusion')
            QApplication.setStyle(style)
            palette = style.standardPalette()
            palette.setColor(QPalette.Mid, QColor(232, 243, 251))
            QApplication.setPalette(palette)
        elif(theme == 'Dark'):
            QApplication.setStyle('Fusion')
            palette = QPalette()
            palette.setColor(QPalette.Window, QColor(50, 50, 50))
            palette.setColor(QPalette.WindowText, QColor(220,220,220))
            palette.setColor(QPalette.Base, QColor(30,30,30))
            palette.setColor(QPalette.AlternateBase, QColor(40,40,40))
            palette.setColor(QPalette.Highlight, QColor(23,92,118))
            palette.setColor(QPalette.HighlightedText, Qt.white)
            palette.setColor(QPalette.ToolTipBase, palette.color(QPalette.Highlight))
            palette.setColor(QPalette.ToolTipText, palette.color(QPalette.WindowText))
            palette.setColor(QPalette.Text, palette.color(QPalette.WindowText))
            palette.setColor(QPalette.BrightText, Qt.red)
            palette.setColor(QPalette.Button, palette.color(QPalette.Window))
            palette.setColor(QPalette.ButtonText, palette.color(QPalette.WindowText))
            palette.setColor(QPalette.Link, palette.color(QPalette.Highlight).lighter())
            palette.setColor(QPalette.LinkVisited, palette.color(QPalette.Highlight))
            palette.setColor(QPalette.Disabled, QPalette.Text, Qt.darkGray)
            palette.setColor(QPalette.Disabled, QPalette.ButtonText, Qt.darkGray)
            palette.setColor(QPalette.Midlight, QColor(66, 66, 66))
            palette.setColor(QPalette.Mid, QColor(32, 66, 85))
            QApplication.setPalette(palette)
        else:
            print('未知主题样式')
 
    
if __name__ == '__main__':
    app = QApplication(sys.argv)
    windows = WindowStyleDemo()
    windows.show()
    sys.exit(app.exec())  

运行效果如下图所示:

实战PyQt5: 106-定制应用显示风格

自定义风格演示

本文知识点

  • 使用QApplication的setStyle()和setPalette()函数来定制应用的显示风格;
  • 使用QActionGroup将菜单项分组;
  • 使用lambda函数来连接槽函数。

前一篇: 实战PyQt5: 105-设置应用的显示风格

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值