一、qss文件的使用
// 设置qss
QFile qss(":/prefix/style.qss");
if (qss.open(QFile::ReadOnly)) {
qApp->setStyleSheet(qss.readAll());
qss.close();
}
二、语法规则
1.Qt 样式表
Qt样式表(style sheet) 是用于定制用户界面的强有力的机制,其概念、术语是受到HTML中的级联样式表( Cascading Style Sheets, CSS) 启发而来的,只是Qt样式表是应用于窗体界面的。
与HTML的CSS类似, Qt的样式表是纯文本的格式定义,在应用程序运行时可以载入和解析这些样式定义。使用样式表可以定义各种界面组件(QWidget类及其子类)的样式,从而使应用程序的界面呈现不同的效果。很多软件具有换肤功能,使用Qt的样式表就可以容易地实现这样的功能。
在UI 设计器中集成了Qt样式表的编辑功能。在设计窗时,选择窗体或某个界面组件,单击鼠标右键,在弹出的快捷菜单中选择” Change styleSheet …” 菜单项就可以出现样式表编辑对话框。图16-4所示是某个窗体的样式表编辑对话框,已经对窗体和一些类设置了样式定义,例如:
QWidget{
background-color: rgb(255, 255, 0);
color: rgb(255, 0, 0);
font: 12pt "宋体";
}
这定义了QWidget类的背景颜色、字体大小和名称、前景颜色。这个样式定义会应用于QWidget 类及其子类。
QLineEdit {
border: 2px groove gray;
border-radius: 5px;
padding: 2px 4px;
border-color: rgb (12, 45, 68);
}
这定义了QLineEdit 类的显示效果,包括边框宽度、圆角边框的半径和边框颜色等。
图1 样式表编辑对话框
在图1中的对话框内,上方有几个具有下拉菜单的按钮,可以添加一些常用的样式属性,如前景色color、背景色background-color 、选中后颜色selection-color,以及背景图片background-image等。
2.Qt样式表句法
2.1 一般句法格式
Qt 样式表的句法(syntax)与HTML的CSS句法几乎完全相同。Qt样式表包含一系列的样式法则,一个样式法则由一个选择器(selector) 和一些声明(declaration ) 组成。例如:
QPlainTextEdit(
font: 12pt "仿宋";
color: rgb (255, 255, 0) ;
background-color: rgb (0, 0, 0);
}
其中, QPlainTextEdit就是选择器,表明后面花括号里的样式声明应用于QPlainTextEdit 类及其子类。样式声明部分是样式法则列表,每个样式法则由属性和值组成,每条法则用分号结束。每条样式法则由“属性:值”构成,例如:font: 12pt "仿宋";
。表示font属性,字体大小为12pt,字体名称为“仿宋”;当一个属性有多个值时,多个值用空格隔开。
2.2 选择器(selector)
Qt样式表支待CSS2中定义的所有选择器,表16-1显示的是一些常用的选择器。
表16-1 Qt样式表中的选择器类型
选择器 | 例子 | 用途 |
---|---|---|
通用选择器 | * | 所有组件 |
类型选择器 | QPushButton | 所有QPushButton类及其子类的组件 |
属性选择器 | QPushButton[ flat= “false” ] | 所有flat属性为false的QPushButton类及其子类的组件。如果样式表应用后组件的属性再发生变化,需要重新应用样式表才能刷新显示效果 |
非子类选择器 | .QPushButton | 所有QPushButton类的组件,但是不包括QPushButton 的子类 |
ID 选择器 | QPushButton#btnOK | ObjectName为btnOK的QPushButton实例 |
从属对象选择器 | QDialog QPushButton | 所有从属于QDialog的QPushButton类的实例,即QDia log对话框里的所有QPushButton |
子对象选择器 | QDialog > QPushButton | 所有直接从属于QDialog的QPushButton类的实例 |
这些选择器的定义为选择界面组件提供了灵活性。选择器可以组合使用, 一个样式声明可以
应用于多个选择器,例如:
QPlainTextEdit, QLineEdit, QPushButton, QCheckBox {
color: rgb(255, 255, 0);
background- color: rgb (O, 0, 0);
}
这个样式声明将同时应用于QPlainTextEdit、QLineEdit 、QPushButton和QCheckBox的实例。
QLineEdit[readOnly="true"], QCheckBox[checked="true"] {
background-color: rgb (255, 0, 0)
}
上面的这个样式应用于readOnly属性为true的QLineEdit 和checked属性为true的QCheckBox实例,功能是使其背景颜色为红色。
在Qt中,可以为一个界面组件使用QObject::setPropertys()
设置一个动态属性,例如,在数据表编辑界面上,一些字段是必填字段,就可以为这些字段的关联组件设置一个required属性为true,如:
editName->setProperty("required", "true");
comboSex->setProperty("required", "true");
checkAgree->setProperty("rPqnired", "true");
这样设置了三个界面组件的动态属性required为true 。
那么,可以应用下面的样式将这种必填字段的背景颜色设置为亮绿色。
*[required="true"] {
background-color: lime
}
2.3 子控件(sub-controls)
对于一些组合的界面组件,需要对其子控件进行选择,如QComboBox的下拉按钮,或QSpinBox的上、下按钮。通过选择器的子控件可以对这些界面元素进行显示效果控制。例如:
QComboBox::drop-down {
image: url(:/images/images/down.bmp);
}
选择器QComboBox::drop-down选择了QComboBox的drop-down子控件,定义的样式是设置其image属性为资源文件中的图片down.bmp 。
QSpinBox::up-button {
image: url(:/images/images/up.bmp);
}
QSpinBox::down-button {
image:url(:/images/images/down.bmp);
}
这两条样式定义语句分别定义了QSpinBox的上、下按钮的图片,用资源文件中的图片替代了缺省的图片。
这样定义的QComboBox和QSpinBox具有如图16-5所示的显示效果。
Qt中常用的子控件见表16-2, 所有子控件的详细描述见Qt 的帮助文档。
表16-2 Qt 样式表中常见的子控件列表
子控件名称 | 说明 |
---|---|
::branch | QTreeView的分支指示器 |
::chunk | QProgressBar的进度显示块 |
::close-button | QDockWidget或QTabBar页面的关闭按钮 |
::down-arrow | QComboBox, QHeaderYiew(排序指示器), QScrollBar或QSpinBox的下拉箭头 |
::down-button | QComboBox的下拉按钮 |
::float-button | QDockWidget 的浮动按钮 |
::groove | QSlider的凹槽 |
::indicator | QAbstractltemView,QCheckBox,QRadioButton,可勾选的QMenu菜单项,或可勾选的QGroupBox的指示器 |
::handle | QScrollBar,QSplitter或QSlider的滑块 |
::icon | QAbstractltemView或QMenu的图标 |
::item | QAbstractltemView,QMenuBar,QMenu或QStatusBar的一个项 |
::left-arrow | QScrollBar的向左箭头 |
::menu-arrow | 具有下拉菜单的QToolButton的下拉箭头 |
::menu-button | QToolButton的菜单按钮 |
::menu-indicator | QPushButton的菜单指示器 |
::right-arrow | QMenu或QScrollBar的右侧箭头 |
::pane | QTabWidget的面板 |
::scroller | QMenu或QTabBar的卷轴 |
::section | QHeaderView的分段 |
::separator | QMenu或QMainWindow的分隔器 |
::tab | QTabBar或QToolBox的分页 |
::tab-bar | QTabWidget的分页条。这个子控件只用于控制QTabBar在QTabWidget中的位置,定义分页的样式使用tab子控件 |
::text | QAbstractlternView的文字 |
::title | QGroupBox或QDockWidget的标题 |
::up-arrow | QHeaderView(排序指示器), QScrollBar或QSpinBox的向上箭头 |
::up-button | QSpinBox的向上按钮 |
2.4 伪状态( pseudo-states)
选择器可以包含伪状态,使得样式法则只能应用于界面组件的某个状态,也就是一种条件应用法则。伪状态出现在选择器的后面,用一个冒号( : )隔开。如下面的样式法则:
QLineEdit:hover{
background-color: black;
color: yellow;
}
定义了当鼠标移动到QLineEdit上方时( hover ),改变QLineEdit的背景色和前景色。
可以对伪状态取反,方法是在伪状态前面加一个感叹号(!),如:
QLineEdit:!read-only{
background-color: rgb(235, 255,251);
}
这定义了readonly属性为false 的QLineEdit 的背景色。
伪状态可以串联使用,相当千逻辑与的计算,例如:
QCheckBox:hover:checked{
color: red;
}
这定义了当鼠标移动到一个被勾选了的QCheckBox组件上方时,其字体颜色变为红色。
伪状态可以并联使用,相当千逻辑或的计算,例如:
QCheckBox:hover, QCheckBox:checked{
color: red;
}
这表示鼠标移动到QCheckBox组件上方,或QCheckBox组件被勾选时,字体颜色变为红色。
子控件也可以使用伪状态,如:
QCheckBox::indicator:checked{
image: url(:/images/images/checked.bmp);
}
QCheckBox::indicator:unchecked{
image: url(:/images/images/unchecked.bmp);
}
这里定义了QCheckBox的indicator在checked和unchecked两种状态下的显示图片。
Qt样式定义中常见的一些伪状态见表16-3 , 熟悉这些伪状态并灵活应用可以定义自己想要的界面效果。
表16-3 Qt样式表中常见的伪状态
伪状态 | 描述 |
---|---|
::active | 当组件处于一个活动的窗体时,此状态为真 |
::adjoins-item | QTreeView::branch与一个条目相邻时,此状态为负 |
::alternate | 当QAbstractltemView的alternatingRowColors()属性为true时,绘制交替的行时此状态为真 |
::bottom | 组件处于底部,如QTabBar的表头位于底部 |
::checked | 组件被勾选,如QAbstractButton的checked属性为true |
::closable | 组件可以被关闭,例如当QDockWidget的DockWidgetClosable属性为true时 |
::closed | 条目处于关闭状态,例如QTreeView的一个没有展开的条目 |
::default | 条目是缺省的,如一个缺省的QPushButton按钮,或QMenu中一个缺省的action |
::disabled | 条目被禁用 |
::editable | QCornboBox是可编辑的 |
::edit-focus | 条目有编辑焦点 |
::enabled | 条目被使能 |
::exclusive | 条目是一个排他性组的一部分,例如一个排他性QActionGroup的一个菜单项 |
::first | 第一个项,例如QTabBar中的第一个页 |
::flat | 条目是flat的,例如QPushButton的flat属性设置为true时 |
::focus | 条目具有输入焦点 |
::has-children | 条目有子条目,例如QTreeView的一个节点具有子节点 |
::horizontal | 条目具有水平方向 |
::hover | 鼠标移动到条目上方时 |
::last | 最后一个项,例如QTabBar中的最后一页 |
::left | 条目位于左侧,例如QTabBar的页头位于左侧 |
::maximized | 条目处于最大化,例如最大化的QMdiSubWindow窗口 |
::minimized | 条目处于最小化,例如最小化的QMdiSubWindow窗口 |
::movable | 条目是可移动的 |
::off | 对于可以切换状态的条目,其状态处于“off’’ |
::on | 对于可以切换状态的条目,其状态处于”on” |
::open | 条目处于打开状态,例如QTreeView的一个展开的条目 |
::pressed | 条目上按下了鼠标 |
::read-only | 条目是只读或不可编辑的 |
::right | 条目位于右侧,例如QTabBar的页头位于右侧 |
::selected | 条目被选中,例如QTabBar中一个被选中的页,或QMenu中一个被选中的菜单项 |
::top | 条目位于顶端,例如QTabBar的页头位于顶端 |
::unchecked | 条目处于被被选中状态 |
::vertical | 条目处于垂直方向 |
2.5 属性
Qt样式表内对每一个选择器可定义多条样式规则,每个规则是一个“属性:值”对, Qt样式表中可定义的属性很多,可以在Qt的帮助文件中查找“Qt Style Sheets Reference” 查看所有属性的详细说明。
在图16-4所示的样式表编辑对话框中,从上方的几个按钮的下拉菜单中可以设计常用的一些属性,如“Add Resource”按钮下三个菜单项可以从项目的资源文件中选择图片作为background-image、border-image或image属性的值;“Add Color”按钮的下拉菜单用于设置组件的各种颜色,包括前景色、背景色、边框颜色等,颜色的值可以用rgb()、rgba()函数表示,或Qt能识别的颜色常量。
使用样式表可以定义组件复杂的显示效果。每个界面组件都可以用如图16-7 所示的盒子模型(BoxModel)来表示,模型由四个同心矩形表示。
(1) content是显示内容矩形区域,如QLineEdit用于显示文字的区域,min-width、max-width、min-height和max-height属性定义最大/最小宽度或高度,就是定义这个矩形区,例如:
QLineEdit {
min-width: 50px;
max-height: 40px;
}
这定义QLineEdit 最小宽度为50px,最大高度是40px,其中px是单位,表示像素。
(2) padding是包围content的矩形区域,通过padding属性可以定义padding的宽度,或padding-top、padding-bottom、padding-left和padding-right分别定义padding的上、下、左、右宽度,例如:
QLineEdit{
padding: 0px 10px 0px 10px;
}
这设定padding的上、右、下、左的宽度, 它等效于:
QLineEdit{
padding-top: 0px;
padding-right: 10px;
padding-bottom: 0px;
padding-left: 10px;
}
(3) border是包围padding的边框,通过border属性(或border-width、border-style、border-color)
可以定义边框的线宽、线型和颜色,也可以分别定义border的上、下、左、右的线宽和颜色。使用border-radius 可以定义边框转角的圆弧半径,从而构造具有圆角矩形的编辑或按钮等组件,例如:
QLineEdit {
border-width: 2px;
border-style: solid;
border-color: gray;
border-radius: 10px;
padding: 0px 10px;
}
这使得QLineEdit 具有灰色边框线条、圆角矩形的效果。
通过border-radius 、min-width和min-height等属性可以设计圆形的按钮,如:
QPushButton {
border: 2px groove red;
border-radius: 30px;
min-width: 60px;
min-height: 60px;
}
使得边框转角半径等于content宽度或长度的一半,宽度和长度相等, 就可以得到一个圆形的按钮。
使用border-image属性还可以为组件设置背景图片,图片会填充border矩形框之内的区域,一般使用材质图片设置背景,以使界面具有统一的特色,例如:
QLineEdit, QPushButton{
border-image: url(:/images/images/border.jpg);
}
(4) margin是border之外与父组件之间的空白边距,可以分别定义上、下、左、右的边距大小。
缺省的情况下,margin、border-width和padding属性缺省值为零,这种情况下,四个同心矩形就是重合的一个矩形。
使用Qt样式表可以为界面组件设计各种美观的显示效果,美观而特殊的界面不仅需要编程的能力,更重要的是美工设计能力。
3 样式表的使用
3.1 程序中使用样式表
有多种方法可以应用样式表。
第一种是在使用Qt Designer设计窗体时,直接用样式表编辑器为窗体或窗体的某个部件设计样式表,则设计的样式保存在窗体的ui文件里,窗体创建时会自动用所设计的样式表。这样设计的样式表对应用程序是固定的,无法取得换肤的效果,且需要为每个窗体都设计样式表,重复性工作量太大。
第二种是使用setStyleSheet函数应用样式,使用qApp的setStyleSheet( )函数可以为应用程序全局设置样式,使用QWidget::setStyleSheet( )可以为一个窗口、一个对话框或一个界面组件设置样式。例如:
qApp->setStyleSheet( " QLineEdit { background-color: gray } ");
这里使用应用程序全局变量qApp为QLineEdit设置样式,如果应用程序内的某些QLineEdit组件没有再被设置样式,则QLineEdit组件的背景色为灰色。
MainWindow->setStyleSheet( " QLineEdit { background-color: gray } ");
这是为主窗口MainWindow内的QLineEdit组件设置样式,即背景色为亮绿色。
editName->setStyleSheet (" color: blue;"
"background-color: yellow;"
"selection-color: yellow;"
"selection-background-color: blue;");
这是设置一个ObjectName为editName的QLineEdit组件的样式,注意这时在样式表中无需设置selector名称,所设置的样式是应用于editName这个QLineEdit组件的。
这样将样式表固定在程序中,很显然也是无法实现切换界面效果的。为了实现切换界面效果(换肤)的目的,一般将样式定义表保存为qss后缀的纯文本文件,然后在程序中打开文件,读取文本内容,再调用setStyleSheet( )函数应用样式。示例代码如下:
QFile file(":/qss/mystyle.qss");
file.open (QFile::ReadOnly);
QString styleSheet = QString::fromLatinl(file.readAll());
qApp->setStyleSheet(styleSheet);
3.2 样式定义的明确性
当多条样式法则对一个属性定义了不同值时,就会出现冲突,例如:
QPushButton#btnSave{ color: gray }
QPushButton{ color: red }
这两条法则都可以应用于ObjectName为btnSave的QPushButton组件,都定义了其前景色,这就会出现冲突。这时,选择器的明确性(specificity)决定组件适用的样式法则,即法则应用于更明确的组件。在上面的例子中, QPushButton#btnSave被认为是比QPushButton更明确的选择器,因为它指向一个对象,而不是QPushButton的所有实例。所以,如果是在一个窗口上应用以上两条法则,则btnSave按钮的前景色为gray,而其他按钮的前景色为red。
同样,具有伪状态的选择器被认为比没有伪状态的选择器明确性更强,如:
QPushButton:hover{ color: white }
QPushButton{ color: red }
这样,当鼠标在按钮上停留时颜色为white, 否则颜色为red。
如果两个选择器具有相同的明确性,则以法则出现的先后顺序为准,后出现的法则起作用,例如:
QPushButton:hover{ color: white }
QPushButton:enabled{ color: red }
这里的两个选择器具有相同的明确性,所以,当鼠标停留在一个使能的按钮上时,只有第二条法则起作用。这种情况下,如果希望不出现冲突,应该修改法则以使其更明确,如下面这两条法则是不冲突的。
QPushButton:hover:enabled{ color: white }
QPushButton:enabled{ color: red }
父子关系的两个类作为选择器时,具有相同的明确性,例如:
QPushButton { color: red}
QAbstractButton { color: gray}
这两个选择器的明确性相同,所以只依赖于语句的先后顺序。
确定法则的明确性,Qt样式表遵循CSS2的规定,在设计样式表时应尽量明确并避免冲突情况。
3.3 样式定义的级联性
样式定义可以在qApp、窗口或一个具体组件中定义,任何一个组件的样式是其父组件、父窗口和qApp的样式的融合。当出现冲突时,组件会使用离自己最近的样式定义,即按顺序使用组件自己的样式、或父组件的样式定义、或父窗口的样式定义,或qApp的样式定义,而不考虑样式选择器的确定性。
例如,在QApplication中设置全局样式:
qApp->setStyleSheet( " QPushButton { color: red } ");
那么应用程序中所有未再定义样式的QPushButton的前景颜色为red 。
如果在MainWindow中再定义样式:
MainWindow->setStyleSheet( " QPushButton { color: blue } ");
则MainWindow上的按钮的前景色为blue,而不是red 。
如果MainWindow上有一个名称为btnSave的QPushButton按钮,其定义样式如下:
btnSave->setStyleSheet( " color: yellow; background-color: black; " );
则按钮btnSave 按照自己的样式显示前景和背景色。
Qt样式表功能强大,可以设计自己想要的界面效果,但是这需要有较好的美工设计基础,需要在使用样式表的过程中不断尝试和总结经验。