导读

正如web前端开发中CSS(Cascade Style Sheet)的作用一样,Qt开发中也可以使用修改版的QSS将逻辑业务和用户界面进行隔离。这样,美工设计人员和逻辑实现者可以各司其职而不受干扰。更重要的是,由于界面和逻辑处理是分离的,低耦合性使得代码重构的工作量可以减少到最小。QSSCSS的语法几乎一致,除了Qt自身增加的一些属性之外,其余的属性都可以在CSS2或CSS3中找到对应的属性。因此,如果曾经有过CSS的使用经验,那么QSS的使用将游刃有余。关于QSS的使用实践,打算撰写一系列博客来记录使用过程中的一些技巧和方法。本篇是系列第一篇,主要探讨QPushButtonQMenu在QSS的作用下的效果。

QSS介绍

QSS(QStyle Sheet)借鉴于CSS的良好思想,实现了界面和逻辑的分离。QSS中引入了盒模型(Box Model)概念,这是样式表技术中的核心概念之一。具体的解释网上说的挺多的,Qt本身自带的文档也有较为详细的说明。在使用盒模型进行设计之前,我们得了解下Qt中哪些组件可以用盒模型进行布局设计:

Qt中可以应用盒模型的组件类
QCheckBox QCheckBox的勾选符号可以使用::indicator子组件来定制。默认情况下,勾选标记位于组件矩形的左上角。QCheckBox的spacing属性可以用于指定勾选标记和文本内容之间的间距。
QComboBox 对于QComboBox而言,支持盒模型的其实是包裹QComboBox的外框(Frame),QComboBox的下拉单按钮通过::drop-down子组件来定制,默认情况下下拉单按钮位于盒模型中padding矩形的右上角。下拉按钮中的箭头号通过::down-arrow子组件进行定制,箭头号默认位于子组件的正中央。
QGroupBox QGroupBox的标题用::title子组件进行定制,标题的位置依QGroupBox::textAlignment的具体值而言。对于可选的QGroupBox而言,标题中还会包含一个勾选标记,勾选标记用::indicator来定制,spacing仍然用于设置勾选标记与文本的间距。
QSpinBox(QDateEdit,QDateTimeEdit) 如图所示,默认情况下spinbox右部分成上下两个按钮。以向上的箭头为例,::up-button和::up-arrow分别用于定制按钮及位于按钮中的箭头号。箭头号默认位于按钮的中间,对于向下的按钮类似,只是用::down-button和::down-arrow子组件。
QToolBox QToolBox是一个具备QQ折叠功能的组件,因此其中的独立的page使用::tab子组件定制。::tab组件支持一些伪状态::only-one, :first, :middle, :previous-selected, :next-selected, :selected,从而达到定制特定page的目的。
QMenuBar 菜单栏组件的spacing属性可指定菜单项之间的间距,单个菜单项还可以通过::item子组件定制风格。但是值得注意的是,由于MAC下菜单栏集成到了系统菜单栏,此时样式表会失去作用。
QProgressBar 进度条组件使用::chunks子组件来定制进度条样式,text-align属性用于设定进度条中文本的对齐方向:left, center, right
QScrollBar 滚动条的组成其实非常复杂,依据垂直和水平方向的不同,由::handle, ::add-line, ::sub-line, ::add-page, ::sub-page, ::right-arrow,  ::left-arrow, ::down-arrow, ::up-arrow等子组件组成。伪状态:horizontal, :vertical用于确定滚动条的方向,width(min-width), height(min-height)则可确定滚动条的不同长和宽。
QToolBar 工具栏的伪状态:top, :left, :right, :bottom的使用依赖于工具栏的具体位置;而:first, :last, :middle, :only-one则用于指代工具栏中的具体位置。工具栏的分隔器用::separator子组件指代,::handle则指代移动工具栏的handle.
QMenu 菜单中的独立项使用::item子组件定制,除了常见的伪状态,::item还支持:selected, :default, :exclusive以及:non-exclusive等伪状态。利用这些伪状态,可以为不同状态的菜单项定制出不同的外观。对于可勾选的菜单项,使用::indicator对勾选标记进行定制,::separator则定制菜单项之间的分隔符;对于有子菜单的菜单项,其箭头号可以用::right-arrow, ::left-arrow进行定制,还有::scroller及::tearoff两个子组件,暂时没搞清楚具体作用。
QLabel QLabel不支持:hover伪状态,自Qt4.3开始,给QLabel设置样式表也就隐式指定了QFrame::frameStyle属性。
QLineEdit 对于QLineEidt,selection-color, selection-background-color属性分别指定了选中文本的文本颜色和背景色,lineedit-password-character属性说明密码输入显示的字符。将在后面的实践中说明。
QPushButton 支持:default, :flat, :checked伪状态,对于具备关联菜单的按钮,可以用::menu-indicator来定制下拉菜单标记。而:open和:closed伪状态则分别用于定制菜单打开和关闭时按钮的外观。
QRadioButton 同上,::indicator用于定制文本前面的选项框,spacing指定文本与选项框之间的间距。
QSlider 对于水平的QSlider,min-width和height属性必须同时提供;对于垂直的QSlider, 必须同时提供min-height和width属性。QSlider由::groove和::handle两部分组成。::groove子组件是一条槽,供::handle在上面滑动。
QSplitter 窗体分割器,主要的部件是::handle。通过::handle可以动态改变分割器中的不同子窗口大小。
QTextEdit 使用selection-color, selection-background-color属性定制,其他的定制方式见QAbstractScrollArea。
QToolButton 如果QToolButton关联了一个菜单,那么和QPushButton是相同的处理方式。如果被设置成了QToolButton::MenuButtonPopup模式,那么::menu-button用于绘制菜单按钮,而::menu-arrow用于绘制按钮中的箭头号。注意:如果设置了QToolButton的背景色,那么必须还要设置边框的宽度才会起作用。这是因为QToolButton默认绘制的边框会完全遮挡住用户设置的背景色。
QAbstractScrollArea 所有派生自QAbstractScrollArea类的子类,包括QTextEdit, QAbstractItemView,都可以通过设置background-attachment属性来实现可滚动背景。通过给background-attachment设置fixed和scroll,背景会固定不动或者跟随滚动。
QHeaderView QHeaderView是Model/View框架中的一部分,最重要的子组件是::section,::section支持:middle, :first, :last, :only-one, :next-selected, :previous-selected, :selected, :checked等伪状态。::up-arrow和::down-arrow用于定制表头的排序标记。
QListView(QListWidget) show-decoration-selected属性控制选中时是选中整项还是仅仅只是项的文本,其他和QTableView相同。
QTableView(QTableWidget) 当view支持斑马色条时,alternate-background-color属性指定备选色实现斑马色带,selection-color和selection-background-color属性指定选定项的文本色和背景色。注意:保证同时设置了背景色和边框宽度值。
QTreeView(QTreeWidget) show-decoration-selected属性控制选中时是选中整项还是仅仅只是项的文本, 子组件::branch和::item用于精细化控制。

应用实例

下面看看如何用QSS对按钮及其关联菜单进行外观定制。我们首先用如下的代码初始化好按钮及其关联菜单,并在Windows 7默认主题下看看其效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
ui.serviceType->setFixedWidth(95);
m_mainMenu = new QMenu(this);
m_osSubMenu = new QMenu(this);
m_appSubMenu = new QMenu(this);
 
m_details = new QAction(QStringLiteral("Details"),this);
m_details->setCheckable(true);
m_details->setChecked(true);
m_settings = new QAction(QStringLiteral("Settings"), this);
m_settings->setIcon(QIcon(":/misc/preference"));
m_settings->setShortcut(QKeySequence::Print);
m_os = new QAction(QStringLiteral("OS"), this);
m_app = new QAction(QStringLiteral("Applications"), this);
 
m_github = new QAction(QStringLiteral("Github"), this);
m_github->setIcon(QIcon(":/app/github"));
m_github->setShortcut(QKeySequence("Ctrl+G"));
m_amazon = new QAction(QStringLiteral("Amazon"), this);
m_amazon->setIcon(QIcon(":/app/amazon"));
m_photoshop = new QAction(QStringLiteral("Photoshop"), this);
m_photoshop->setIcon(QIcon(":/app/photoshop"));
m_facebook = new QAction(QStringLiteral("Facebook"), this);
m_facebook->setIcon(QIcon(":/app/facebook"));
 
m_apple = new QAction(QStringLiteral("Apple"), this);
m_apple->setShortcut(QKeySequence("Ctrl+A"));
m_apple->setIcon(QIcon(":/os/apple"));
m_windows = new QAction(QStringLiteral("Windows"), this);
m_windows->setIcon(QIcon(":/os/windows"));
m_windows->setShortcut(QKeySequence("Ctrl+W"));
m_fedora = new QAction(QStringLiteral("Fedora"), this);
m_fedora->setIcon(QIcon(":/os/fedora"));
m_fedora->setDisabled(true);
 
m_osSubMenu->addAction(m_apple);
m_osSubMenu->addAction(m_windows);
m_osSubMenu->addAction(m_fedora);
m_os->setMenu(m_osSubMenu);
 
m_appSubMenu->addAction(m_amazon);
m_appSubMenu->addAction(m_github);
m_appSubMenu->addAction(m_facebook);
m_appSubMenu->addSeparator();
m_appSubMenu->addAction(m_photoshop);
m_app->setMenu(m_appSubMenu);
 
m_mainMenu->addAction(m_details);
m_mainMenu->addSeparator();
m_mainMenu->addAction(m_os);
m_mainMenu->addAction(m_app);
m_mainMenu->addAction(m_settings);
 
ui.serviceType->setMenu(m_mainMenu);

  先不加任何QSS效果,其效果如下:

一片灰蒙蒙的感觉,不亮堂。对于讲究实用性的软件产品,做到这一步已然足够。如若客户要求具备个性一点的外观呢?此时此刻,我们可以尝试用QSS来进行改造。我们将所有的样式语句放到一个*.qss文件中,然后在main函数中加载。需要注意的是,我们应该将.qss文件添加到.qrc文件中进行编译。每一次修改.qss文件之后应该重新编译.qrc文件。否则在界面上将看不出任何改变。代码如下:

1
2
3
4
QFile file(":/ThemeRoller/style");
file.open(QFile::ReadOnly);
qApp->setStyleSheet(file.readAll());
file.close();

  先考虑将QPushButton作为练手对象,编写如下QSS代码:

1
2
3
4
5
6
7
8
9
10
QPushButton {
    backgroundwhite;
    border1px solid rgb(415785);
    border-radius: 3px;  # 设置边框具备3个像素的圆角
    font-weightbold;    # 字体设置为加粗
}
 
QPushButton:hover {
    background: lightgray;
}

  效果对比如下:

效果似乎还不错,但是我们发现右边的箭头号已经偏移到右下角去了,不太和谐。我们尝试使用subcontrol-positionsubcontrol-origin两个属性来进行调整(position和origin这两个属性在CSS中是非常容易被混淆的,具体含义需细细区分):

QPushButton::menu-indicator{
subcontrol-position: right center;
subcontrol-origin: padding;
}

显然,系统默认的箭头号不太和谐,于是我们再尝试换掉这个箭头号,并且在菜单打开时设置为向下的箭头号,菜单关闭时设置为水平向右的箭头号:

1
2
3
4
5
6
7
8
9
10
11
QPushButton::menu-indicator:open {
    image: url(:/misc/down_arrow_2);
    subcontrol-positionright center;
    subcontrol-origin: padding;
}
 
QPushButton::menu-indicator:closed {
    image: url(:/misc/right_arrow_2);
    subcontrol-positionright center;
    subcontrol-origin: padding;
}

  得到的效果如下:

好吧,到此位置我们的按钮似乎好看多了。再来看看整个关联菜单的QSS该如何编写。首先,把背景色调整为白色是必须的,如下:

1
2
3
4
5
6
7
8
QMenu {
    background-colorwhite;
    padding1px;  # 缩小菜单项四个方向的padding
}
 
QMenu::item{
    background-colortransparent;
}

  

我们可以发现一个严重的缺陷,当鼠标划过相应的菜单项时,文本内容看不见了,显然是由于背景色的原因,所以我们还得修改一下啊:

1
2
3
4
QMenu::item:selected{
    background-colorrgb(234243253);
    colorblack;
}

  用伪状态:selected进行设置,当鼠标划过时将文本颜色设置为黑色,也即保持不变。但此时我们根本看不到鼠标划过的效果,因此给当前选中的菜单项一个背景色吧(rgb(234, 243, 253))。效果如何呢:

根据不同的需要,定制出来的外观也是千差万别的。主要是能理解好QSS中各种属性的作用,其余的工作就是做好布局设计和图片设计。美观大方的界面设计离不开精致的图标设计和合理的布局管理。

参考

  1. Qt style sheet reference

http://www.cnblogs.com/csuftzzk/p/qss_button_menu.html

Qt Style Sheet实践(一):按钮及关联菜单(24K纯开源,一共四篇)的更多相关文章

  1. Qt Style Sheet实践(一):按钮及关联菜单

    导读 正如web前端开发中CSS(Cascade Style Sheet)的作用一样,Qt开发中也可以使用修改版的QSS将逻辑业务和用户界面进行隔离.这样,美工设计人员和逻辑实现者可以各司其职而不受干 ...

  2. Qt Style Sheet实践(二):组合框QComboBox的定制

    导读 组合框是一个重要且应用广泛的组件,一般由两个子组件组成:文本下拉单部分和按钮部分.在许多既需要用户选择.又需要用户手动输入的应用场景下,组合框能够很好的满足我们的需求.如我们经常使用的聊天软件Q ...

  3. Qt Style Sheet实践(二):组合框QComboBox的定制(24K纯开源)——非常漂亮

    组合框是一个重要且应用广泛的组件,一般由两个子组件组成:文本下拉单部分和按钮部分.在许多既需要用户选择.又需要用户手动输入的应用场景下,组合框能够很好的满足我们的需求.如我们经常使用的聊天软件QQ登录 ...

  4. Qt Style Sheet实践(三):QCheckBox和QRadioButton

    导读 单选按钮(QRadioButton)和复选框(QCheckBox)是界面设计中的重要元素.单选按钮只允许用户在一组选项中选择一个,且当其中一个被选中的时候,按钮组中的其他单选按钮自动取消.复选框 ...

  5. Qt Style Sheet实践(四):行文本编辑框QLineEdit及自动补全

    导读 行文本输入框在用于界面的文本输入,在WEB登录表单中应用广泛.一般行文本编辑框可定制性较高,既可以当作密码输入框,又可以作为文本过滤器.QLineEdit本身使用方法也很简单,无需过多的设置就能 ...

  6. Qt 外观之一 ——Qt Style Sheet

    Qt Style Sheet 目录 使用 对于应用程序 创建自定义控件 QSS语法 一般选择器(selector) 伪选择器 解决冲突 使用specificity Namespace冲突 级联效应 设 ...

  7. Qt---自定义界面之 Style Sheet

    这次讲Qt Style Sheet(QSS),QSS是一种与CSS类似的语言,实际上这两者几乎完全一样.既然谈到CSS我们就有必要说一下盒模型. 1. 盒模型(The Box Model) 在样式中, ...

  8. Qt的皮肤设计(Style Sheet)

      Qt的皮肤设计,也可以说是对Qt应用程序的界面美化,Qt使用了一种类CSS的样式规则QSS. 一.Style Sheet的应用 1.直接在程序代码中设置样式,利用setStyleSheet()方法 ...

  9. Qt Style Sheets制作UI特效

    使用Qt Style Sheets制作UI特效  博客出处:http://developer.nokia.com/community/wiki/%E4%BD%BF%E7%94%A8Qt_Style_S ...

随机推荐

  1. 6.828 lab1 bootload

    MIT6.828 lab1地址:http://pdos.csail.mit.edu/6.828/2014/labs/lab1/ 第一个练习,主要是让我们熟悉汇编,嗯,没什么好说的. Part 1: P ...

  2. iCloud同步测试

    步骤一 在iPad上拍照A后,相机胶卷与照片流都出现照片A --> Mac上iCloud我的照片流内出现照片A --> iphone上我的照片流出现照片A 同理,在iphone拍摄照片B后 ...

  3. std::string 字符替换函数

    // 替换路径中所有“\”为“/” #include <algorithm> static std::string ConvertSlash(std::string& strUrl ...

  4. $.browser.msie jq解析不出来的原因及解决方法

    检查是否为 IE6:// Oldif ($.browser.msie && 7 > $.browser.version) {}// Newif ('undefined' == t ...

  5. css书写顺序和常用命名推荐

    写代码的时候有一个好的规范和顺序能够帮你节省很多时间.下文将推荐相关CSS书写顺序和规范的一些方法.这个文档将会整理进前端规范文档中,如果你有更好的意见,不妨留言告知我们. CSS书写顺序 该代码来自 ...

  6. Android textview 设置不同的字体大小和颜色

    在实际应用中,需要将一个字符串已不同的颜色,字体显示出来.当然完全可以通过不同textview拼接出来.也可以通过一个textview来展示. 步骤如下: 1.定义不同style . 不妨如下定义2个 ...

  7. 动态Script标签 解决跨域问题

     动态Script 解决跨域问题 1.动态创建scriptcreateScript : function(src){ var varScript = document.createElement(&q ...

  8. 【Linux指令】使用中学习(一)

    sed指令: 应用:对于大文件,比如10G的大文件,我遇到的是导出的数据库.sql文件,想要使用vim修改几乎是不可能的,用sed指令可以在不打开文件的情况下修改文件,下面是一些具体用法 删除文件特定 ...

  9. SQL Server FileStream优点与不足

    LOB优点: 1.保证大对象的事务一致性. 2.备份与还原包括大数据对象,可以对它进行时点恢复. 3.所有数据都可以使用一种存储与查询环境. LOB不足: 1.大型对象在缓存中占非常大的缓存区. 2. ...

  10. 权威验证:MSDN会明确告诉你下载的光盘镜像是否正宗微软原版

    MSDN是微软官方网站.这个网站的职能之一,就是向MSDN订户(付费相当高昂)提供Microsoft Windows资源,即大家通常说的操作系统光盘镜像.相信大家手头都有不少这类下载,但究竟是否微软的 ...