Qt控件样式之QSS
QSS常用于Qt的控件样式美化,合理地使用Qss可以完成在不改动代码的情况下改变Qt界面的样式。
官方提供的例子: http://qt-project.org/doc/qt-4.8/stylesheet-examples.html
这个是官方提供的例子,只有qt-4.8的,目前Qt最新版本是Qt5.4,但似乎在qss这块没有较大的更新,同时有关帮助手册可以在Qt Assistant中寻找。
在这个Qt Style Sheets Reference中有QSS所支持的所有属性、状态,QSS是参照CSS2的,但并非所有的CSS2属性QSS都支持,具体支不支持就需要查一下帮助手册了。
QSS的语法和CSS的语法保持一致
selector {declaratin1; declaratin2; ...declaratinN; }
拿最简单的QPushButton来看
QPushButton { // selector color: red; // \ border: none; // / declaration }
declaration部分就是一系列的properties: values
在使用属性:值的时候曾经碰到过一个小问题。
QLabel { background: url ("xxxx"); // 如果在url后面有空格,这句属性将不起效果 }
由于自己在写C/C++代码的时候有在函数名后加空格的习惯,导致了这个错误,需要注意一下。
上面直接使用QPushButton或是QLabel将会对所有的该类控件引起效果,有些时候我们并不希望这样,所以这个时候需要指定选择器来区分要操作的对象。
关于选择器的一些介绍可以看这篇博文,虽然也是转载的http://www.cnblogs.com/davesla/archive/2011/01/30/1947928.html
稍微总结一下常用的。
QSS 中最常用的当属ID选择器了,用#号区分
QLabel#thisIsLabel { color: red; }
用了ID选择器以后,将只会有这个ID对应的控件会产生样式效果。拿这个ID怎么来的呢?一般通过setObjectName指定的,像对这个QLabel进行设置,就必须在代码中加上thisIsLabel->setObjectName ("thisIsLabel");
但通常从Designer中命名好的控件不用特意加上setObjectName是因为在系统生成的ui头文件中已经帮你做了这件事儿了,所以在用的时候千万不能QLabel#ui->thisIsLabel 这样,ui是命名控件,这样写是非法的。
属性选择器有些时候也会有妙用,比如当你的一个控件需要因为一个属性的改变而希望样式改变的时候,就需要用到属性选择器。
QLabel#thisIsLabel[enable=true] { color: red; } QLabel#thisIsLabel[enable=false] { color: blue; }
[] 中括号内部的就是选择的属性,属性名和value都需要通过setProperty这个函数实现。
下面这个是Qt Assistant关于这个函数的介绍,这个函数除了指定属性为QSS服务以外还有很多其他的用法,这里暂不做讨论。
我基本上就使用这两种选择器能完成大部分的设计了。
然后就是一些子控件选择器了,如 QAbstractItemView 的::item, QScrollBar的::handle。
这些以::开头的都表示控件的子控件选择器,为什么说是子控件,因为一个控件可能是由多个子控件组成的,我们在改变样式的时候自然也希望改变其子控件的样式。
像:hover, :pressed, :checked这些都是伪指示器,活用这些可以实现控件的三态效果(普通,悬停,按下),但要注意的是并不是所有的控件都会有这些效果的,QLabel就没有,但如果想实现QLabel的三态效果也不是不可以,可以使用事件过滤器去捕获QLabel的enterEvent和leaveEvent实现hover,使用mousePressEvent实现pressed,只是QLabel本身是不支持的,具体哪些控件支持哪些功能,可以查阅Qt Style Sheets Reference
伪指示器也是支持!(否定符号)的
QPushButton#myBtn:!pressed { color: red; }
这样就表示在鼠标没有按下的情况下字体颜色是红色的。
掌握QSS的基础知识 + 懂CSS2语法基本就能进行QSS样式设计了。
QSS在代码中可以通过setStyleSheet ();的方式将样式设置进去,但同时也可以通过加载样式文件的方式,我通常喜欢把所有的QSS放在xxx.qss文件中进行统一管理。
QApplication a (argc, argv);
File_operate file_opt;
QByteArray array = file_opt.read_file (FILE_STYLE_PATH);
array += file_opt.read_file (FILE_STYLE_ADD_PATH);
a.setStyleSheet (QLatin1String (array));
File_operate是我根据QFile封装的一层类,增加了一些日志和判断
这里我用到了两个路径,为了实现换肤的效果,第一个路径文件里面放置的QSS基础样式,而第二个路径文件里面放置的是要拓展改变的样式,这样我可以通过加载不同的文件来实现样式的快速切换。
在使用QSS的时候还发现了一些小BUG,可能不能算BUG,但如果用CSS习惯将会实现不了的功能。
有这样一张图片
图片的尺寸是260*32, 而我希望在26*32的一个label上面显示这张图片,我所能想到的两个属性是background和border-image
如果拿background来做,就需要用到background-position这个属性
backgroud:#FFF url(image) no-repeat [fixed | scoll] x y;
#FFF 表示背景色
image 表示图片资源路径
no-repeat 表示图片是否重复
fixed 表示不滑动 scroll 表示滚动 默认为scroll
x y 表示图片的偏移量,也就是background-position这个属性
在CSS语法中,x y 可以用百分比或者px表示,也可以使用left、right、top、bottm、center这五种对齐方式
而在这个应用中我采用了这句语法发现是不起效果的
background: url(:/C:/Users/xx/Desktop/days_nums.png) no-repeat fixed 26px 0px;
我希望的显示1这个数字,实际上没有任何效果,当然采用百分比的方式
background: url(:/C:/Users/xx/Desktop/days_nums.png) no-repeat fixed 10% 0%;
效果依旧和前一种一样,而使用对齐方式表示,则生效了
background: url(:/C:/Users/dp/Desktop/days_nums.png) no-repeat fixed right;
这样就会显示最右边的数字9
不知道是否是我“打开方式有误”,感觉如果不能使用数字和百分比的话我就无法实现我的需求了,这个时候就只能思量border-image这个属性了,关于border-image,这里有篇非常好的文章解释了其用法 戳这里
使用border-image实现上面需要的功能,就要利用其剪裁特性,其实就是左一刀右一刀上一刀下一刀,对于border-image而言,剪裁后会留下周围一圈的切片,可以通过单独对这些切片处理就获得了想要的border,看到这个之后发现,如果要实现背景的阴影也只需要拿一张含有阴影的图片裁剪成九宫格,然后可以随意扩展top、right、bottom、left的尺寸,再和4个角拼接起来。
border-image: url(:/C:/Users/xx/Desktop/days_nums.png) 0 208 0 26 stretch stretch;
这里的0、208、0、26分别是top、right、bottom、left的裁剪坐标,这句语句所形成的效果是,把1这个数字显示在了32*26的QLabel上了,可是从上面分享的那篇文章来看,border-image显示的应该是边框,不应该是中间那块,我表示比较纳闷,除此之外,这条语句依旧不支持百分比
border-image: url(:/C:/Users/xx/Desktop/days_nums.png) 0% 80% 0% 10% stretch stretch;
这样原来应该和数字表示的形成一样的效果,结果发现这条语句也将不起作用,这是否算是QSS遗留的一些BUG呢?
关于这些“BUG”只是自己摸索的,或许哪些地方没有考虑到,请各位大神指点。
一点点小小的总结,希望对Qt初学者有所帮助,不足之处望指出。