对于 QSS 来说, 基本的语法结构非常简单:
选择器 {
属性名: 属性值;
}
其中:
例如:
QPushButton { color: red; }
上述代码的含义表示,针对界⾯上所有的 QPushButton , 都把⽂本颜⾊设置为红色。
代码示例: QSS 基本使用:
1 Widget::Widget(QWidget *parent)
2 : QWidget(parent)
3 , ui(new Ui::Widget)
4 {
5 ui->setupUi(this);
6
7 ui->pushButton->setStyleSheet("QPushButton { color: red; }");
8 }
QWidget 中包含了 setStyleSheet ⽅法, 可以直接设置样式。上述代码我们已经演⽰了上述设置⽅式。
另⼀⽅⾯, 给指定控件设置样式之后, 该控件的⼦元素也会受到影响。
代码⽰例: ⼦元素受到影响
在界⾯上创建⼀个按钮
修改 widget.cpp, 这次我们不再给按钮设置样式, ⽽是给 Widget 设置样式 (Widget 是 QPushButton 的⽗控件).
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 给 Widget 本⾝设置样式.
this->setStyleSheet("QWidget { color: red;} ");
}
运⾏程序, 可以看到样式对于⼦控件按钮同样会⽣效.
还可以通过 QApplication 的 setStyleSheet ⽅法设置整个程序的全局样式. 全局样式优点:
代码⽰例1: 使⽤全局样式
在界⾯上创建三个按钮.
编辑 main.cpp, 设置全局样式
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton { color: red; }");
Widget w;
w.show();
return a.exec();
}
运⾏程序, 可以看到此时三个按钮的颜⾊都设置为红⾊了.
代码⽰例2: 样式的层叠特性
如果通过全局样式给某个控件设置了属性1, 通过指定控件样式给控件设置属性2, 那么这两个属性都会产⽣作⽤.
在界⾯上创建两个按钮
编写 main.cpp, 设置全局样式, 把按钮⽂本设置为红⾊
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton { color: red; }");
Widget w;
w.show();
return a.exec();
}
编写 widget.cpp, 给第⼀个按钮设置字体⼤⼩.
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置指定控件样式
ui->pushButton->setStyleSheet("QPushButton { font-size: 50px} ");
}
运⾏程序, 可以看到, 对于第⼀个按钮来说, 同时具备了颜⾊和字体⼤⼩样式. ⽽第⼆个按钮只有颜⾊样式.说明针对第⼀个按钮, 两种设置⽅式设置的样式, 叠加起来了.
注意:如果全局样式, 和指定控件样式冲突, 则指定控件样式优先展⽰.
上述代码都是把样式通过硬编码的⽅式设置的. 这样使 QSS 代码和 C++ 代码耦合在⼀起了, 并不⽅便代码的维护.
因此更好的做法是把样式放到单独的⽂件中, 然后通过读取⽂件的⽅式来加载样式.
代码⽰例: 从⽂件加载全局样式:
使⽤ Qt Creator 打开 style.qss , 编写内容:
QPushButton {
color: red;
}
修改 main.cpp, 新增⼀个函数⽤来加载样式
QString loadQSS() {
QFile file(":/style.qss");
// 打开⽂件
file.open(QFile::ReadOnly);
// 读取⽂件内容. 虽然 readAll 返回的是 QByteArray, 但是 QString 提供了QByteArray 版本的构造函数.
QString style = file.readAll();
// 关闭⽂件
file.close();
return style;
}
修改 main.cpp, 在 main 函数中调⽤上述函数, 并设置样式.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 调⽤上述函数加载样式
const QString& style = loadQSS();
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
运⾏程序, 可以看到样式已经⽣效了.
QSS 也可以通过 Qt Designer 直接编辑, 从⽽起到实时预览的效果. 同时也能避免 C++ 和 QSS 代码的耦合.
代码⽰例: 使⽤ Qt Designer 编辑样式
代码示例:使⽤ id 选择器
先通过 QPushButton 设置所有的按钮为⻩⾊.
再通过 #pushButton 和 #pushButton_2 分别设置这两个按钮为红⾊和绿⾊.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
QString style = "";
style += "QPushButton { color: yellow; }";
style += "#pushButton { color: red; }";
style += "#pushButton_2 { color: green; }";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
有些控件内部包含了多个 “⼦控件” . ⽐如 QComboBox 的下拉后的⾯板, ⽐如 QSpinBox 的上下按钮等.
可以通过⼦控件选择器 :: , 针对上述⼦控件进⾏样式设置
代码⽰例: 修改进度条的颜⾊
编辑如下内容:
其中的 chunk 是选中进度条中的每个 “块” . 使⽤ QProgressBar::text 则可以选中⽂本.
QProgressBar::chunk {background-color: #FF0000;}
同时把 QProcessBar 的 alignment 属性设置为垂直⽔平居中.
通过上述⽅式, 也可以修改⽂字的颜⾊, 字体⼤⼩等样式。
伪类选择器, 是根据控件所处的某个状态被选择的. 例如按钮被按下, 输⼊框获取到焦点, ⿏标移动到某个控件上等.
使⽤ : 的⽅式定义伪类选择器
常⽤的伪类选择器:
这些状态可以使⽤ ! 来取反. ⽐如 :!hover 就是⿏标离开控件时, :!pressed 就是⿏标松开时, 等等.
代码⽰例: 设置按钮的伪类样式.
在界⾯上创建⼀个按钮
编写 main.cpp, 创建全局样式
int main(int argc, char *argv[])
{
QApplication a(*argc*, argv);
QString style = "";
style += "QPushButton { color: red; }";
style += "QPushButton:hover { color: green; }";
style += "QPushButton:pressed { color: blue; }";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
运⾏程序, 可以看到, 默认情况下按钮⽂字是红⾊, ⿏标移动上去是绿⾊, ⿏标按下按钮是蓝⾊.
QSS 中的样式属性⾮常多, 不需要都记住. 核⼼原则还是⽤到了就去查.
⼤部分的属性和 CSS 是⾮常相似的.
在⽂档的 Customizing Qt Widgets Using Style Sheets 的 The Box Model 章节介绍了盒模型.
⼀个遵守盒模型的控件, 由上述⼏个部分构成.
默认情况下, 外边距, 内边距, 边框宽度都是 0
可以通过⼀些 QSS 属性来设置上述的边距和边框的样式.
代码⽰例: 设置边框和内边距
在界⾯上创建⼀个 label
修改 main.cpp, 设置全局样式
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet("QLabel { border: 5px solid red; padding-left: 10px; }");
Widget w;
w.show();
return a.exec();
}
代码⽰例: 设置外边距
为了⽅便确定控件位置, 演⽰外边距效果, 我们使⽤代码创建⼀个按钮
修改 widget.cpp, 创建按钮, 并设置样式
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn = new QPushButton(this);
btn->setGeometry(0, 0, 100, 100);
btn->setText("hello");
btn->setStyleSheet("QPushButton { border: 5px solid red; margin: 20px; }");
const QRect& rect = btn->geometry();
qDebug() << rect;
}
运⾏程序, 可以看到, 当前按钮的边框被外边距挤的缩⼩了. 但是获取到的按钮的 Geometry 是不变的.
代码⽰例: ⾃定义按钮
右键 -> 改变样式表, 使⽤ Qt Designer 设置样式
QPushButton {
font-size: 20px;
border: 2px solid #8f8f91;
border-radius: 15px;
background-color: #dadbde;
}
QPushButton:pressed {
background-color: #f6f7fa;
}
执⾏程序, 可以看到效果
代码⽰例: ⾃定义复选框
创建⼀个复选框
QCheckBox {
font-size : 20px;
}
QCheckBox::indicator {
width: 20px;
height: 20px;
}
QCheckBox::indicator : unchecked {
image: url(:/checkbox - unchecked.png);
}
QCheckBox::indicator : unchecked : hover {
image:url(:/checkbox - unchecked_hover.png);
}
QCheckBox::indicator:unchecked:pressed {
image: url(:/checkbox-unchecked_pressed.png);
}
QCheckBox::indicator:checked {
image: url(:/checkbox-checked.png);
}
QCheckBox::indicator:checked:hover {
image: url(:/checkbox-checked_hover.png);
}
QCheckBox::indicator:checked:pressed {
image: url(:/checkbox-checked_pressed.png);
}
运⾏程序, 可以看到此时的复选框就变的丰富起来了
参考复选框,用法基本一样。
代码⽰例: ⾃定义单⾏编辑框
在 Qt Designer 中编写样式.
QLineEdit {
border-width: 1px;
border-radius: 10px;
border-color: rgb(58, 58, 58);
border-style: inset;
padding: 0 8px;
color: rgb(255, 255, 255);
background:rgb(100, 100, 100);
selection-background-color: rgb(187, 187, 187);
selection-color: rgb(60, 63, 65);
}
执⾏程序观察效果.
代码⽰例: ⾃定义列表框
编写代码
QListView::item:hover {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FAFBFE, stop: 1 #DCDEF1);
}
QListView::item:selected {
border: 1px solid #6a6ea9;
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6a6ea9, stop: 1 #888dd9);
}
执⾏程序, 观察效果
代码⽰例: ⾃定义菜单栏
编写样式
QMenuBar {
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 lightgray, stop:1 darkgray);
spacing: 3px; /* spacing between menu bar items */
}
QMenuBar::item {
padding: 1px 4px;
background: transparent;
border-radius: 4px;
}
QMenuBar::item:selected { /* when selected using mouse or keyboard */
background: #a8a8a8;
}
QMenuBar::item:pressed {
background: #888888;
}
QMenu {
background-color: white;
margin: 0 2px; /* some spacing around the menu */
}
QMenu::item {
padding: 2px 25px 2px 20px;
border: 3px solid transparent; /* reserve space for selection border */
}
QMenu::item:selected {
border-color: darkblue;
background: rgba(100, 100, 100, 150);
}
QMenu::separator {
height: 2px;
background: lightblue;
margin-left: 10px;
margin-right: 5px;
}
执⾏程序, 观察效果
基于上述学习过的 QSS 样式, 制作⼀个美化版本的登录界⾯
把上述控件添加⼀个⽗元素 QFrame, 并设置 QFrame 和 窗⼝⼀样⼤.
创建 resource.qrc, 并导⼊图片,编写 QSS 样式.
使⽤ border-image
设置背景图⽚, ⽽不是 background-image
. 主要是因为 border-image
是可以⾃动缩放的. 这⼀点在窗⼝⼤⼩发⽣改变时是⾮常有意义的.
QFrame {
border-image: url(:/picture.jpg);
}
编写 QSS 代码
QLineEdit {
color: #8d98a1;
background-color: #405361;
padding: 0 5px;
font-size: 20px;
border-style: none;
border-radius: 10px;
}
背景⾊使⽤ transparent 表⽰完全透明 (应⽤⽗元素的背景).
QCheckBox {
color: white;
background-color: transparent;
}
设置按钮样式
QPushButton {
font-size: 20px;
color: white;
background-color: #555;
border-style: outset;
border-radius: 10px;
}
QPushButton:pressed {
color: black;
background-color: #ced1db;
border-style: inset;
}
最终完整样式代码. 这些代码设置到 QFrame 的属性中即可。通常我们建议把样式代码集中放置, ⽅便调整和排查
QFrame {
border-image: url(:/cat.jpg);
}
QLineEdit {
color: #8d98a1;
background-color: #405361;
padding: 0 5px;
font-size: 20px;
border-style: none;
border-radius: 10px;
}
QCheckBox {
color: white;
background-color: transparent;
}
QPushButton {
font-size: 20px;
color: white;
background-color: #555;
border-style: outset;
border-radius: 10px;
}
QPushButton:pressed {
color: black;
background-color: #ced1db;
border-style: inset;
}
虽然 Qt 已经内置了很多的控件, 但是不能保证现有控件就可以应对所有场景。很多时候我们需要更强的 “⾃定制” 能⼒。
Qt 提供了画图相关的 API, 可以允许我们在窗⼝上绘制任意的图形形状, 来完成更复杂的界⾯设计.
绘图 API 核⼼类
绘图 API 的使⽤, ⼀般不会在 QWidget 的构造函数中使⽤, ⽽是要放到 paintEvent 事件中.
因此, 如果把绘图 api 放到构造函数中调⽤, 那么⼀旦出现上述的情况, 界⾯的绘制效果就⽆法确保符合预期了.
void drawLine(const QPoint &p1, const QPoint &p2);
参数:
p1:绘制起点坐标
p2:绘制终点坐标
1、在 “widget.h” 头⽂件中声明绘图事件
2、在 “widget.cpp” ⽂件中重写 paintEvent() ⽅法
实现效果如下:
void QPainter::drawRect(int x, int y, int width, int height);
参数:
x:窗⼝横坐标;
y:窗⼝纵坐标;
width:所绘制矩形的宽度;
height:所绘制矩形的⾼度;
void QPainter::drawEllipse(const QPoint ¢er, int rx, int ry)
参数:
center:中⼼点坐标
rx:横坐标
ry:纵坐标
实现效果:
QPainter 在绘制时,是有⼀个默认的画笔的。在使⽤时也可以⾃定义画笔。在 Qt 中,QPen类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen类 可以设置画笔的线宽、颜⾊、样式、画刷等。
画笔的颜⾊可以在实例化画笔对象时进⾏设置,画笔的宽度是通过 setWidth() ⽅法进⾏设置,画笔的风格是通过setStyle()⽅法进⾏设置,设置画刷主要是通过 setBrush() ⽅法。
画笔的⻛格有:
⽰例:画笔的使⽤
实现效果如下: