一、QT绘图原理
Qt4中的2D绘图系统称为Arthur绘图系统,可以使用相同的API在屏幕上和绘图设备上进行绘制,主要基于QPainter、QPainterDevice和 QPainterEngine。QPainter执行绘图操作,QPainterDevice提供绘图设备,是一个二维空间的抽象,QPainterEngine提供一些接口。QPainter用来执行具体的绘图相关操作,如画点,画线,填充,变换,alpha通道等。QPaintDevice类是能够进行绘图的对象的基类,QWidget,QPixmap,QPicture,QImage,以及QPrinter类继承了QPaintEngine类的绘图能力,QPainter类可以在一切继承QPainterDevice的子类上进行绘制操作。
QT中Arthur绘图框架中的基本绘图元素是画笔,画刷。
QPainter类具有GUI程序需要的绝大多数函数,能够绘制基本图形(点,线,矩形,多边形等)以及复杂的图形(如绘图路径)。使用绘图路径(QPaintPath)的优点是复杂形状的图形只用生成一次,再使用的时候只需要调用QPainter::drawPath()就可以绘制。QPainterPath对象可以用来填充,绘制轮廓。
线和轮廓都可以用画笔(QPen)进行绘制,画刷(QBrush)进行填充。画笔定义风格(线形),宽度,笔尖画刷以及端点是如何绘制的(cap-style),端点的连接方式(join-style)。画刷用来填充画笔绘制的图形,可以定制不同的填充模式和颜色的画刷。
当绘制文字时,字体使用QFont类定义,Qt使用指定字体的属性,如果没有匹配的字体,Qt将使用最接近的字体。字体属性可以通过QFontInfo来获取。字体的度量(measurement)使用QFontMetrics类来获取。QFontDatabase类可以获得底层窗口系统所有可用的字体。
通常情况下QPainter以默认的坐标系统进行绘制,也可以用QMatrix类对坐标进行变换。
当绘制时,可以使用QPainter::SetRenderHint函数设置绘图引擎是否启用反锯齿功能使图变得平滑。
QPainter::Antialiasing尽可能进行边的反锯齿绘制
QPainter::TextAntialiasing 尽可能进行文字的反锯齿绘制
QPainter::SmoothPixmapTransform 使用平滑的pixmap变换算法(双线性插值算法),而不是近邻插值算法
1、重写重绘事件处理函数实现绘图
重绘事件处理函数:
void QWidget::paintEvent ( QPaintEvent * event )
基础部件类Qwidget提供的paintEvent函数,是纯虚函数;Qwidget的子类要使用paintEvent函数必须重新实现。在三种情况会发生重绘事件调用paintEvent函数:
A、当窗口部件第一次显示时,系统会自动产生一个绘图事件
B、repaint()与update()函数被调用时
C、当窗口部件被其他部件遮挡,然后又再次显示出来时,就会对隐藏的区域产生一个重绘事件
D、重新调整窗口大小时
2、通过事件过滤器实现重绘
二、绘图工具
绘图时需要先定义一个QPainter类对象,绘图工具可以使Qpen(画笔)和QBrush(画刷)。Qpen(画笔)来绘制轮廓线,QBrush(画刷)用来填充,使用QPen写文本时还可以指定字体(QFont类)。
1、QPen画笔
画笔的属性包括线型,线宽,颜色等。
A、QPen主要成员函数如下:
QPen(Qt::PenStyle style)
QPen(const QColor & color)
QPen(const QBrush & brush, qreal width, Qt::PenStyle style = Qt::SolidLine, Qt::PenCapStyle cap = Qt::SquareCap, Qt::PenJoinStyle join = Qt::BevelJoin)
QPen(const QPen & pen)
void setBrush(const QBrush & brush)
void setCapStyle (Qt::PenCapStyle style)
void setColor (const QColor & color)
void setJoinStyle (Qt::PenJoinStyle style)
void setWidth (int width)
画笔的属性可以在构造函数中指定,也可以使用setStyle(),setWidth(),setBrush(),setCapStyle(),setJoinStyle()等函数设定画笔的各项属性。Qt中使用Qt::PenStyle定义了6种画笔风格,分别是Qt::SolidLine,Qt::DashLine,Qt::DotLine,Qt::DashDotLine,Qt::DashDotDotLine,Qt::CustomDashLine。自定义线风格(Qt::CustomDashLine),需要使用QPen的setDashPattern()函数来设定自定义风格。
画笔的设置代码如下:
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);
B、画笔风格
画笔风格使用Qt::PenStyle枚举定义。
C、画笔的端点风格( Qt::PenCapStyle)
画笔端点风格决定了线的端点样式,只对线宽大于1的线有效。Qt使用枚举定义了三种端点风格,分别为Qt::SqureCap,QT::FlatCap,Qt::RoundCap。
D、画笔连接风格(Qt::PenJoinStyle)
画笔连接风格是两条线如何连接,连接风格对线宽大于等于1的线有效。Qt使用枚举定义了四种连接类型,分别是Qt::MiterJoin,Qt::BevelJoin,Qt::RoundJoin,Qt::SvgMiterJoin。
2、QBrush画刷
在Qt中图形使用QBrush进行填充,画刷包括填充颜色和填充模式(风格)。
A、QBrush主要成员函数
QBrush(Qt::BrushStyle style)
QBrush(const QColor& color,Qt::BrushStyle style = Qt::SolidPattern)
QBrush(Qt::GlobalColor color,Qt::BrushStyle style = Qt::SolidPattern)
QBrush(const QColor & color, const QPixmap & pixmap)
QBrush(Qt::GlobalColor color, const QPixmap & pixmap)
QBrush(const QPixmap & pixmap)
QBrush(const QImage & image)
QBrush(const QBrush & other)
QBrush(const QGradient & gradient)
const QColor &color() const
const QGradient *gradient() const
const QMatrix &matrix() const
void setColor(const QColor & color)
void setColor(Qt::GlobalColor color)
void setMatrix(const QMatrix & matrix)
void setStyle(Qt::BrushStyle style)
void setTexture(const QPixmap & pixmap)
void setTextureImage(const QImage & image)
void setTransform(const QTransform & matrix)
Qt::BrushStyle style() const
QPixmap texture() const
QImage textureImage() const
QTransform transform() const
B、填充颜色
在Qt中,颜色使用QColor类表示,QColor支持RGB,HSV,CMYK颜色模型。QColor还支持alpha混合的轮廓和填充。RGB是面向硬件的模型,颜色由红绿蓝三种基色混合而成;HSV模型比较符合人对颜色的感觉,由色调(0-359),饱和度(0-255),亮度(0-255)组成;CMYK由青,洋红,黄,黑四种基色组成,主要用于打印机等硬件拷贝设备上,每个颜色分量的取值是0-255。
C、填充模式
填充模式通过枚举类型Qt::BrushStyle来实现,默认值是Qt::NoBrush,不进行任何填充;填充模式包括基本填充模式,渐变填充,和纹理填充模式。不同的填充模式显示效果如下:
Qt4中,QBrush提供了三种渐变填充:线性(QLinearGradient),圆形(QRadialGradient)和圆锥渐变(QConicalGradient),所有的类都从QGradient类继承。
线性渐变填充
线性渐变填充指定两个控制点,画刷在两个控制点之间进行颜色插值。通过创建QLinearGradient对象来设置画刷。
QLinearGradient linearGradient(0,0,200,100);
linearGradient.setColorAt(0,Qt::red);
linearGradient.setColorAt(0.5,Qt::green);
linearGradient.setColorAt(1,Qt::blue);
painter.setBrush(linearGradient);
painter.drawRect(0,0,200,100);
在QGradient构造函数中指定线行填充的两点分别为(0,0),(100,100)。 setColorAt()函数在0-1之间设置指定位置的颜色。
圆形渐变填充
圆形渐变填充需要指定圆心,半径和焦点。画刷在焦点和圆上的所有点之间进行颜色插值,通过创建QRadialGradient对象设置画刷。
QRadialGradient radialGradient(50,50,50,30,30);
radialGradient.setColorAt(0.2,Qt::cyan);
radialGradient.setColorAt(0.8,Qt::yellow);
radialGradient.setColorAt(1,Qt::magenta);
painter.setBrush(radialGradient);
painter.drawEllipse(0,0,100,100);
圆锥渐变填充
圆锥渐变填充指定圆心和开始角,画刷沿圆心逆时针对颜色进行插值,通过创建QConicalGradient对象并设置画刷。
QConicalGradient conicalGradient(60,40,30);
conicalGradient.setColorAt(0,Qt::gray);
conicalGradient.setColorAt(0.4,Qt::darkGreen);
conicalGradient.setColorAt(0.6,Qt::darkMagenta);
conicalGradient.setColorAt(1,Qt::drakBlue);
painter.setBrush(conicalGradient);
painter.drawEllipse(0,0,100,100);
其他填充模式
其他填充模式通过setStyle(Qt::BrushStyle style)函数进行设置。
如果实现自定义填充,可以使用QPixmap或者QImage对象进行纹理填充。两种图像分别使用setTexture()和setTextureImage()函数加载纹理。
D、alpha通道
在windows,Mac OSX和有XRender扩展的X11系统上,Qt4能够支持Alpha通道,通过使用Alpha通道,可以实现半透明效果,QColor类中定义了Alpha通道的透明度,0表示完全透明,255表示完全不透明。QWidget类有一个属性windowOpacity,通过setWindowOpacity(qreal level)可以设置窗口的透明度。但该属性和Alpha通道的原理并不相同,Qt4在Windows和Mac OS X平台上才支持该属性,但在X11平台上却需要Composite扩展才能工作。(alpha通道使用的是X11的xRender扩展)。
3、双缓冲绘图
在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图。使用双缓冲,可以减轻绘制的闪烁感。在有些情况下,用户要关闭双缓冲,自己管理绘图。下面的语句设置了窗口部件的Qt::WA_PaintOnScreen属性 ,就关闭了窗口部件的双缓冲。
widget->setAttribute(Qt::WA_PaintOnScreen);
Qt4不再提供异或笔,组合模式QPainter::CompostionMode_Xor()并不是异或笔,Qt4只提供了QRubberBand实现矩形和直线的绘图反馈。要实现在绘图中动态反馈必须使用其他方法。程序中使用双缓冲来解决这个问题。在绘图过程中,一个缓冲区绘制临时内存,一个缓冲区保存绘制好的内容,最后进行合并。
在交互绘图过程中,程序将图像缓冲区复制到临时缓冲区,并在临时缓冲区上绘制,绘制完毕在将结果复制到图像缓冲区,如果没有交互复制,则直接将图像缓冲区绘制显示到屏幕上。
4、绘图路径
绘图路径(painter path)由基本图元(矩形,椭圆,直线,曲线)组成,绘图路径可以是闭合的路径,如矩形和圆,或者是非闭合的路径,如直线和曲线。绘图路径在Qt中使用QPainterPth类表示,提供了绘图操作的容器,可以使图形能够复用。绘图路径可以进行填充,显示轮廓和裁剪。要生成可填充的轮廓的绘图路径,可以使用QPainterPathStroker类。使用QPainterPath的优点是复杂的图形只需创建一次,就可以多次使用。QPainterPath对象可以是只有起点的空路径,或者从其他QPainterPath对象复制,创建了QPainterPath对象后,可以使用lineTo(),cubicTo(),quadTo() 函数将直线和曲线添加到路径中来,直线和曲线从currentPosition()开始绘制。currentPosition()总是返回最后的子路经绘制的终点。使用moveTo()函数可以在不增加路径的情况下移动currentPositon(),它关闭了一个子路经,开始一个新的子路经。 closeSubPath()也可以关闭当前路径,并从currentPosition()连接一条直线到绘图路径的起点。QPainter可以使用 addEllipse(),addPath(),addRect(),addRegion(),
addText()将Qt的一些基本图元加入绘图路径。一个已有的绘图路径可以通过connectPath()函数加入到另一个绘图路径中。
箭头的绘制代码如下:
QPainterPath path;
path.moveTo(10,100);
path.cubicTo(10,100,100,10,200,70);
path.lineTo(200,50);
path.lineTo(220,80);
path.lineTo(200,110);
path.lineTo(200,90);
path.cubicTo(200,100,100,50,50,100);
QPainter painter(this);
QPen pen(QColor(255,0,0),2);
painter.setPen(pen);
painter.drawPath(path);
Qt提供了两种填充方式,Qt::OddEventFill和Qt::WindingFill。Qt::OddEvent是默认的填充规则,指定QPainterPath使用奇偶填充规则,奇偶填充规则判断一个点是否在路径图形内的方法是从该点画一条水平线到路径外,计算水平线和路径的交点数,如果交点是奇数个则说明该点在路径图形内。QPainterPath还有一些函数可以获取路径信息,如elementAt()函数可以取出指定的子路经元素,isEmpty()函数判断当前路径是否为空。controlPointRect()函数返回路径中所有的点和控制点的矩形,controlPointRect函数运行速度比返回精确包容框boundingRect()函数快得多。contains()函数判断一个点或一个矩形是否在路径内。intersects()判断指定的矩形与路径是否相交。QPainterPath可以将矩形图形转换为其他图形,如使用toFillPolygon(),toFillPolygon(),toSubpathPOlygons()函数将路径转化为多边形。
QPainterPath还可以使用文字作为路径。
使用线性渐变填充的文字路径实现代码:
QPainter painter(this);
QLinearGradient linearGrad(QPointF(200,0),QPointF(1000,0));
linearGrad.setColorAt(0,Qt::black);
linearGrad.setColorAt(1,Qt::white);
QFont font("隶书