13. 绘图和样式表¶
Qt 5中的图形主要通过命令式QPainter API或Qt的声明性UI语言Qt Quick及其场景图形后端来完成, Qt的图形功能还包括对打印的支持,以及对各种图像格式的加载和保存。
Qt GUI界面提供了OpenGL和OpenGL ES集成,2D图形,基本图像,字体和文本等类,使用这些类我们可以方便的绘制图形。本章将介绍下在窗口绘制二维图形以及控件的样式。
Qt的绘图可以使用相同的API在屏幕和打印设备上绘画, 并且主要基于 QPainter, QPaintDevice 和 QPaintEngine 类。
QPainter 用于执行绘制操作,可以看作是画家;
QPaintDevice 是二维空间的抽象,想象成画板,就是绘图设备,常见的绘图设备有QWidget、QPixmap、QPicture等;
QPaintEngine 提供了绘制器用来在不同类型的绘图设备上绘制的接口。
QPaintDevice 相关类的继承关系:
QWidget是所有界面组件的基类,常见的绘图设备。
QImage、QPixmap、QBitmap和QPicture这些类用于处理图像数据,其中QImage是针对I/O和直接像素访问和操作进行设计和优化的类;QPixmap是针对屏幕上显示的图像进行设计和优化的类; QBitmap是一个继承自QPixmap的便捷类,确保深度为1;QPicture类是一个绘画设备,可以记录和回放QPainter命令。
QSvgGenerator 是用于创建SVG图形的绘制设备,可缩放矢量图形(scalable vector graphics)是一种图片格式。
QOpenGLPaintDevice 是用于渲染到当前OpenGL(ES)2.0的绘制设备, QPainter将调用OpenGL绘制到QOpenGLPaintDevice实例。
QPagePaintDevice是支持多个页面的绘图设备类。
13.1. QPainter绘图¶
Qt的二维绘制功能是使用QPainter在绘图设备上绘制,提供了高度优化的功能,可以完成大多数图形GUI程序所需的功能, 它可以绘制从简单的线条到复杂的形状的所有内容,它还可以绘制对齐的文本和像素图。 通常,它在逻辑坐标系中绘制,但也可以进行逻辑坐标到物理坐标的转换。
QPainter可以对继承QPaintDevice类的任何对象进行操作。
QPainter的常见用法是在控件的绘画事件中:构造和自定义(例如,设置笔或画笔)Painter,然后进行图形绘制。
13.1.1. 基本概念¶
13.1.1.1. 绘图事件¶
QWidget类有一个事件处理函数paintEvent,当组件需要重新绘制时,系统会自动调用整函数。 QPainter的常见用途就是在窗口的绘画事件(paintEvent)中,在绘图事件处理函数中创建QPainter对象,然后使用这个QPainter在绘图设备上绘制。 例如:
void MainWindow::paintEvent(QPaintEvent *event)
{
// 创建与绘制设备关联的对象QPainter
QPainter painter(this);
// 绘制图形,先创建一个画笔,设置颜色等,然后在窗口中心绘制文本"LubanCat"
painter.setPen(Qt::red);
painter.drawText(rect(), Qt::AlignCenter, "LubanCat"); //绘制文本
}
QPainter类除了绘制图像,还可以自定义QPainter设置及其渲染质量,支持剪辑功能。此外,还可以通过指定QPainter的构图模式来控制不同形状如何合并在一起。
13.1.1.2. 颜色¶
Qt中的任何颜色都由支持RGB,HSV和CMYK颜色模型的QColor类表示。 通常使用 QColor RGB(R,G,B) 来指定颜色。 QColor还支持alpha混合轮廓和填充(指定透明效果), 并且该类与平台和设备无关(使用QColormap类将颜色映射到硬件)。
// Specify semi-transparent red
painter.setBrush(QColor(255, 0, 0, 127));
painter.drawRect(0, 0, width()/2, height());
// Specify semi-transparent blue
painter.setBrush(QColor(0, 0, 255, 127));
painter.drawRect(0, 0, width(), height()/2);
预定义的颜色
QColorConstants命名空间中有20个预定义的QColor对象, 包括黑色,白色,原色和辅助色,这些颜色的较暗版本以及三种灰度。
brush.setColor(Qt::blue);
pen.setColor(Qt::red);
13.1.1.3. 窗口坐标¶
我们通常用x轴y轴组成的平面坐标系来限定2D绘图,Qt中坐标系由QPainter类控制。
绘画设备的默认坐标系的原点位于左上角。该X值增加向右和ÿ值向下增加。 在基于像素的设备上,默认单位是一个像素。
逻辑QPainter坐标到物理QPaintDevice坐标的映射由QPainter的变换矩阵,视口和窗口处理所决定。 默认情况下,逻辑坐标系和物理坐标系重合。
13.1.1.4. 窗口和视口¶
在使用QPainter进行绘制时,我们使用逻辑坐标指定点,然后将其转换为绘画设备的物理坐标,也就是可以通过窗口和视口来设置组件大小位置。
视口是基于QPaintDevice类组件坐标实现,是物理坐标,可以通过setViewport()函数设置;窗口是基于自身的逻辑坐标,不是真实坐标,可以通过setWindow()函数设置。
逻辑坐标到物理坐标的映射由QPainter的world transformation worldTransform()以及QPainter的viewport()和window()处理。 视口表示指定任意矩形的物理坐标。“窗口”在逻辑坐标中描述相同的矩形。 默认情况下,逻辑坐标系和物理坐标系重合,相当于绘制设备的矩形。
使用窗口-视口转换,可以使逻辑坐标系符合您的首选项。该机制还可用于使绘图代码独立于绘图设备。 例如,可以通过调用QPainter::setWindow()函数使逻辑坐标从(-50,-50)扩展到(50,50),其中(0,0)位于中心:
QPainter painter(this);
qp->setWindow(QRect(-50, -50, 100, 100));
当QPainter初始化的时候,视口和窗口的坐标是一致的,通过上面setWindow函数设置,逻辑坐标(-50,-50)对应于绘图设备的物理坐标(0,0), 与绘画设备无关,绘画代码将始终在指定的逻辑坐标上运行。
13.1.2. 绘画相关类¶
13.1.2.1. QPen¶
QPen 类用于设置绘制时的线条特性,控制线条的颜色,宽度,线型等。
笔的宽度可以指定为整数(width())和浮点(widthF())精度,线宽为零表示修饰笔,这意味着笔的宽度始终绘制为一个像素宽,与QPainter上设置的变换无关。 使用*setColor()* , setWidth() 函数分别设置颜色和线宽。
PenStyle
QPen可以设置其线条样式, 通过setStyle()函数设置,参数是枚举类型Qt::PenStyle:
样式 |
值 |
描述 |
---|---|---|
Qt::NoPen |
0 |
完全没有线。例如,QPainter::drawRect()填充但不绘制任何边界线 |
Qt::SolidLine |
1 |
一条简单的宽线 |
Qt::DashLine |
2 |
短划线隔开几个像素,虚线 |
Qt::DotLine |
3 |
点分开几个像素,点划线 |
Qt::DashDotLine |
4 |
交替的点和破折号 |
Qt::DashDotDotLine |
5 |
一个破折号,两个点,一个破折号,两个点 |
Qt::CustomDashLine |
6 |
使用QPainterPathStroker::setDashPattern()定义的自定义模式 |
除了上面基本的样式,用户还可以自定义线条样式,需要使用函数setDashOffset(qreal offset)和setDashPattern(const QVector<qreal> &pattern)函数。
PenCapStyle
使用函数setCapStyle()设置线条的端点样式,参数是枚举Qt::PenCapStyle,它仅适用于宽线(宽度为1或更大)。 在Qt的 Qt:: PenCapStyle 枚举提供了以下样式:
样式 |
值 |
描述 |
---|---|---|
Qt::FlatCap |
0x00 |
一个方形的线条端,不覆盖线条的端点 |
Qt::SquareCap |
0x10 |
一个方形的线条端,覆盖线条的端点并延伸1/2的线宽长度 |
Qt::RoundCap |
0x20 |
一个圆角的线条端 |
PenJoinStyle
线条连接样式定义了如何使用QPainter绘制两条连接线之间的连接。连接样式仅适用于宽线(宽度为1或更大)。 在Qt的 Qt:: PenJoinStyle 枚举提供了以下样式,setJoinStyle()设置:
样式 |
值 |
描述 |
---|---|---|
Qt::MiterJoin |
0x00 |
线连接的外边缘延伸成一定角度相交,并填充 |
Qt::BevelJoin |
0x40 |
两条线之间的三角形缺口,直接用线连接填充 |
Qt::RoundJoin |
0x80 |
连接之间缺口,用圆弧连接填充 |
Qt::SvgMiterJoin |
0x100 |
与SVG 1.2 Tiny规范中的斜接定义相对应的斜接 |
13.1.2.2. QBrush¶
QBrush对象用于设置QPainter绘制时一个区域的填充效果,具有样式,颜色,渐变和纹理等属性。
QBrush使用setColor()设置笔刷颜色,setStyle()设置笔刷样式,setTexture()设置图片作为笔刷。
笔刷样式使用 Qt::BrushStyle 枚举定义填充图案,Qt支持的画笔样式如下:
样式 |
值 |
描述 |
---|---|---|
Qt::NoBrush |
0 |
没有画笔图案 |
Qt::SolidPattern |
1 |
颜色均匀,单一颜色填充 |
Qt::Dense1Pattern |
2 |
极其密集的画笔图案 |
Qt::Dense2Pattern |
3 |
非常密集的画笔图案 |
Qt::Dense3Pattern |
4 |
有点密集的画笔图案 |
Qt::Dense4Pattern |
5 |
半密实的画笔图案 |
Qt::Dense5Pattern |
6 |
有点稀疏的画笔图案 |
Qt::Dense6Pattern |
7 |
非常稀疏的画笔图案 |
Qt::Dense7Pattern |
8 |
极稀疏的画笔图案 |
Qt::HorPattern |
9 |
水平线填充 |
Qt::VerPattern |
10 |
垂直线填充 |
Qt::CrossPattern |
11 |
跨越水平和垂直线 |
Qt::BDiagPattern |
12 |
向后的对角线 |
Qt::FDiagPattern |
13 |
向前的对角线 |
Qt::DiagCrossPattern |
14 |
交叉对角线 |
Qt::LinearGradientPattern |
15 |
线性渐变(使用专用的QBrush构造函数设置) |
Qt::ConicalGradientPattern |
17 |
锥形渐变(使用专用的QBrush构造函数设置) |
Qt::RadialGradientPattern |
16 |
辐射形渐变(使用专用的QBrush构造函数设置) |
Qt::TexturePattern |
24 |
自定义填充(请参阅QBrush::setTexture()函数) |
其效果如下:
13.1.2.3. QGradient¶
QGradient 和QBrush组合使用,可以实现包括从均匀颜色到非常稀疏的图案的基本图案,各种线条组合,渐变填充和纹理等等效果。
Qt提供了三种渐变填充类:QLinearGradient,QConicalGradient和QRadialGradient,这三种都继承自QGradient。
QLinearGradient 是线性渐变,指定一个起点和颜色,一个终点和颜色,起点到终点的颜色按线性插值计算,得到渐变的填充颜色。 其中,还可以知道中间点的颜色。
QRadialGradient 是辐射形渐变,有简单的辐射渐变和扩展的辐射渐变两种方式,简单的方式是在圆内一个焦点和一个端点之间渐变, 扩展辐射是在一个焦点圆和一个中心圆之间渐变。
QConicalGradient 是圆锥渐变,围绕一个中心点逆时针渐变。
三种渐变的效果:
13.1.3. QPainter绘图基础图形¶
QPainter提供了许多接口用于绘制基础图像,包括点,直线,椭圆等,每个接口函数 都有很多参数形式,下面将简单介绍下这些函数。
13.1.3.1. drawPoint¶
绘制点函数原型:
void QPainter::drawPoint(const QPointF &position)
示例程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //绘制点
void MainWindow::myDrawPoints(QPainter *qp)
{
qp->setPen(QColor(255,0,0));
qp->setBrush(QColor(255,0,0));
QPolygonF points;
for(int i=0; i<10; i++)
for(int j=0; j<10; j++)
{
qp->drawPoint(QPoint(305+i*10,110+j*10)); //绘制单个点,在指定位置
points.append(QPoint(405+i*10,110+j*10));
}
qp->setPen(QColor(0,0,255)); //重新设置颜色
qp->setBrush(QColor(0,0,255)); //重新设置填充颜色
qp->drawPoints(points); //批量绘制点
}
|
13.1.3.2. drawLine¶
绘制直线,函数原型(更多重载函数看下Qt帮助手册):
void QPainter::drawLine(const QLineF &line)
void QPainter::drawLines(const QLineF *lines, int lineCount)
示例程序:
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 | void MainWindow::myDrawLines(QPainter *qp)
{
QPen pen;
//画直线
pen.setWidth(5);
pen.setStyle(Qt::SolidLine); //宽线
pen.setCapStyle(Qt::SquareCap); //端点样式是方形线条端
qp->setPen(pen);
qp->drawLine(QPointF(5, 110), QPointF(195, 110));
pen.setStyle(Qt::DashLine); //虚线
// pen.setColor(QColor(255, 0, 0));
qp->setPen(pen);
qp->drawLine(QPointF(5, 130), QPointF(195, 130));
pen.setStyle(Qt::DotLine);
pen.setCapStyle(Qt::FlatCap);
qp->setPen(pen);
qp->drawLine(QPointF(5, 150), QPointF(195, 150));
pen.setStyle(Qt::DashDotLine);
// pen.setColor(QColor(255, 255, 0));
qp->setPen(pen);
qp->drawLine(QPointF(5, 170), QPointF(195, 170));
pen.setStyle(Qt::DashDotDotLine);
pen.setCapStyle(Qt::RoundCap);
qp->setPen(pen);
qp->drawLine(QPointF(5, 190), QPointF(195, 190));
pen.setStyle(Qt::CustomDashLine);
pen.setWidth(2);
qp->setPen(pen);
qp->drawLine(QPointF(5, 210), QPointF(195, 210));
}
|
13.1.3.3. drawRect¶
绘制矩形,函数原型:
void QPainter::drawRect(const QRectF &rectangle)
示例程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void MainWindow::myDrawRect(QPainter *qp)
{
QPen pen;
QBrush brush;
//画矩形,有填充矩形
pen.setColor(QColor(255, 0, 0));
brush.setStyle(Qt::SolidPattern);
brush.setColor(QColor(0, 255, 0, 125));
qp->setPen(pen);
qp->setBrush(brush);
qp->drawRect(505, 110, 90, 90);
//画矩形,无填充矩形
pen.setStyle(Qt::SolidLine);
pen.setColor(QColor(255, 0, 0));
brush.setStyle(Qt::NoBrush);
qp->setPen(pen);
qp->setBrush(brush);
qp->drawRect(605, 110, 90, 90);
}
|
13.1.3.4. drawRoundedRect¶
绘制圆角的矩形,函数原型:
void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize)
示例程序:
1 2 | QRectF rectangle(705.0, 110.0, 90.0, 90.0);
qp->drawRoundedRect(rectangle, 20.0, 20.0);
|
13.1.3.5. drawEllipse¶
绘制圆,函数原型:
void QPainter::drawEllipse(const QRectF &rectangle)
示例程序:
1 2 3 4 5 | //椭圆
qp->drawEllipse(QRectF(305,220,90,60));
//圆
qp->drawEllipse(QRectF(405,210,90,90));
|
13.1.3.6. drawArc¶
绘制弧线,函数原型:
void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
示例程序:
1 2 3 | int startAngle = 30 * 16;//起始角度
int spanAngle = 120 * 16;//跨越度数
qp->drawArc(QRectF(5.0, 210.0, 90.0, 90.0), startAngle, spanAngle);
|
13.1.3.7. drawPie¶
绘制扇形,函数原型:
void QPainter::drawPie(const QRectF &rectangle, int startAngle, int spanAngle)
示例程序:
1 2 3 | int startAngle = 30 * 16;//起始角度
int spanAngle = 120 * 16;//跨越度数
qp->drawPie(QRectF(105.0, 210.0, 90.0, 90.0), startAngle, spanAngle);
|
13.1.3.8. drawChord¶
绘制带弦的弧,函数原型:
void QPainter::drawChord(const QRectF &rectangle, int startAngle, int spanAngle)
示例程序:
1 2 3 | int startAngle = 30 * 16;//起始角度
int spanAngle = 120 * 16;//跨越度数
qp->drawChord(QRect(205, 210, 90, 90), startAngle, spanAngle);
|
13.1.3.9. drawPolyline¶
绘制折线,函数原型:
void QPainter::drawPolyline(const QPointF *points, int pointCount)
示例程序:
1 2 3 4 5 6 7 8 | QPointF Polylinepoints[5] = {
QPointF(505.0, 210.0),
QPointF(555.0, 290.0),
QPointF(535.0, 275.0),
QPointF(595.0, 295.0),
QPointF(505.0, 215.0),
};
qp->drawPolyline(Polylinepoints, 5);
|
13.1.3.10. drawConvexPolygon¶
绘制多边形,函数原型:
void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule = Qt::OddEvenFill)
示例程序:
1 2 3 4 5 6 7 | QPointF Polygonpoints[4] = {
QPointF(610.0, 280.0),
QPointF(620.0, 210.0),
QPointF(680.0, 230.0),
QPointF(690.0, 270.0),
};
qp->drawConvexPolygon(Polygonpoints, 4);
|
13.1.3.11. 渐变¶
绘制多边形,函数原型:
void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule = Qt::OddEvenFill)
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 | void MainWindow::myDrawGradient(QPainter *qp)
{
//线性渐变
QLinearGradient linearGradient(QPointF(40, 190), QPointF(70, 190));
linearGradient.setColorAt(0, Qt::yellow);
linearGradient.setColorAt(0.5, Qt::red);
linearGradient.setColorAt(1, Qt::green);
linearGradient.setSpread(QGradient::RepeatSpread);
qp->setBrush(linearGradient);
qp->drawRect(5, 310, 90, 90);
//辐射渐变
QRadialGradient radialGradient(QPointF(150, 350),40,QPointF(550,40));
radialGradient.setColorAt(0, QColor(255, 255, 100, 150));
radialGradient.setColorAt(1, QColor(0, 0, 0, 50));
qp->setBrush(radialGradient);
qp->drawEllipse(QPointF(150, 350), 40, 40);
//锥形渐变
QConicalGradient conicalGradient(QPointF(250, 350), 100);
conicalGradient.setColorAt(0.2, Qt::cyan);
conicalGradient.setColorAt(0.9, Qt::black);
qp->setBrush(conicalGradient);
qp->drawEllipse(QPointF(250, 350), 40, 40);
}
|
13.1.3.12. 文字¶
绘制文字,函数原型:
void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule = Qt::OddEvenFill)
示例程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void MainWindow::myDrawText(QPainter *qp)
{
//设置一个矩形
QRectF rect(305, 310, 190, 90);
qp->drawRect(rect);
qp->setPen(QColor(Qt::red));
qp->drawText(rect, Qt::AlignHCenter, "野火电子");
//绘制文字
QFont font("宋体", 10, QFont::Bold, true);
font.setLetterSpacing(QFont::AbsoluteSpacing,5);
qp->setFont(font);
qp->drawText(310, 350, "Qt 嵌入式教程");
//绘制文字
qp->setPen(Qt::green);
font.setLetterSpacing(QFont::AbsoluteSpacing,0);
font.setBold(false);
font.setFamily("黑体");
font.setPointSize(10);
font.setItalic(true);
qp->setFont(font);
qp->drawText(310, 380, "绘制文字");
}
|
13.1.3.13. QPainterPath¶
QPainterPath类为绘制操作提供了一个容器,使绘制图形能够被构建和重用,函数原型:
void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule = Qt::OddEvenFill)
示例程序:
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 | void MainWindow::myDrawPath(QPainter *qp)
{
//简单的使用QPainterPath,使绘制图形能够被构建和重用
QPainterPath path1;
path1.addEllipse(510, 320, 50, 50); //绘制一个圆
path1.lineTo(505, 380); //绘制一直线
qp->setPen(Qt::blue);
qp->setBrush(Qt::red); //填充红色
qp->drawPath(path1);
//复制图形
QPainterPath path2;
path2.addPath(path1);
path2.translate(70,0);
qp->drawPath(path2);
//绘制线
QPainterPath path4;
qp->setBrush(Qt::transparent);
path4.lineTo(0,105);
path4.lineTo(this->width(),105);
path4.lineTo(this->width(),205);
path4.lineTo(0,205);
path4.lineTo(0,305);
path4.lineTo(this->width(),305);
path4.lineTo(this->width(),405);
path4.lineTo(0,405);
qp->drawPath(path4);
}
|
13.1.3.14. 图片处理¶
绘制图片,函数原型:
void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule = Qt::OddEvenFill)
1 2 3 4 5 6 7 8 | //简单绘制图片
QPixmap pix;
pix.load(":/image/test.png");
painter.drawPixmap(650, 305, 25, 25, pix);
//缩放
pix = pix.scaled(pix.width()*2, pix.height()*2,Qt::KeepAspectRatio);
painter.drawPixmap(650, 330, pix);
|
13.2. QSS¶
在Web开发中, CSS(层叠样式表) 主要用来设计网页的样式,美化网页; 它不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。 CSS能够对网页中元素位置的排版进行像素级精确控制,可以有效地对页面的布局、字体、颜色、背景和其它效果实现更加精确的控制, 拥有对网页对象和模型样式编辑的能力。
在Qt中也引入了类似的概念,可以称之为 QSS (Qt Style Sheets, Qt样式表),它可以定义界面的组件样式,使界面程序呈现特殊的显示效果。
13.2.1. QSS语句格式¶
Qt样式表的句法与HTML CSS的规则几乎相同。QSS中包含一系列的样式规则, 样式规则由一个选择器(selector)和一个声明(declaration )组成。选择器指定哪些小部件受规则影响;声明指定应该在小部件上设置哪些属性。例如:
QPushButton { color: red; background-color: white }
其中QPushButton是选择器,{ color: red; background-color: white }是声明,声明中的每条样式规则由属性和值组成,即 property: value
, 每条样式以分号隔开。
例如声明中的 color: red;
表示color属性,值为red。
Qt样式表支持各种属性、伪状态和子控件,使自定义小部件的外观成为可能,关于样式表属性可以参考下:https://doc.qt.io/qt-5/stylesheet-reference.html
13.2.1.1. 选择器¶
到目前为止,所有的示例都使用了最简单的选择器类型,即类型选择器。Qt样式表支持CSS2中定义的所有选择器,下表总结了最有用的选择器类型(以QPushButton示例):
选择器 |
示例 |
描述 |
---|---|---|
通用选择器 |
所有组件 |
|
类型选择器 |
QPushButton |
所有QPushButton类及其子类的组件 |
属性选择器 |
QPushButton[flat=false] |
匹配flat属性为false的QPushButton类及其子类的组件,也可以使用动态属性 |
非子类选择器 |
|
所有QPushButton类的组件,但是不包括 OPushButton 的子类 |
ID选择器 |
|
对象名称为 btnOK的OPushButton实例 |
从属对象选择器 |
QDialog QPushButton |
匹配从属于QDialog的 QPushButton类的实例 |
子对象选择器 |
QDialog > QPushButton |
所有直接从属于ODialog的OPushButton类的实例 |
选择器可以包含伪状态,伪状态表示基于小部件的状态限制规则的应用。伪状态出现在选择器的末尾,中间有一个冒号(:)。例如下面按鼠标的状态:
:hover 鼠标移动到控件上
:pressed 鼠标按下
:checked 鼠标点击
:release 鼠标抬起
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 | QToolButton{
border-image: url(:/resource/image/light/6-social-person.png);
border-style: flat;
border-radius:5px;padding:2px 4px;
}
# 鼠标移动到控件上时
QToolButton:hover{
border-image: url(:/resource/image/dark/6-social-person.png);
border-radius:5px;padding:2px 4px;
}
# 鼠标按下时
QToolButton:pressed{
border-image: url(:/resource/image/light/6-social-person.png);
border-style: flat;
border-radius:5px;padding:2px 4px;
}
# 鼠标点击时
QToolButton:checked{
border-image: url(:/resource/image/light/6-social-person.png);
border-radius:5px;padding:2px 4px;
}
# 鼠标释放时
QToolButton:release{
border-image: url(:/resource/image/light/6-social-person.png);
border-radius:5px;padding:2px 4px;
}
|
这样就可以通过QSS来控制按键不同状态显示不同的样式。
关于选择器更多的规则,比如子控件、冲突解决、级联等等,可以参考下https://doc.qt.io/qt-5/stylesheet-syntax.html
13.2.2. 样式表使用¶
Qt Designer中集成了QSS的编辑功能,在Qt Designer界面我们右击选中组件,在弹出的窗口选择 更改样式表...
,就可以弹出样式表编辑对话框。
这样样式表会自动保存在UI文件中,创建窗口时会自动调用。
也可以直接使用函数setStyleSheet()设置样式表,例如:
1 | qApp->setStyleSheet("QLineEdit { background-color: yellow }");
|
这里使用全局变量qApp为QLineEdit设置样式,设置背景颜色为黄色。
13.2.2.1. 属性¶
在使用CSS或QSS时,使用样式表可以定义复杂的显示效果,每个界面组件具有四个同心矩形的框(box model,盒子模型):边距矩形,边框矩形,填充矩形和内容矩形。
Content(内容) 控件的内容区域,显示文本和图像。
Padding(填充) 包围内容的区域,填充也是透明的。
Border(边框) 围绕在内边距和内容外的边框。
Margin(边距) 清除边框外的区域,边距是透明的,与父组件的之间的空白边距。
在使用QSS的时候,我们可以通过特定的属性来控制上述四个盒子的样式,从而使控件呈现出我们想要的效果。 比如说margin,分别定义了上下左右四个边距大小:
margin-top 上边距。
margin-right 右边距。
margin-bottom 底边距。
margin-left 左边距。
我们完全可以通过指定上下左右边距的值来实现下面的效果:
除了上面,常见的属性比如background,是用来设置背景,其中又可以细分如下:
background-color 背景颜色
background-image 背景图像
background-repeat 背景图像的填充方式
background-position 背景图片的对齐方式
background-attachment 背景图像是相对于视口滚动还是固定的
background-clip background-color和background-image被剪切到的矩形
background-origin 背景矩形,与background-position和结合使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | QPushButton {
color: rgb(206, 246, 223);
background-color:rgb(18, 210, 100);
border-radius:20px;padding:10px 40px;
}
QPushButton :pressed{
color: rgb(206, 246, 223);
background-color:rgba(18, 216, 105, 5);
border-radius:20px;padding:10px 40px;
}
|
例如在示例中,我们对控件设置如上面的样式,其中设置控件的背景颜色(background-color)为rgba(18, 216, 105, 5), 文字颜色(color)为rgb(206, 246, 223),并通过border-radius设置控件显示为圆角。
Qt中支持的属性可参考下: https://doc.qt.io/qt-5/stylesheet-reference.html#list-of-properties 。
样式表详细的描述和使用使用参考下: https://doc.qt.io/qt-5/stylesheet-customizing.html 。
13.3. 例程说明¶
本章配套例程在 lubancat_qt_tutorial_code/Graphics 目录下
例程中包含两个示例demo,QtPainter和QSS,QtPainter演示了Qt 2D绘图,QSS则演示了在Qt中使用样式表
13.3.1. 编程思路¶
QtPainter
新建空白工程
Qt绘图事件 paintEvent()
在paintEvent()中绘制各种2D图形
QSS
使用Qt Designer 模仿360界面,对控件进行布局
使用QSS控制控件样式,最终达到相近的效果
13.3.2. 主要代码讲解¶
绘图和QSS代码在前面都有讲解,这里讲一下如何实现点击窗口任意位置都可拖动窗口。 实现思路如下:
当鼠标按下时,接收鼠标按下事件,记录下鼠标和窗口的初始位置; 按下过程中,移动鼠标会产生鼠标移动事件,根据鼠标和窗口的相对位置,移动窗口; 松开鼠标时,会产生鼠标抬起事件,窗口移动结束。
1 2 3 4 5 6 | bool windowsDrag;
QPoint mouseStartPoint;
QPoint windowTopLeftPoint;
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
|
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 | //拖拽操作
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
windowsDrag = true;
//获得鼠标的初始位置
mouseStartPoint = event->globalPos();
//mouseStartPoint = event->pos();
//获得窗口的初始位置
windowTopLeftPoint = this->frameGeometry().topLeft();
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(windowsDrag)
{
//获得鼠标移动的距离
QPoint distance = event->globalPos() - mouseStartPoint;
//QPoint distance = event->pos() - mouseStartPoint;
//改变窗口的位置
this->move(windowTopLeftPoint + distance);
}
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
windowsDrag = false;
}
}
|