QSS是C++ Qt中的界面美化神器,其语法和CSS区别不大,但是QSS有一个独有的功能——subcontrol,这是CSS所没有的,一个widget往往由多个子部件构成,利用subcontrol可以对窗口部件的某些子部件做精细处理,从而使得界面美化达到定制最大化。

以下内容来源于http://qtdebug.com/QSS-Subcontrol.html

http://qtdebug.com/index.html上有很多不错的教程

Subcontrol 的绘制位置由 subcontrol-origin、subcontrol-position, top, left 来指定,就先从这几个属性开始入手。

Subcontrol-Origin

subcontrol-origin 定义在 parent widget 中绘制 subcontrol 的参考矩形,默认在 padding 的矩形中绘制。

The origin rectangle of the subcontrol within the parent element. If this property is not specified, the default is padding.

subcontrol-origin 有 4 个值可选:
  • margin
  • border
  • padding
  • content

下图展示了 subcontrol-origin 的值不同时,在 parent widget 的不同位置进行绘制 subcontrol:

Subcontrol-Position

已经知道 subcontrol 要在 parent widget 的某个矩形区域里绘制,如 padding rectangle,这个矩形这么大,具体要在这个矩形的哪个位置绘制呢?使用 subcontrol-position 来指定,不同的 subcontrol 的 subcontrol-position 默认值不同,例如 QSlider 的 handle 的默认值是 center center,QSpinBox 的 up-button 的默认值是 right top。

The alignment of the subcontrol within the origin rectangle specified by subcontrol-origin. If this property is not specified, it defaults to a value that depends on the subcontrol.

subcontrol-position 水平方向有 3 个值可选:
  • left
  • center
  • right
subcontrol-position 垂直方向有 3 个值可选:
  • top
  • center
  • bottom

用 Top 和 Left 微调 Subcontrol 的位置

Top 和 left 的主要作用是 :hover,:pressed 等发生时,用 top 和 left 偏移一点 subcontrol,这样就看到 subcontrol 的鼠标动作了,偏移是相对于 subcontrol-orign 和 subcontrol-position 确定的位置,top 和 left 的默认值是 0。

用下面的 QSS 总结一下 subcontrol-origin, subcontrol-position, top, left:
  • QSpinBox 的 up-button 放置在 QSpinBox 的左边垂直剧中
  • 当鼠标放到 up-button 上时,将其向右下角偏移 1px
  • 当鼠标离开 up-button 后,up-button 移回到原来的位置
QSpinBox::up-button {
subcontrol-origin: margin;
subcontrol-position: left center;
} QSpinBox::up-button:hover {
top: 1px;
left: 1px;
}

接下来就具体的介绍每一个 Widget 有哪些 subcontrol,怎么 QSS 它们。

QCheckBox

QCheckBox 的 subcontrol 有 ::indicator,比较有意思的是,text 总是显示在 indicator 右边,所以如果 indicator 靠右边显示的话,text 很可能就看不到了。

QRadioButton 的 QSS 和 QCheckBox 的一样,所以就不在重复介绍。

下面 QSS 的效果如图:

QCheckBox {
color: lightgray;
background: rgb(44, 44, 44);
border: 10px solid rgb(76, 76, 76);
spacing: 10px; /* indicator 和 text 的间隔 */
padding: 10px;
} QCheckBox::indicator {
subcontrol-origin: border;
subcontrol-position: left center;
background: white;
border: 2px solid rgb(170, 170, 170);
} QCheckBox::indicator:checked {
background: rgb(76, 76, 76);
}

修改 subcontrol-origin 和 subcontrol-position 为不同的值看看效果是什么。

QComboBox

QComboBox 的 subcontrol 有 drop-down

下面 QSS 的效果如图:

QComboBox {
color: lightgray;
background: rgb(44, 44, 44);
border: 10px solid rgb(76, 76, 76);
spacing: 10px; /* indicator 和 text 的间隔 */
padding: 10px;
} QComboBox::drop-down {
width: 15px;
height: 10px;
subcontrol-origin: border;
subcontrol-position: right center;
background: white;
border: 2px solid rgb(170, 170, 170);
border-radius: 3px;
} QComboBox::drop-down:hover {
background: rgb(76, 76, 76);
} QComboBox::drop-down:on {
background: black;
top: 1px;
left: 1px;
}

QSpinBox, QDateEdit, QTimeEdit, QDateTimeEdit

QSpinBox 的 subcontrol 有 ::up-button::down-button::up-arrow::down-arrow

  • up-button 显示在 QSpinBox 里,它的 subcontrol-origin 是相对于 QComboBox 的
  • down-button 显示在 QSpinBox 里,它的 subcontrol-origin 是相对于 QComboBox 的
  • up-arrow 显示在 up-button 里,它的 subcontrol-origin 是相对于 up-button 的
  • down-arrwo 显示在 down-button 里,它的 subcontrol-origin 是相对于 down-button 的

QDateEdit, QTimeEdit, QDateTimeEdit 的 subcontrol 和 QSpinBox 是一样的,只需要把下面 QSS 里的 QSpinBox 换成 QDateEdit,QTimeEdit 或 QDateTimeEdit 即可。

下面 QSS 的效果如图,down-button 靠左垂直居中,up-button 靠右垂直居中:

QSpinBox {
color: lightgray;
background: rgb(44, 44, 44);
border: 10px solid rgb(76, 76, 76);
padding: 5px;
} QSpinBox::down-button, QSpinBox::up-button {
subcontrol-origin: border;
width: 16px;
height: 10px;
background: white;
border: 2px solid rgb(170, 170, 170);
} QSpinBox::down-button {
subcontrol-position: center left;
} QSpinBox::up-button {
subcontrol-position: center right;
} QSpinBox::up-arrow, QSpinBox::down-arrow {
subcontrol-origin: content;
subcontrol-position: center center;
width: 6px;
height: 6px;
background: rgb(76, 76, 76);
}

QSlider

QSlider 的 subcontrol 有 ::groove(槽),::handle::add-page 和 ::sub-page

  • groove 显示在 QSlider 里,它的 subcontrol-origin 是相对于 QSlider 的
  • handle 显示在 groove 里,它的 subcontrol-origin 是相对于 groove 的
  • sub-page 显示在 groove 里,它的 subcontrol-origin 是相对于 groove 的
  • add-page 显示在 groove 里,它的 subcontrol-origin 是相对于 groove 的
  • handle, sub-page, add-page 虽然都显示在 groove 里,但是都可以把它们扩展到 groove 外

下面 QSS 的效果如图:

QSlider {
background: rgb(170, 170, 170);
padding: 2px;
height: 40px;
} QSlider::groove:horizontal {
subcontrol-origin: content;
background: rgb(76, 76, 76); /* the groove expands to the size of the slider by default.
by giving it a height, it has a fixed size */
height: 20px;
} QSlider::handle:horizontal {
background-color: rgb(50, 50, 50);
width: 40px;
border-radius: 20px; /* handle is placed by default on the contents rect of the groove.
Expand outside the groove */
margin: -10px 0;
} QSlider::sub-page:horizontal {
background: #999;
margin: 5px;
border-radius: 5px;
} QSlider::add-page:horizontal {
background: #666;
margin: 5px;
border-radius: 5px;
}

Groove 的默认高度和 QSlider content rectangle 的高度一样,给它一个高度值就可以让他有固定的高度了,把 groove 的 height 去掉试试。

Handle 的默认高度和 groove content rectangle 的高度一样,为了让起显示超出 groove,需要设置 margin 为负值,如果这个负值太小,显示超出 QSlider 的部分将看不到。Handle 的 subcontrol-position 没有作用,因为 handle 不是固定在一个地方的,而是根据 QSlider 的值动态计算显示的位置。

QProgressBar

QProgressBar 的 subcontrol 有 ::chunk

对于 QProgressBar 的 QSS,大多数都是想把 chunk 定义为圆角矩形的样子,但是当它的 value 比较小时,chunk 的圆角会变成直角,即使使用图片都不行,效果很不理想,所以如果要修改 QProgressBar 的外观的话,推荐继承 QProgressBar 自己绘制或者使用 QStyle。

QGroupBox

QGroupBox 的 subcontrol 有 ::title 和 ::indicator

  • title 相对于 QGroupBox
  • indicator 的 subcontrol-origin 和 subcontrol-position 自定义无效

下面 QSS 的效果如图:

QGroupBox {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #E0E0E0, stop: 1 #EEEEEE);
border: 2px solid gray;
border-radius: 5px;
margin-top: 10px; /* leave space at the top for the title */
} QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center; /* position at the top center */
padding: 2px 3px;
color: white;
margin-top: 2px;
background-color: gray;
border-radius: 3px;
spacing: 5px;
} QGroupBox::indicator {
width: 13px;
height: 13px;
border: 1px solid black;
background: white;
} QGroupBox::indicator:checked {
background: yellow;
}

QTableView

QTableView 相关的 subcontrol 有 QTableView 的 ::item,QHeaderView 的 ::section 和 左上角的 QTableCornerButton 的 ::section

QTableView 的 QSS 对于 QTableWidget 也是生效的。

下面 QSS 的效果如图:

  1.  
    QTableView, QHeaderView, QTableView::item {
  2.  
    background: white;
  3.  
    }
  4.  
     
  5.  
    QTableView::item:alternate {
  6.  
    background: rgb(209, 231, 254);
  7.  
    }
  8.  
     
  9.  
    QTableView::item:selected { /*被选中的index*/
  10.  
    color: black;
  11.  
    background: qlineargradient(
  12.  
    x1: 0, y1: 0, x2: 0, y2: 1,
  13.  
    stop: 0 #FAFBFE,
  14.  
    stop: 1 #DCDEF1);
  15.  
    }
  16.  
     
  17.  
    QHeaderView::section:horizontal, QTableCornerButton::section {
  18.  
    background-color: qlineargradient(spread:reflect,
  19.  
    x1:0, y1:0, x2:0, y2:1,
  20.  
    stop:0 rgba(255, 255, 255, 255),
  21.  
    stop:1 rgba(164, 164, 164, 255));
  22.  
    border: 1px solid rgb(153, 153, 153);
  23.  
    border-width: 0 1px 1px 0;
  24.  
    }
  25.  
     
  26.  
    QHeaderView::section:vertical {
  27.  
    background: #DDD;
  28.  
    border: 1px solid rgb(153, 153, 153);
  29.  
    border-width: 0 1px 1px 0;
  30.  
    }

QTreeView

QTreeView 相关的 subcontrol 有 QHeaderView::section(和上面 QTableView 的 header view 的 QSS 一样,其实就是一个东西),QTreeView::item 和 QTreeView::branch

QTreeView 的 QSS 对于 QTreeWidget 也是生效的。

QTreeView 的 subcontrol 并不多,但是 branch 有很多种不同的状态,关键就是理解这些状态,不同状态时使用不同的背景,下面 QSS 的效果如图:

QHeaderView::section:horizontal {
background-color: qlineargradient(spread:reflect,
x1:0, y1:0, x2:0, y2:1,
stop:0 rgba(255, 255, 255, 255),
stop:1 rgba(164, 164, 164, 255));
border: 1px solid rgb(153, 153, 153);
border-width: 0 1px 1px 0;
} QTreeView::item {
border-bottom: 1px solid lightgray;
selection-color: black;
} QTreeView::item:selected { /*被选中的index*/
background: qlineargradient(
x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #FAFBFE,
stop: 1 #DCDEF1);
} QTreeView::branch {
background: yellow;
} QTreeView::branch:has-siblings:!adjoins-item {
background: cyan;
} QTreeView::branch:has-siblings:adjoins-item {
background: red;
} QTreeView::branch:!has-children:!has-siblings:adjoins-item {
background: blue;
} QTreeView::branch:closed:has-children:has-siblings {
background: black;
} QTreeView::branch:has-children:!has-siblings:closed {
background: gray;
} QTreeView::branch:open:has-children:has-siblings {
background: magenta;
} QTreeView::branch:open:has-children:!has-siblings {
background: green;
}

上面的 QSS 是不实用的,直接这么用到项目里,肯定被咔嚓,但是把各种状态的 branch 标记为不同的颜色,这样在做设计的时候就能很容易的分辨出各种 branch,然后根据需求设计出不同的图片放到对应的 branch。其实 Qt 的帮助文档里对 QTreeView 的 QSS 已经有一个很完善的例子,在 QtCreator 的帮助里搜索 style sheets examples,定位到 Customizing QTreeView 就可以看到这个例子了,开发的时候,照葫芦画瓢的做就可以了:

QTabWidget

QTabWidget 相关的 subcontrol 有:
  • QTabWidget::pane
  • QTabWidget::tab-bar
  • QTabBar::tab
  • QTabBar::close-button
  • QTabBar::tear
  • QTabBar::scroller
  • QTabBar QToolButton::left-arrow
  • QTabBar QToolButton::right-arrow

不幸的是,在我看来,QTabWidget 还有一些 bug,例如:
  • QTabBar::close-button 只能定位在 tab 的左边或者右边,不能调整和文本之间的间隔
  • Tab 互相遮盖的情况下,如我们的例子的样式,拖动 tab 时某些 tab 会被截断
  • QTabBar::scroller 的定位也是个问题,不能自由定位到需要的位置
  • QTabBar 和 QTabWidget 不一样宽


上图是 SublimeText 的截图,很多应用中的 tab widget 也差不多是上面这个样,至少这几个 bug 决定了 QTabWidget 使用 QSS 我还做不到这么好,其实用性大受限制,所以就不对 QTabWidget 做太多介绍,只给出一个小例子,展示一下简单的定制 QTabWidget,满足一般的需求,复杂的需要我们自己实现一个 tab widget。

下面 QSS 的效果如图:

QTabWidget::pane { /* The tab widget frame */
border: 2px solid rgb(69, 69, 69);
margin-top: -2px;
} QTabWidget::tab-bar {
left: 5px; /* move to the right by 5px */
} QTabBar::tab {
color: gray;
min-width: 40px;
height: 28px;
border-width: 0 18px 0 18px;
border-image: url(:/resources/tab-inactive.png) 0 18 0 18 stretch stretch;
} QTabBar::tab:selected {
color: #DDD;
height: 28px;
border-width: 0 18px 0 18px;
border-image: url(:/resources/tab-active.png) 0 18 0 18 stretch stretch;
} QTabBar::tab:!first {
margin-left: -20px;
} QTabBar::tab:hover {
color: #DDD;
}
tab-active.png tab-inactive.png

QScrollBar

QScrollBar 相关的 subcontrol 挺多的,仔细观察的话,有点像 QSpinBox 和 QSlider 的合体:

  • ::sub-line, ::add-line
  • ::sub-page, ::add-page
  • ::up-arrow, ::down-arrow
  • ::left-arrow, ::right-arrow

很多时候并不是每一个 subcontrol 都需要处理的,例如下面的 QSS 中,arrow 没有处理,直接绘制在 ::sub-line 和 ::add-line 的背景里,也没有处理 ::sub-page 和 ::add-page,效果如图:

QScrollBar:horizontal {
height: 16px;
border-width: 0px 10px 0px 10px;
border-image: url(:/resources/horizontal-track.png) 0 10 0 10 repeat stretch;
margin-left: 6px;
margin-right: 16px;
padding-right: 4px;
} QScrollBar::handle:horizontal {
min-width: 40px;
border-width: 0 17px 0 17px;
border-image: url(:/resources/horizontal-handle.png) 0 17 0 17 repeat repeat;
} QScrollBar::sub-line:horizontal {
width: 20px;
height: 17px;
subcontrol-position: left;
subcontrol-origin: margin;
background-image: url(:/resources/horizontal-sub-line.png)
} QScrollBar::add-line:horizontal {
width: 20px;
height: 17px;
subcontrol-position: right;
subcontrol-origin: border;
background-image: url(:/resources/horizontal-add-line.png)
} QScrollBar:vertical {
width: 16px;
border-width: 10px 0px 10px 0px;
border-image: url(:/resources/vertical-track.png) 10 0 10 0 repeat repeat;
margin-top: 6px;
margin-bottom: 16px;
padding-bottom: 6px;
} QScrollBar::handle:vertical {
min-height: 40px;
border-width: 17px 0px 17px 0px;
border-image: url(:/resources/vertical-handle.png) 17 0 17 0 repeat repeat;
} QScrollBar::sub-line:vertical {
width: 17px;
height: 22px;
subcontrol-position: top left;
subcontrol-origin: margin;
background-image: url(:/resources/vertical-sub-line.png)
} QScrollBar::add-line:vertical {
width: 17px;
height: 22px;
subcontrol-position: bottom;
subcontrol-origin: border;
background-image: url(:/resources/vertical-add-line.png)
}

QTableView 的 QSS 这里没有给出,请参考上面 QTableView 的 subcontrol 的内容。

QScrollBar 使用的背景图:
       


有 subcontrol 的常用 widget 基本上介绍完了,相关的 QSS 还有更多的细节都可以在 Qt 的帮助文档里找到。

https://blog.csdn.net/hechao3225/article/details/53914390

QSS独门秘籍:subcontrol的更多相关文章

  1. 小齐读者拿到快手、百度、网易等 offer 的独门秘籍!

    小齐说: 这篇文章来自读者冰红茶,他刚结束了秋招,拿了很多家 offer. 和他聊完之后,我觉得他的备考思路也完全适用于美国的面试,只是分值要调整一下,但是具体每一块的内容,地球村通用.所以分享给大家 ...

  2. c# winform编程之多线程ui界面资源修改总结篇

    单线程的winfom程序中,设置一个控件的值是很easy的事情,直接 this.TextBox1.value = "Hello World!";就搞定了,但是如果在一个新线程中这么 ...

  3. WinForm/Silverlight多线程编程中如何更新UI控件的值

    单线程的winfom程序中,设置一个控件的值是很easy的事情,直接 this.TextBox1.value = "Hello World!";就搞定了,但是如果在一个新线程中这么 ...

  4. 【转】OpenStack和Docker、ServerLess能不能决定云计算胜负吗?

    还记得在十多年前,SaaS鼻祖SalesForce喊出的口号『No Software』吗?SalesForce在这个口号声中开创了SaaS行业,并成为当今市值460亿美元的SaaS之王.今天谈谈『No ...

  5. 对于spark以及hadoop的几个疑问(转)

    Hadoop是啥?spark是啥? spark能完全取代Hadoop吗? Hadoop和Spark属于哪种计算计算模型(实时计算.离线计算)? 学习Hadoop和spark,哪门语言好? 哪里能找到比 ...

  6. [Spring入门学习笔记][Spring的AOP原理]

    AOP是什么? 面向切面编程 软件工程有一个基本原则叫做“关注点分离”(Concern Separation),通俗的理解就是不同的问题交给不同的部分去解决,每部分专注于解决自己的问题.这年头互联网也 ...

  7. 正本清源区块链——Caoz

    正本清源区块链 说明:以下内容整理自Caoz的<正本清源区块链>,如有不妥,请联系我修改或删除. 简介 不讨论炒币!不讨论炒币!不讨论炒币! 本课程内容分为两部分: 第一部分,烧脑篇,介绍 ...

  8. 《15个提高Google搜索的技巧》

    为了得到更加「多元化」的搜索结果,虽然 Google 目前访问起来并不是那么方便,但是仍然有很多人把它作为常用搜索引擎在使用. 其实除了最简单的关键词搜索之外,搜索引擎还提供了很多精细化的搜索功能,如 ...

  9. Java程序算法设计视频分享,需要的来

    每年都会有人说,IT行业饱和了,根本就找不到工作,其实,我想说的是,不是工作难找,而是你自己不够好! 前几天看到一CEO在微博上吐槽: 前几天招一算法工程师我们给了8万月薪*14+奖金,人家去阿里拿5 ...

随机推荐

  1. Mac NVM 配置

    1.NVM 简介 NVM(node version manager)是一个可以让你在同一台机器上安装和切换不同版本 node 的工具. GitHub 地址 2.NVM 环境配置 2.1 安装 NVM ...

  2. mysql 动态增加列,查找表中有多少列,具体什么列。 通过JSON生成mysql表 支持子JSON

    好消息, 程序员专用早餐机.和掌柜说 ideaam,可以节省20元. 点击链接  或復·制这段描述¥k3MbbVKccMU¥后到淘♂寳♀ 或者 淘宝扫码 支持下同行哈 ---------------- ...

  3. .NET Core +NuGet 创建打包发布自己的类库包

    1. 创建类库项目 你可以使用现有的 .NET 类库项目用于要打包的代码,或者创建一个简单的项目,.NET CORE 2.1 项目的 类库如下所示: NugetDemo.class using Sys ...

  4. TensorFlow与caffe中卷积层feature map大小计算

    刚刚接触Tensorflow,由于是做图像处理,因此接触比较多的还是卷及神经网络,其中会涉及到在经过卷积层或者pooling层之后,图像Feature map的大小计算,之前一直以为是与caffe相同 ...

  5. (转)java术语(PO/POJO/VO/BO/DAO/DTO)

    转自:http://blog.csdn.net/gaoyunpeng/article/details/2093211 PO(persistant object) 持久对象在o/r 映射的时候出现的概念 ...

  6. 禅道项目管理系统整合Selenium IDE的思路

    前两天说用过Selenium IDE产生了一些想法,这里做一些整理. 传统的测试人员管理测试用例,基本都是用Excel.这没什么不好的,也没什么好的.如果通过管理系统来管理用例,相对来说,少了一些简便 ...

  7. caffe网络结构可视化在线工具

    http://ethereon.github.io/netscope/#/editor shift+enter

  8. nginx学习与使用

    安装与运行 (从源码安装,这里OS为Ubuntu,参考资料:https://nginx.org/en/docs/configure.html) 1.下载并解压:https://nginx.org/en ...

  9. c++中为什么可以通过指针或引用实现多态,而不可以通过对象呢?

    引言:  在c++中司空见惯的事情就是:可以通过指针和引用可以实现多态,而对象不可以.  那为什么?让我们来解开这神秘的暗纱! 1. 类对象的存储方式: 在一个类的实例中,只会存放非静态的成员变量. ...

  10. error connecting: Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置

    [参考]Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置 [参考][数据库-MySql] MySqlConnection error connec ...