• QSS独门秘籍:subcontrol


    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 {
         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;
         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;
         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);
         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 {
         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- 0 1px 1px 0;
    24.  
      }
    25.  
       
    26.  
      QHeaderView::section:vertical {
    27.  
      background: #DDD;
    28.  
      border: 1px solid rgb(153, 153, 153);
    29.  
      border- 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- 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- 40px;
        height: 28px;
        border- 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- 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.pngtab-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- 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- 40px;
        border- 0 17px 0 17px;
        border-image: url(:/resources/horizontal-handle.png) 0 17 0 17 repeat repeat;
    }
    
    QScrollBar::sub-line:horizontal {
         20px;
        height: 17px;
        subcontrol-position: left;
        subcontrol-origin: margin;
        background-image: url(:/resources/horizontal-sub-line.png)
    }
    
    QScrollBar::add-line:horizontal {
         20px;
        height: 17px;
        subcontrol-position: right;
        subcontrol-origin: border;
        background-image: url(:/resources/horizontal-add-line.png)
    }
    
    QScrollBar:vertical {
         16px;
        border- 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- 17px 0px 17px 0px;
        border-image: url(:/resources/vertical-handle.png) 17 0 17 0 repeat repeat;
    }
    
    QScrollBar::sub-line:vertical {
         17px;
        height: 22px;
        subcontrol-position: top left;
        subcontrol-origin: margin;
        background-image: url(:/resources/vertical-sub-line.png)
    }
    
    QScrollBar::add-line:vertical {
         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

  • 相关阅读:
    CentOS 7 下Django项目部署(基于uwsgi和Nginx)
    群晖 利用docker和同步远程修改服务配置
    Fody 很方便,也有不方便的时候
    HTTP请求中Get、Post与后台参数接收的分析
    微信小程序跨页面跨组件通讯eventbus
    import、require、export、module.exports 混合使用详解
    JavaScript中Object对象方法总结
    关于存储过程调用视图的效率问题
    思想的痕迹
    Gmail、Orkut和Wallop的不限量,不限时邀请
  • 原文地址:https://www.cnblogs.com/findumars/p/10721207.html
Copyright © 2020-2023  润新知