前面一章我们提到,Qt 绘图系统定义了两个绘制时使用的关键属性:画刷和画笔。前者使用QBrush
描述,大多用于填充;后者使用QPen
描述,大多用于绘制轮廓线。
QBrush
定义了QPainter
的填充模式,具有样式、颜色、渐变以及纹理等属性。
画刷的style()
定义了填充的样式,使用Qt::BrushStyle
枚举,默认值是Qt::NoBrush
,也就是不进行任何填充。我们可以从下面的图示中看到各种填充样式的区别:

画刷的color()
定义了填充模式的颜色。这个颜色可以是 Qt 预定义的颜色常量,也就是Qt::GlobalColor
,也可以是任意QColor
对象。
画刷的gradient()
定义了渐变填充。这个属性只有在样式是Qt::LinearGradientPattern
、Qt::RadialGradientPattern
或者Qt::ConicalGradientPattern
之一时才有效。渐变可以由QGradient
对象表示。Qt 提供了三种渐变:QLinearGradient
、QConicalGradient
和QRadialGradient
,它们都是QGradient
的子类。我们可以使用如下代码片段来定义一个渐变的画刷:
QRadialGradient gradient(50, 50, 50, 50, 50); gradient.setColorAt(0, QColor::fromRgbF(0, 1, 0, 1)); gradient.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); QBrush brush(gradient);
当画刷样式是 Qt::TexturePattern
时,texture()
定义了用于填充的纹理。注意,即使你没有设置样式为Qt::TexturePattern
,当你调用setTexture()
函数时,QBrush
会自动将style()
设置为Qt::TexturePattern
。
QPen
定义了用于QPainter
应该怎样画线或者轮廓线。画笔具有样式、宽度、画刷、笔帽样式和连接样式等属性。画笔的样式style()
定义了线的样式。画刷brush()
用于填充画笔所绘制的线条。笔帽样式capStyle()
定义了使用QPainter
绘制的线的末端;连接样式joinStyle()
则定义了两条线如何连接起来。画笔宽度width()
或widthF()
定义了画笔的宽。注意,不存在宽度为 0 的线。假设你设置 width 为 0,QPainter
依然会绘制出一条线,而这个线的宽度为 1 像素。也就是说,画笔宽度通常至少是 1 像素。
这么多参数既可以在构造时指定,也可以使用 set 函数指定,完全取决于你的习惯,例如:
QPainter painter(this); QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin); painter.setPen(pen);
等价于
QPainter painter(this); QPen pen; // creates a default pen pen.setStyle(Qt::DashDotLine); pen.setWidth(3); pen.setBrush(Qt::green); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); painter.setPen(pen);
使用构造函数的优点是代码较短,但是参数含义不明确;使用 set 函数则正好反过来。
默认的画笔属性是纯黑色,0 像素,方形笔帽(Qt::SquareCap
),斜面型连接(Qt::BevelJoin
)。
下面是画笔样式的示例:

你也可以使用setDashPattern()
函数自定义样式,例如如下代码片段:
QPen pen; QVector<qreal> dashes; qreal space = 4; dashes << 1 << space << 3 << space << 9 << space << 27 << space << 9 << space; pen.setDashPattern(dashes);
笔帽定义了画笔末端的样式,例如:

他们之间的区别是,Qt::SquareCap
是一种包含了最后一个点的方形端点,使用半个线宽覆盖;Qt::FlatCap
不包含最后一个点;Qt::RoundCap
是包含最后一个点的圆形端点。具体可以参考下面的示例(出自《C++ GUI Programming with Qt 4, 2nd Edition》):

连接样式定义了两条线连接时的样式,例如:

同样,可以参考下面图示来理解这几种连接样式的细节(出自《C++ GUI Programming with Qt 4, 2nd Edition》):

注意,我们前面说了,QPainter
也是一个状态机,这里我们所说的这些属性都是处于这个状态机之中的,因此,我们应该记得是否要将其保存下来或者是重新构建。
23 评论
学习了, 我正在想着弄个平铺背景呢
QVariant(Qt::GlobalColor) Q_DECL_EQ_DELETE;
QVariant(Qt::BrushStyle) Q_DECL_EQ_DELETE;
QVariant(Qt::PenStyle) Q_DECL_EQ_DELETE;
QVariant(Qt::CursorShape) Q_DECL_EQ_DELETE;
看Qt5,把这几个还有其它的QVariant自动转换给去掉了。而从http://qt-project.org/doc/qt-5.0/painting-basicdrawing.html这里的例子看都是手动static_cast的,不知为什么要这么做?
按照代码注释:These constructors don't create QVariants of the type associcated with the enum, as expected, but they would create a QVariant of type int with the value of the enum value. Use QVariant v = QColor(Qt::red) instead of QVariant v = Qt::red for example. 我的理解是,如果不禁用这几个构造函数,QVariant 会将这些枚举当做普通的 int,而实际这些枚举是有自己的含义的,例如,Qt::GlobalColor 其实代表一个 QColor 对象。这样的话,可能会有隐藏的 bug,因为 Qt::GlobalColor 会退化为一个普通的 int。所以,Qt 5 将这些有特殊含义的枚举的构造函数禁止掉了。
http://qt-project.org/doc/qt-5.0/painting-basicdrawing.html
但是像这个例子,把它手动转换为static_cast了。那不是在QVariant里还是存为int。取出来时还是手动static_cast才行。
这个例子里面,之所以转换成 int,是因为它仅是作为 QComboBox 一个项的 value 使用,没必要存储一个完整的 QBrush 对象而占用内存空间。当然,你也可以当做 QBrush 存储,这只是一个例子而已,你可以选择自己的实现。
Errata:
setDashPattern():===>
QPen pen;
QVector dashes;//
qreal space = 4;
dashes << 1 << space << 3 << space << 9 << space
<< 27 << space << 9 << space;
pen.setDashPattern(dashes);
我也是这里编译不通过
错误提示:
C:\Users\linxiaotao1993\Desktop\Qt\untitled\mainwindow.cpp:23: 错误:missing template arguments before 'dashes'
QVector dashes;
^
查了一下
把QVector dashes; 改成 QVector dashes;
就可以了
页面将模板参数过滤掉了,已经修改过
我想制作一个时间轴,就是一个以时间为刻度的轴,把相关项目按照时间刻度排放在轴的两边,并且可以通过拖动改变其时间,请问使用什么方法比较好?在网上看了一些说使用qwt比较方便,但是不是很会,请问您有何高见
QWT 应该是不错的选择,既然你要绘制坐标轴,很有可能还有其它的图标,比如线图、饼图之类,QWT 就是这类图库。如果你要全部自己绘制,需要计算一些数据。所以如果项目的确是这种统计图形,为开发方便起见,最好考虑研究一下 QWT。如果 QWT 还是无法满足要求,再考虑自己实现吧。
豆子老师,还想再问你一个问题,就是:
QBrush brush(gradient);
/*。。。*/
painter.setBrush(brush);
//为什么文档里写这里需要一个QBrush*类型的参数,可是直接用brush就可以呢?
QPainter 的 setBrush() 函数接受一个 QBrush 类型,可能是你看错参数类型了吧?
豆子大大,我想问下现在我需要在QtextEdit下画点,这个文本文档是在主窗口下的一个控件,利用QPaint能不能实现?请教下,谢谢!
这段代码什么意思
dashes << 1 << space << 3 << space << 9 << space
<< 27 << space << 9 << space;
请教
setDashPattern() 函数需要一个包含偶数个元素的列表,这段代码就是为了构建这个列表。具体来说,这个数组包含偶数个元素,其中,奇数位置的元素代表线段长度;偶数位置的元素代表间隔长度。可以查看 setDashPattern() 函数的文档。
怎么实现画笔的绘制功能,就是点着鼠标左键不松,移动鼠标绘制图形,松掉鼠标左键,结束绘制。
这种做法一般是在 mousePressEvent() 事件中记录下起始坐标,然后在 mouseMoveEvent() 中实时修改终点坐标,不停绘制图形,然后在 mouseReleaseEvent() 中获得最终坐标,然后绘制最终图形
大大我想问一下为什么我的QPainter painter(this);以及QPen pen中的painter和pen的地方会报错啊?
是报什么错误呢?
请问大神,painter.setBrush(Qt::red),参数传入的是颜色,而该函数的形参类型应该是Qt::BrushStyle,为什么可以这样用呢?我看Qt原码里也没有对参数进行判断,是发生了什么隐式转换吗?麻烦您啦,谢谢您。
setBrush()
有两个重载,参数类型分别是QBrush
和Qt::BrushStyle
;而QBrush
有很多构造函数,其中就有QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style = Qt::SolidPattern)
。当传入Qt::GlobalColor
(即文中的Qt::red
)时,C++ 会尝试使用这个参数去创建对应的QBrush
实例(如果创建失败就会报错),这样就可以满足setBrush()
了。