【Qt样式(qss)-2】使用小结(软件换肤,比如暗黑模式)

1.背景:

【Qt样式(qss)-1】手册小结

【Qt样式(qss)-2】使用小结(软件换肤,比如暗黑模式) 

【Qt样式(qss)-3】几套配色方案

【Qt样式(qss)-4】应用到QMdiArea不生效的解决

【Qt样式(qss)-5】qss混乱,错乱,不生效的一种原因

其中主要是记录如何获取手册细节。

现在很多软件都有换肤功能,比如暗黑模式。有了qss就简单太多了。学过前端的朋友一看就会。跟css大同小异。

2.使用:

Style Sheet最主要就是生效范围问题,按照面向对象编程的思维,可以认为它像继承。按照平面设计的思维,可以认为跟画画一样,先画轮廓,再勾细节。

在一个项目中,qss可以统一定义一份,在主窗体加载构造的时候,执行setStyleSheet一下,在这个窗体内部就会全局生效,实现快速换肤。

具体用法手册和网络中有太多,不用赘述。就拿最近我写的qss为例记录一下。

/************************************************************************
** Class name:     style_dark_green
** Author:         (Henrick.nie)
** Created date:   2022-12-30
** Used for:       ui
************************************************************************/

/*background,font*/
*,QTabBar::tab,QTableView::item,QTableCornerButton::section,QHeaderView::section {
    background-color: rgb(0, 30, 0);
    color: rgb(0, 255, 0);
}

/*disabled*/
*:disabled {
    color: rgb(200, 200, 200);
}

/*selected*/
QTabBar::tab:selected,QTableView::item:selected {
    background-color: rgb(0, 80, 0);
}

/*hover*/
QComboBox,QDateTimeEdit:hover,QTabBar::tab:hover,
QToolButton:hover,QMenuBar::item:selected,QMenu::item:selected,
QTableView::item:hover,QPushButton:hover,QLineEdit:hover {
    background-color: rgb(0, 150, 0);
}

/*border*/
*,QTabWidget::pane {
    border: none;
    border-radius: 6px;
}
QComboBox,QDateTimeEdit,QGroupBox,
QLineEdit,QTextEdit,QListView,QTextBrowser,
QTableView,QTableView::item,QTableCornerButton::section,QHeaderView::section {
    border: 1px solid green;
}
QTableView,QTableView::item,QTableCornerButton::section,QHeaderView::section {
    border-radius: 0px;
}

/*button-color*/
QPushButton,QPushButton:pressed,QScrollBar::handle {
    background-color: rgb(0, 100, 0);
}

/*QScrollBar*/
QScrollBar::add-page,QScrollBar::sub-page {
    background-color: rgb(50, 50, 50);
}

/*QToolTip*/
QToolTip {
    background-color: rgb(250, 255, 230);
    color: black;
}

/*QGroupBox*/
QGroupBox {
    padding-top: 12px;
}

/*QPushButton*/
QPushButton {
    min-width: 80px;
    min-height: 25px;
}

/*QMessageBox*/
QMessageBox QPushButton {
    min-width: 100px;
    max-width: 100px;
    min-height: 30px;
    max-height: 30px;
}

/*title 1: top and left*/
QToolButton, UiBase_view > QTabWidget > QTabBar {
    font-size: 15px;
}
QToolBar, QToolButton, UiBase_view > QTabWidget > QTabBar::tab {
    background-color: rgb(0, 50, 0);
}

上面的qss,我先定义了最常用的几个特征:背景、字体、disable、选中、鼠标停留、边框,然后定义了针对每一类控件特殊的特征。

先定义常用特征,就好像定义基类,或者画一下轮廓。

后针对控件描述特征,就好像写子类,或者勾画细节。

其实也可以使用“#”号针对具体的控件对象来定义,就好像类的实例化,或者作画的具体细节。

我用的是上面的写法,如果需要改样式某个特征,只改一个地方就行了。

上面的qss还可以像下面这样按控件分类写。效果是一样的。所谓横着写和竖着写,各有利弊,看习惯哪种:

/*background*/
* {
    background-color: rgb(30, 30, 30);
    color: rgb(0, 255, 0);
}

/*disabled*/
*:disabled {
    color: rgb(200, 200, 200);
}

/*QLabel*/
QLabel {
    border: none;
}

/*QLineEdit*/
QLineEdit {
    border: 1px solid green;
    border-radius: 6px;
}

QLineEdit:hover {
    background-color: rgb(0, 150, 0);
}

/*QTextEdit,QTextBrowser,QListView*/
QTextEdit,QTextBrowser,QListView {
    border: 1px solid green;
    border-radius: 6px;
}

/*QMenuBar,QMenu*/
QMenuBar::item {
    border: none;
}

QMenuBar::item:selected,QMenu::item:selected {
    background-color: rgb(0, 150, 0);
}

/*QDateTimeEdit*/
QDateTimeEdit {
    border: 1px solid green;
    border-radius: 6px;
}

QDateTimeEdit:hover {
    background-color: rgb(0, 150, 0);
}

/*QComboBox*/
QComboBox {
    background-color: rgb(0, 150, 0);
    border: 1px solid green;
    border-radius: 6px;
}

/*QTabWidget*/
QTabWidget:pane {
    border: none;
}

QTabBar::tab {
    background-color: rgb(30, 30, 30);
}

QTabBar::tab:selected {
    background-color: rgb(0, 80, 0);
}

QTabBar::tab:hover {
    background-color: rgb(0, 150, 0);
}

/*QPushButton*/
QPushButton {
    background-color: rgb(0, 100, 0);
}

QPushButton:hover {
    background-color: rgb(0, 150, 0);
}

QPushButton:pressed {
    background-color: rgb(0, 100, 0);
}

/*QScrollBar*/
QScrollBar::handle {
    background-color: rgb(0, 100, 0);
}

QScrollBar::add-page,QScrollBar::sub-page {
    background-color: rgb(50, 50, 50);
}

/*QToolTip*/
QToolTip {
    color: black;
}

/*QGroupBox*/
QGroupBox {
    padding-top: 12px;
    border: 1px solid green;
    border-radius: 6px;
}

/*QTableView*/
QTableCornerButton::section,QHeaderView::section {
    background-color: rgb(30, 30, 30);
    border: 1px solid green;
}

QTableView {
    border: 1px solid green;
    border-radius: 6px;
}

QTableView::item {
    background-color: rgb(30, 30, 30);
    border: 1px solid green;
}

QTableView::item:selected {
    background-color: rgb(0, 80, 0);
}

QTableView::item:hover {
    background-color: rgb(0, 150, 0);
}

3.问题:

在使用过程中遇到了几个典型问题,这里需要记录一下。

3.1.按钮QPushButton:

上面qss中已经解决了这个问题,这里阐述一下。控件一般都继承QWidget类,所以一旦定义了QWidget样式,就会间接影响到按钮。按钮最讨厌就是边框问题,一旦定义了border相关属性,只要是没有拉伸的地方,按钮就会变成自适应文本大小。一般界面中可以人为控制还好,就怕QMessageBox这类,一旦变成自适应,就成了这样:

6644f1eeb64e4debaf0679e3ae83dffa.png

像右下角那俩按钮的德行,什么玩意?

而我的原则,不要试图样式和界面中的各种属性结合控制,很不好,应该尽量把界面做的“通用”,让它随时可以通过定义qss来改变显示风格。

所以之前我都是尽量规避对按钮边框样式的定义,取而代之的,是利用颜色的变化来做显示效果。 所以正常情况下,我希望按钮是这样的:

e9e3f4463aa545ad9449a881c6650f63.png

这个问题其实也能解决。上一篇博客写了手册如何使用,先看手册的语法最后部分:

注意看最后三项,qss允许把选择器定位到:

定位到具体控件实例,需要给定具体的控件名字(objectName),使用#号。——点兵点将。

定位到某个类的直接和间接子孙类,需要给定祖宗类的名字,使用空格。——株连九族。

定位到某个类的直接子类,需要给定父类的名字,只用>号。——亲生子女。

我觉得形容的够贴切了。

所以,像MessageBox中按钮的情况,完全可以这样:

/*QMessageBox*/
QMessageBox QPushButton {
    min-width: 100px;
    max-width: 100px;
    min-height: 30px;
    max-height: 30px;
}

即使是前面定义了border有关的样式,无论何种原因让QMessageBox中的按钮受影响了,那就指定QMessageBox的九族子孙中的QPushButton类,锁定其大小即可。这里要注意,如果前面定义了边框的圆角,那么控件的大小不能太小,否则就不生效。就好像一个边长只有5px的正方形,我让它边角半径大于2.5px这就没法生效,因为不合理。

如此,让它即继承了前面定义的样式,又保持了自己单独的特征。

效果如期而至:

还可以活学活用,指定株连的辈分。比如这样:

UiBase_view > QTabWidget > QTabBar::tab {
    background-color: rgb(0, 50, 0);
}

像这样就可以从UiBase_view类开始,逐一向下寻找子孙类并定义样式。比如在设计界面时,可以根据规律顺藤摸瓜,从而指定某个界面层级,并为其定义样式。

当然逐个去写是一样的,只是代码量大。我喜欢按照层级规律写。

qss语法的最后,还展示了如何用选择器针对命名空间操作,以及用qss控制控件的属性,真是强大。这里只是提及一下,不再赘述。

3.2.QTabWidget

这东西让不少人头疼,主要是边框问题。

比如右边和下边这个大白边,网上说需要设置界面中的属性documentModel=true,是可以直接实现,但会造成在最上面多一个小白边。所以放弃!

在我的努力下,通过qss实现:

QTabWidget:pane{border: none;}

 这样就可以了,直接去掉了它所有的边框,其它看着玩就行了。

比如做个颜色试试:

QTabWidget:pane{border: 1px solid blue;}

010bfbe110114d77be700dffa9521d89.png

如果要定义页签部分,则需要这样:

QTabBar::tab{background-color:rgb(30, 30, 30);color:rgb(0, 255, 0);}
QTabBar::tab:selected{background-color:rgb(0, 80, 0);}
QTabBar::tab:hover{background-color:rgb(0, 150, 0);}

 8ad54edd929e4f22a4ceaa95fa50e22d.png

这里我没有使用更高级的用法。其实上面的页签可以定义为圆边,也可以改变位置到左边、右边、下边。还可以用画笔画成其它形状的。

 3.2.3.表格QTableWidget/QTableView

因为QTableWidget继承于QTableView,所以只需要定义QTableView就行了。也就是说,定义了父类,子类也会继承过来样式并生效的。QListWidget&QListView也是一样道理。

 比如上面用到的有关表格的部分:

/*QTableView*/
QTableView{background-color:rgb(30, 30, 30);color:rgb(0, 255, 0);}
QTableCornerButton::section,QHeaderView::section,QTableView::item{background-color:rgb(30, 30, 30);border: 1px solid green;}
QTableView{border-radius: 6px;}
QTableView,QTableView::item{border: 1px solid green;}
QTableView::item:selected{background-color:rgb(0, 80, 0);}
QTableView::item:hover{background-color:rgb(0, 150, 0);}

/*QScrollBar*/
QScrollBar::handle{background-color:rgb(0, 100, 0);}
QScrollBar::add-page,QScrollBar::sub-page{background-color:rgb(50, 50, 50);}

2fd3537cf7e343b49de888a016f841cf.png

 就实现了上图的效果。

3.2.4.菜单和工具栏QMenuBar/QMenu/QToolButton

QMainWindow上面的菜单实际上是两部分组成的,最上面那一条叫菜单栏QMenuBar,每一个主菜单项是它的item,比如:文件、编辑、帮助等,也就是一级菜单。

按一下一级菜单弹出来的才叫菜单QMenu,而其中每一个项也是它的item,比如文件-退出,编辑-剪切,帮助-关于等。

所以要定义一级菜单需要使用QMenuBar::item,定义子菜单项需要使用QMenu::item。比如我需要让鼠标停留的菜单项高亮,就这样写:

QMenuBar::item:selected,QMenu::item:selected{background-color:rgb(0, 150, 0);}

b0f25712c18c473e9ea6ae4f21e69a1f.png

 3.2.5.与QStyle或QPaint生效优先级

按照前端css的说法,样式优先级比属性高。但是qt当中如果使用了画笔绘制,qss是无法生效的,这是我实验的结果。

我认为,qt有点像c#的wpf,说白了特别像html这些前端脚本技术,默认它是透明的,都是用样式在描述它的特征,如果后期自定义了样式,就以后定义的为准。就好像一个变量,先赋值为1,再赋值为2,显然它等于2。

但是画笔是另外一套体系,直接从本质上赋予它颜色,那就不是样式能解决的了。

也许是我还没找到跟权威的说法。

4.小结

先总结这么多,目前为止,我已经用qss实现了换肤机制。

我感觉qtcreator的界面很可能本身就是这么做出来的,只要能掌握方法,ui可玩性很高。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值