Qt drawing class

QPainter drawing

1. QPainter and QPaintDevice

Qt's drawing system allows users to draw on the screen or printing device using the same API. The drawing system is based on the QPainter, QPaintDevice and QPaintEngine classes. QPainter is a class used for drawing operations. QPaintDevice is an abstract two-dimensional interface that can be used for drawing with QPainter. QPaintEngine provides QPainter with interfaces for drawing on different devices. The QPaintEngine class is used internally by QPainter and QPaintDevice. Applications generally do not need to deal with QPaintEngine unless they want to create their own device type.

General drawing devices include QWidget, QPixmap, QImage, etc. These drawing devices provide a "canvas" for QPainter.

2. paintEvent event and drawing area

    The QWidget class and its subclasses are the most commonly used drawing devices. Classes inherited from the QWidget class have paintEvent() events. To draw on the device, you only need to redefine this event and write the response code. Create a QPainter object to obtain the interface of the drawing device, and then you can draw on the "canvas" of the drawing device.

The basic program structure of drawing in the paintEvent() event is:

void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter(this);  //创建与绘图设备关联的QPainter对象
...//painter在设备的窗口上画图
}

First create a QPainter object painter that belongs to this drawing device, and then use this painter to draw on the window of the drawing device.

The drawing area of ​​QWidget is the internal area of ​​its window. As shown in Figure 1, a filled rectangle is drawn on a QWidget window (this solid rectangle and its border are graphics drawn by the program, and other straight lines and text are added for illustration). The rectangular area inside the entire window is what QPainter can The drawing area.

The coordinate system of QWidget's internal drawing area is shown in Figure 1. The unit of the coordinate system is pixels. The coordinates of the upper left corner are (0, 0), the positive direction of the X-axis is to the right, and the positive direction of the Y-axis is downward. The width of the drawing area is obtained by the QWidget::width() function, and the height is obtained by the QWidget::height() function. , so the coordinates of the point in the lower right corner of the drawing area are (width(), height()). This coordinate system is the local physical coordinates of the QWidget drawing area, called viewport coordinates. Correspondingly, there are logical coordinates, called window coordinates, which will be introduced in detail later.

Insert image description here

Figure 1 Drawing on the window inherited from QWidget

Using QPainter to draw on QWidget is to draw in such a rectangular area.

3.The main properties of QPainter drawing

   ; Using QPainter to draw on a drawing device mainly draws some basic graphic elements, including points, lines, circles, rectangles, curves, text, etc. The three attributes of QPainter that control the characteristics of these drawing elements are as follows.

pen attribute: It is a QPen object used to control the color, width, line type, etc. of the line. As shown in Figure 8-1, the characteristics of the line of the rectangular border are determined by the pen attribute.
brush attribute: It is a QBrush object used to set the filling characteristics of an area. You can set the filling color, filling method, gradient characteristics, etc. You can also use pictures as material filling. The rectangle in Figure 1 is filled with yellow due to the brush attribute settings.
font attribute: It is a QFont object, used to set the font style, size and other attributes of the text when drawing text.
Using these three properties basically controls the basic characteristics of drawing. Of course, there are also some other functions that can be used in combination, such as overlay mode, rotation and scaling.

4. Create instance

To demonstrate the basic functions of QPainter drawing, create a Qt Widget Application project, select the window base class as QWidget, and automatically create a form. The created project has a Widget class. In order to simplify the code function, no other components are placed in the Widget window, which is only used for drawing.

Below is the complete definition of the Widget class. Just redefine the paintEvent() event and write the drawing code in this event.The Q_DECL_OVERRIDE macro indicates that this function is an overload of the parent class virtual function

class Widget : public QWidget
{
    
    
   Q_OBJECT
protected:
   void   paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
public:
   explicit Widget(QWidget *parent = 0);
   ~Widget();
private:
   Ui::Widget *ui;
};

The following is the code of the Widget class constructor and paintEvent() function. A filled rectangle is drawn on the interface as shown in Figure 1, demonstrating the basic process of QPainter drawing.

Widget::Widget(QWidget *parent) :  QWidget(parent),  ui(new Ui::Widget)
{
    
    
   ui->setupUi(this);
   setPalette(QPalette(Qt::white)); //设置窗口为白色背景
   setAutoFillBackground(true);
}
void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter (this);//创建QPainter对象
   painter.setRenderHint(QPainter::Antialiasing);
   painter.setRenderHint(QPainter::TextAntialiasing);
   int W=this->width(); //绘图区宽度
   int H=this->height(); //绘图区高度
   QRect   rect(W/4,H/4,W/2,H/2); //中间区域矩形框
//设置画笔
   QPen   pen;
   pen.setWidth(3); //线宽
   pen.setColor(Qt::red); //划线颜色
   pen.setStyle(Qt::SolidLine);//线的样式,实线、虚线等
   pen.setCapStyle(Qt::FlatCap);//线端点样式
   pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
   painter.setPen(pen);
//设置画刷
   QBrush  brush;
   brush.setColor(Qt::yellow); //画刷颜色
   brush.setStyle(Qt::SolidPattern); //画刷填充样式
   painter.setBrush(brush);
//绘图
   painter.drawRect(rect);
}

In the paintEvent() function, first create the QPainter object painter associated with the Widget, so that you can use this painter to draw on the Widget.

The following code obtains the width and height of the Widget window and defines a rectangle rect located in the middle area. The size of this rectangle changes with the size of the Widget because its size definition uses the width and height of the Widget instead of being fixed. size.

int W=this->width(); //绘图区宽度
int H=this->height(); //绘图区高度
QRect   rect(W/4,H/4,W/2,H/2); //中间区域矩形框

Then define an object pen of the QPen class, set its line width, color, line type, etc., and then set it as the painter's pen.

Then define an object brush of the QBrush class, set its color to yellow, the filling method to solid filling, and then set it to the painter's brush.

After setting the pen and brush attributes of the painter, call the drawRect() function of the QPainter class to draw the previously defined rectangle. The line characteristics of the rectangular frame are determined by the pen, and the fill characteristics are determined by the brush. Run the program and you will get the filled rectangle in the middle of the interface as shown in Figure 8-1.

In order not to make the program structure too complicated, the various attributes of the pen and brush are directly set in the paintEvent() function instead of designing a complex interface program to modify these settings. To implement any drawing function, just modify the code directly in the paintEvent() function.

QPen’s main functions

    QPen is used to set lines when drawing, mainly including line width, color, line type, etc. Table 1 is the main interface function of the QPen class. Usually a setting function has a corresponding reading function. For example, setColor() is used to set the brush color, and the corresponding function to read the brush color is color(). Table 1 only lists the setting functions (omitting the function parameters) const keyword).

Table 1 Main functions of QPen
Function prototype|Function----|------ void setColor(QColor &color)|Set the pen color, that is, the line color void setWidth(int width)|Set the line width void setStyle (Qt::PenStyle style)|Set Line style, the parameter is the Qt::PenStyle enumeration type void setCapStyle (Qt::PenCapStyle style) | Set the line endpoint style, the parameter is the Qt::PenCapStyle enumeration type void setJoinStyle (Qt::PenJoinStyle style) | Set the connection style, The parameter is Qt::PenJoinStyle enumeration type

Needless to say, the setting of line color and width. The other three main attributes of QPen that affect line characteristics are line style (style), endpoint style (capStyle) and connection style (joinStyle).

1. line style

The setStyle(Qt::PenStyle style) function is used to set the line style. The parameter is a constant of the enumeration type Qt::PenStyle. The drawing effects of several typical line styles are shown in Figure 2. The Qt::PenStyle type also has a constant Qt::NoPen which means no lines are drawn.
Insert image description here

Figure 2 Lines of various styles (from Qt help file)

In addition to several basic line styles, users can also customize line styles. When customizing line styles, you need to use the setDashOffset() and setDashPattern() functions.

2. Line endpoint style

The setCapStyle (Qt::PenCapStyle style) function is used to set the line endpoint style. The parameter is a constant of the enumeration type Qt::PenCapStyle. The three values ​​​​of this enumeration type and their drawing effects are shown in Figure 3.

Insert image description here

Figure 3 Various line endpoint styles (from Qt help file)

3.Line connection style

The setJoinStyle (Qt::PenJoinStyle style) function is used to set the line connection style. The parameter is a constant of the enumeration type Qt::PenJoinStyle. The value of this enumeration type and its drawing effect are shown in Figure 4.

Insert image description here

Figure 4 Various line connection styles (from Qt help file)

3. Main functions of QBrush

QBrush defines the filling characteristics of QPainter when drawing, including filling color, filling style, material picture when filling with materials, etc. Its main functions are shown in Table 8-2 (the const keyword in the function parameters is omitted).

Table 2 Main functions of QBrush
function prototype Function
void setColorr(QColor &color) Set the brush color, which is the fill color when the entity is filled.
void setStyle(Qt::BrushStyle style) Set the brush style, the parameter is the Qt::BrushStyle enumeration type
void setTexture(QPixmap &pixmap) Set a QPixmap type picture as the brush picture, and the brush style is automatically set to Qt::TexturePattern
void setTextureImage(QImage &image) Set a QImage type picture as the brush picture, and the brush style is automatically set to Qt::TexturePattern

The setStyle(Qt::BrushStyle style) function sets the style of the brush. The parameter is the Qt::BrushStyle style enumeration type. The typical values ​​of this enumeration type are shown in Table 3. For detailed values, please refer to the Qt help file. . The filling effects of several typical values ​​are shown in Figure 5.

Table 3 Several main constants of the enumeration type Qt::BrushStyle and their meanings

enum constants describe
Qt:: NoBrush No padding
Qt:: SolidPattern single color fill
Qt:: HorPattern horizontal line fill
Qt:: VerPattern vertical line fill
Qt:: LinearGradientPattern Linear gradient, you need to use QLinearGradient class object as Brush
Qt:: RadialGradientPattern Radiation gradient, you need to use QRadialGradient class object as Brush
Qt:: ConicalGradientPattern Conical gradient requires using QConicalGradient class object as Brush
Qt::TexturePattern Material filling, you need to specify texture or textureImage picture

Gradient filling requires a special class to be assigned to QPainter as a Brush. This part will be introduced in detail later. For other types of line fills, you only need to set the type parameters. To use materials, you need to set the material pictures.

Insert image description here

Figure 5 Qt::BrushStyle several fill styles (from Qt help file)

The following is an example program that uses a picture in a resource file to fill a rectangle with a material. The program results are shown in Figure 8-6.

void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter(this); 
   int W=this->width(); //绘图区宽度
   int H=this->height(); //绘图区高度
   QRect   rect(W/4,H/4,W/2,H/2); //中间区域矩形框
//设置画笔
   QPen   pen;
   pen.setWidth(3); //线宽
   pen.setColor(Qt::red); //划线颜色
   pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
   painter.setPen(pen);
//设置画刷
   QPixmap texturePixmap(":images/images/texture.jpg");
   QBrush  brush;
   brush.setStyle(Qt::TexturePattern); //画刷填充样式
   brush.setTexture(texturePixmap); //设置材质图片
   painter.setBrush(brush);
//绘图
   painter.drawRect(rect);
}

4. Gradient fill

To use gradient filling, you need to use a gradient class object as the Painter's brush. There are three classes that implement gradient filling.

QLinearGradient:Linear gradient. Specify a starting point and its color, an end point and its color, and you can also specify the color of a point in the middle. The color between the starting point and the end point will be linearly interpolated to obtain a linear gradient fill color.
QRadialGradient: There are two methods: simple radiation gradient and extended radiation gradient. A simple radiant gradient generates a gradient color between a focus point and an endpoint within a circle, and an extended radiant gradient generates a gradient color between a focus circle and a central circle.
QConicalGradient: Conical gradient, generating gradient color counterclockwise around a center point.
Example effects of these three gradients are shown in Figure 6.
Insert image description here

Figure 6 3 gradient filling effects (from Qt help file): (left) QLinearGradient; (middle) QRadialGradient; (right) QConicalGradient

These three gradient classes all inherit from the QGradient class. In addition to the different ways of generating gradient colors, in addition to the set gradient color coordinate range, you also need to use the setSpread(QGradient::Spread method) function of the QGradient class to set the extension method. . The enumeration type QGradient::Spread has three values, which represent three extension effects respectively. Figure 8-7 shows the effects of three extension methods when using radiation gradient. setSpread() has no effect on conical gradients.

PadSpread mode fills the outer area with the color of the end point, which is the default way.
RepeatSpread mode repeatedly uses gradients to fill the outer area.
ReflectSpread is a reflective reuse gradient method that fills the outer area.

Insert image description here

Figure 7 3 gradient extension effects (from Qt help file)

The following code demonstrates drawing using a gradient effect, and a radial gradient is used in the program.

void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter(this); 
   int W=this->width();
   int H=this->height();
//径向渐变
   QRadialGradient  radialGrad(W/2,H/2,qMax(W/8,H/8),W/2,H/2);
   radialGrad.setColorAt(0,Qt::green);
   radialGrad.setColorAt(1,Qt::blue);
   radialGrad.setSpread(QGradient::ReflectSpread);
   painter.setBrush(radialGrad);
//绘图
   painter.drawRect(this->rect()); //填充更大区域,会有延展效果
}

The constructor prototype used when defining the QRadialGradient object in the above code is:

QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qreal fy)

Among them, (cx, cy) is the center point of the radiation filling, which is set to (W/2, H/2) in the program, which is the center of the Widget window; radius is the radius of the radiation filling area, which is set to qMax(W /8, H/8); (fx, fy) is the focus coordinate, which is set to (W/2, H/2) in the program, which is the same as the center point.

The statements to set the starting color and end color of the radiation gradient are:

radialGrad.setColorAt(0,Qt::green);
radialGrad.setColorAt(1,Qt::blue);

The "point" here uses logical coordinates, 0 represents the starting point, which is the radiation center point; 1 represents the end point, which is the circumference of the filled area circle.

Then use the setSpread() function to set the extension method to QGradient::ReflectSpread.

The final plot statement is:

painter.drawRect(this->rect());

A rectangle is drawn here, but the rectangle used is this->rect(), which is the entire rectangular area of ​​the Widget window. It is larger than the defined radiation filling area, so there will be an extension effect. The running effect of the program is shown in Figure 8.
Insert image description here
Figure 8 Radiation filling effect

If linear gradient filling is used, the sample code is as follows (only the part defined by QLinearGradient is listed). When defining the QLinearGradient object, the starting point and end point of the linear gradient are specified. When setting the color, the color values ​​of multiple points can be set between the starting point and the end point.

//   QLinearGradient  linearGrad(rect.left(),rect.top(),
//                 rect.right(),rect.bottom()); //对角线
   QLinearGradient  linearGrad(rect.left(), rect.top(), rect.right(), rect.top());//从左到右
   linearGrad.setColorAt(0,Qt::blue);//起点颜色
   linearGrad.setColorAt(0.5,Qt::green);//中间点颜色
   linearGrad.setColorAt(1,Qt::red);//终点颜色
   linearGrad.setSpread(QGradient::ReflectSpread);  //展布模式
   painter.setBrush(linearGrad);

When creating the QLinearGradient object, two coordinate points are passed, representing the starting point and end point of the filling area respectively. The starting point and end point are defined in different ways, and different effects such as horizontal gradient, vertical gradient, or diagonal gradient can be achieved.

Example code for using a cone gradient is as follows. When creating a QConicalGradient object, the center point coordinates and starting angle are specified, and then the colors of multiple points are set. Note, however, that conical fills have no extension effect.

QConicalGradient  coniGrad(W/2,H/2,45);
coniGrad.setColorAt(0,Qt::yellow);
coniGrad.setColorAt(0.5,Qt::blue);
coniGrad.setColorAt(1,Qt::green);
painter.setBrush(coniGrad);

5 QPainter draws basic graphic components

1. basic graphic elements

QPainter provides many functions for drawing basic graphics, including points, straight lines, ellipses, rectangles, curves, etc. Complex graphics can be formed from these basic graphics. The functions for drawing basic primitives provided in QPainter are shown in Table 8-4. Each function basically has multiple parameter forms. Here we only list the function name and give an example code for one of the parameter forms. It is assumed that the painter, window width W and height of the drawing window have been obtained through the following code. H.

QPainter painter(this);
int W=this->width(); //绘图区宽度
int H=this->height(); //绘图区高度

Table 8-4 QPainter functions for drawing basic graphic components

Function name Functions and sample code Sample graphics
drawArc Draw arcs, e.g.

QRect rect(W/4,H/4,W/2,H/2);
int startAngle = 90 * 16; //Start at 90°
int spanAngle = 90 * 16; //Rotate 90°
painter.drawArc(rect , startAngle, spanAngle);

Insert image description here
drawChord Draw a string, e.g.

QRect rect(W/4,H/4,W/2,H/2);
int startAngle = 90 * 16; //Start at 90°
int spanAngle = 90 * 16; //Rotate 90°
painter. drawChord (rect , startAngle, spanAngle);

picture
drawConvexPolygon Draws a convex polygon based on given points

QPoint points[4]={
QPoint(5W/12,H/4),
QPoint(3
W/4,5H/12),
QPoint(5
W/12,3H/4),
QPoint(W/4,5
H/12), };
painter.drawConvexPolygon(points, 4);

Picture 139
drawEllipse Draw an ellipse
QRect rect(W/4,H/4,W/2,H/2);
painter.drawEllipse(rect);
Picture 153
drawImage Draw an image within the specified rectangular area
QRect rect(W/4,H/4,W/2,H/2);
QImage image(“:images/images/qt.jpg”);
painter.drawImage(rect, image );
Picture 19
drawLine 画直线
QLine Line(W/4,H/4,W/2,H/2);
painter.drawLine(Line);
图片 157
drawLines 画一批直线
QRect rect(W/4,H/4,W/2,H/2);
QVector Lines;
Lines.append(QLine(rect.topLeft(),rect.bottomRight()));
Lines.append(QLine(rect.topRight(),rect.bottomLeft()));
Lines.append(QLine(rect.topLeft(),rect.bottomLeft()));
Lines.append(QLine(rect.topRight(),rect.bottomRight()));
painter.drawLines(Lines);
图片 160
drawPath 绘制由QPainterPath对象定义的路线
QRect rect(W/4,H/4,W/2,H/2);
QPainterPath path;
path.addEllipse(rect);
path.addRect(rect);
painter.drawPath(path);
图片 162
drawPie 绘制扇形
QRect rect(W/4,H/4,W/2,H/2);
int startAngle = 40 * 16;//起始40°
int spanAngle = 120 * 16;//旋转120°
painter.drawPie(rect, startAngle, spanAngle);
图片 165
drawPixmap 绘制Pixmap图片
QRect rect(W/4,H/4,W/2,H/2);
QPixmap pixmap(“:images/images/qt.jpg”);
painter.drawPixmap(rect, pixmap);
drawPoint 画一个点
painter.drawPoint(QPoint(W/2,H/2));
drawPoints 画一批点
QPoint points[]={
QPoint(5W/12,H/4),
QPoint(3
W/4,5H/12),
QPoint(2
W/4,5*H/12) };
painter.drawPoints(points, 3);
drawPolygon 画多边形,最后一个点会和第一个点闭合
QPoint points[]={
QPoint(5W/12,H/4),
QPoint(3
W/4,5H/12),
QPoint(5
W/12,3H/4),
QPoint(2
W/4,5*H/12) };
painter.drawPolygon(points, 4);
图片 167
drawPolyline 画多点连接的线,最后一个点不会和第一个点连接
QPoint points[]={
QPoint(5W/12,H/4),
QPoint(3
W/4,5H/12),
QPoint(5
W/12,3H/4),
QPoint(2
W/4,5*H/12), };
painter.drawPolyline(points, 4);
图片 171
drawRect 画矩形
QRect rect(W/4,H/4,W/2,H/2);
painter.drawRect(rect);
图片 173
drawRoundedRect 画圆角矩形
QRect rect(W/4,H/4,W/2,H/2);
painter.drawRoundedRect(rect,20,20);
图片 266
drawText 绘制文本,只能绘制单行文字,字体的大小等属性由QPainter::font()决定。
QRect rect(W/4,H/4,W/2,H/2);
QFont font;
font.setPointSize(30);
font.setBold(true);
painter.setFont(font);
painter.drawText (rect,“Hello,Qt”);
eraseRect 擦除某个矩形区域,等效于用背景色填充该区域
QRect rect(W/4,H/4,W/2,H/2);
painter.eraseRect(rect);
fillPath 填充某个QPainterPath定义的绘图路径,但是轮廓线不显示
QRect rect(W/4,H/4,W/2,H/2);
QPainterPath path;
path.addEllipse(rect);
path.addRect(rect);
painter.fillPath(path,Qt::red); 图片 273
fillRect 填充一个矩形,无边框线
QRect rect(W/4,H/4,W/2,H/2);
painter.fillRect (rect,Qt::green);
图片 33

这些基本图形元件的绘制用户可以通过修改samp8_1的paintEvent()里的代码进行测试,这里就不再详细举例和说明了。

2.QPainterPath的使用

在表8-4列举的QPainter绘制基本图形元件的函数中,一般的图形元件的绘制都比较简单和直观,只有drawPath()函数是绘制一个复合的图形对象,它使用一个QPainterPath类型的参数作为绘图对象。drawPath()函数的原型是:

void QPainter::drawPath(const QPainterPath &path)

QPainterPath是一系列绘图操作的顺序集合,便于重复使用。一个PainterPath由许多基本的绘图操作组成,如绘图点移动、划线、画圆、画矩形等,一个闭合的PainterPath是终点和起点连接起来的绘图路径。使用QPainterPath的优点是绘制某些复杂形状时只需创建一个PainterPath,然后调用QPainter::drawPath()就可以重复使用。例如绘制一个复杂的星星图案需要多次调用lineto()函数,定义一个QPainterPath类型的变量path记录这些绘制过程,再调用drawPath(path)就可以完成星型图案的绘制。

QPainterPath提供了很多函数可以添加各种基本图形元件的绘制,其功能与QPainter提供的绘制基本图件的功能类似,也有一些用于PainterPath的专用函数,如closeSubpath()、connectPath()等,对于QPainterPath的函数功能不做详细说明,可以参考Qt帮助文件查看QPainterPath类的详细描述。

2 坐标系统和坐标变换

1 坐标变换函数

QPainter在窗口上绘图的默认坐标系统如图8-1所示,这是绘图设备的物理坐标。为了绘图的方便,QPainter提供了一些坐标变换的功能,通过平移、旋转等坐标变换,得到一个逻辑坐标系统,使用逻辑坐标系统在某些时候绘图更方便。坐标变换函数见表8-5。

表1 QPainter有关坐标变换操作的函数

分组 函数原型 功能
坐标变换 void translate(qreal dx, qreal dy) 坐标系统平移一定的偏移量,坐标原点平移到新的点
void rotate(qreal angle) 坐标系统顺时针旋转一个角度
void scale(qreal sx, qreal sy) 坐标系统缩放
void shear(qreal sh, qreal sv) 坐标系统做扭转变换
状态保存与恢复 void save() 保存painter当前的状态,就是将当前状态压入堆栈
void restore() 恢复上一次状态,就是从堆栈中弹出上次的状态
void resetTransform() 复位所有的坐标变换

常用的坐标变换是平移、旋转和缩放,使用世界坐标变换矩阵也可以实现这些变换功能,但是需要单独定义一个QTransform类的变量,对于QPainter来说,简单的坐标变换使用QPainter自有的坐标变换函数就足够了。

1.坐标平移

坐标平移函数是translate(),其中一种参数形式的函数原型是:

void  translate(qreal dx, qreal dy)

表示将坐标系统水平方向平移dx个单位,垂直方向平移dy个单位,在缺省的坐标系统中,单位就是像素。如果是从原始状态平移(dx, dy),那么平移后的坐标原点就移到了(dx, dy)。

假设一个绘图窗口宽度为300像素,高度为200像素,则其原始坐标系统如图8-10左所示;若执行平移函数translate(150, 100),则坐标系统水平向右平移150像素,向下平移100像素,平移后的坐标系统如图 8-10 右所示,坐标原点在窗口的中心,而左上角的坐标变为(−150, −100),右下角的坐标变为(150, 100)。如此将坐标原点变换到窗口中心在绘制某些图形时是非常方便的。

2.坐标旋转

坐标旋转的函数是rotate(),其函数原型为:

void rotate(qreal angle)
它是将坐标系统绕坐标原点顺时针旋转angle角度,单位是度。当angle为正数时是顺时针旋转,为负数时是逆时针旋转。

在图8-10右的基础上,若执行rotate(90),则得到图8-11所示的坐标系统。

Insert image description here

图8-10 (左)原始坐标系统;(右)平移(150,100)后的坐标系统

Insert image description here

图8-11 对图8-10右图旋转90°之后的坐标系
注意 
旋转之后并不改变窗口矩形的实际大小,只是改变了坐标轴的方向。

在图8-11的新坐标系下,窗口左上角的坐标变成了(-100, 150),而右下角的坐标变成了(100, -150)。

3.缩放

缩放函数是scale(),其函数原型为:

void  scale(qreal sx, qreal sy)

其中,sx, sy分别为横向和纵向缩放比例,比例大于1是放大,小于1是缩小。

4.状态保存与恢复

    进行坐标变换时,QPainter内部实际上有一个坐标变换矩阵,用save()保存当前坐标状态,用restore()恢复上次保存的坐标状态,这两个函数必须配对使用,操作的是一个堆栈对象。

resetTransform()函数则是复位所有坐标变换操作,恢复原始的坐标系统。

2 坐标变换绘图实例

1.绘制3个五角星的程序

创建一个基于QWidget的窗口的应用程序,窗体上不放置任何组件。在Widget类的构造函数和paintEvent()事件中编写代码,代码内容如下。

Widget::Widget(QWidget *parent) :   QWidget(parent),   ui(new Ui::Widget)
{
    
    
   ui->setupUi(this);
   setPalette(QPalette(Qt::white)); //设置窗口背景色
   setAutoFillBackground(true);
   resize(600,300); //固定初始化窗口大小
}
void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter(this); 
   painter.setRenderHint(QPainter::Antialiasing);
   painter.setRenderHint(QPainter::TextAntialiasing);
//生成五角星的5个顶点的坐标,假设原点在五角星中心
   qreal   R=100; //半径
   const   qreal Pi=3.14159;
   qreal   deg=Pi*72/180;
   QPoint points[5]={
    
    
      QPoint(R,0),
      QPoint(R*std::cos(deg),-R*std::sin(deg)),
      QPoint(R*std::cos(2*deg),-R*std::sin(2*deg)),
      QPoint(R*std::cos(3*deg),-R*std::sin(3*deg)),
      QPoint(R*std::cos(4*deg),-R*std::sin(4*deg)),
   };
//设置字体
   QFont   font;
   font.setPointSize(12);
   font.setBold(true);
   painter.setFont(font);
//设置画笔
   QPen   penLine;
   penLine.setWidth(2); //线宽
   penLine.setColor(Qt::blue); //划线颜色
   penLine.setStyle(Qt::SolidLine);//线的类型 
   penLine.setCapStyle(Qt::FlatCap);//线端点样式
   penLine.setJoinStyle(Qt::BevelJoin);//线的连接点样式
   painter.setPen(penLine);
//设置画刷
   QBrush  brush;
   brush.setColor(Qt::yellow); //画刷颜色
   brush.setStyle(Qt::SolidPattern); //画刷填充样式
   painter.setBrush(brush);
//设计绘制五角星的PainterPath,以便重复使用
   QPainterPath starPath;
   starPath.moveTo(points[0]);
   starPath.lineTo(points[2]);
   starPath.lineTo(points[4]);
   starPath.lineTo(points[1]);
   starPath.lineTo(points[3]);
   starPath.closeSubpath(); //闭合路径,最后一个点与第一个点相连
   starPath.addText(points[0],font,"0"); //显示端点编号
   starPath.addText(points[1],font,"1");
   starPath.addText(points[2],font,"2");
   starPath.addText(points[3],font,"3");
   starPath.addText(points[4],font,"4");
//绘图
   painter.save(); //保存坐标状态
   painter.translate(100,120);//平移
   painter.drawPath(starPath); //画星星
   painter.drawText(0,0,"S1");
   painter.restore(); //恢复坐标状态

   painter.translate(300,120); //平移
   painter.scale(0.8,0.8); //缩放
   painter.rotate(90); //顺时针旋转90度
   painter.drawPath(starPath);//画星星
   painter.drawText(0,0,"S2");

   painter.resetTransform(); //复位所有坐标变换
   painter.translate(500,120); //平移
   painter.rotate(-145); //逆时针旋转145度
   painter.drawPath(starPath);//画星星
   painter.drawText(0,0,"S3");
}

运行该实例程序,得到如图8-12所示的结果,在窗口上绘制了3个五角星。

Insert image description here

图8-12 使用QPainterPath和坐标变换的绘图效果

第1个是原始的五角星;第2个是缩小为0.8倍,顺时针旋转90度的五角星;第3个是逆时针旋转145度的五角星。这个程序中使用到了QPainterPath和QPainter的坐标变换功能。

2.绘制五角星的PainterPath的定义

首先假设一个五角星的中心点是原点,第0个点在X轴上,五角星外接圆半径为100,计算出5个点的坐标,保存在points数组中。

然后定义了一个QPainterPath类的变量starPath,用于记录画五角星的过程,就是几个点的连线过程,并且标注点的编号。使用QPainterPath的优点就是定义一个QPainterPath类型的变量记录一个复杂图形的绘制过程后,可以重复使用。虽然points数组中的点的坐标是假设五角星的中心点是原点,在绘制不同的五角星时只需将坐标平移到新的原点位置,就可以绘制不同的五角星。

绘制第1个五角星的程序是:

painter.save(); //保存坐标状态
painter.translate(100,120);
painter.drawPath(starPath); //画星星
painter.drawText(0,0,"S1");
painter.restore(); //恢复坐标状态

这里,save()函数保存当前坐标状态(也就是坐标的原始状态),然后将坐标原点平移到(100,120),调用绘制路径的函数drawPath(starPath)绘制五角星,在五角星的中心标注“S1”表示第1个五角星,最后调用restore()函数恢复上次的坐标状态。这样就以(100,120)为中心点绘制了第1个五角星。

绘制第2个五角星的程序是:

painter.translate(300,120); //平移
painter.scale(0.8,0.8); //缩放
painter.rotate(90); //顺时针旋转90度
painter.drawPath(starPath);//画星星
painter.drawText(0,0,"S2");

这里首先调用坐标平移函数translate(300, 120)。由于上次restore()之后回到坐标初始状态,所以这次平移后,坐标原点到了物理坐标(300, 120)。而如果没有上一个restore(),会在上一次的坐标基础上平移。

绘图之前调用了缩放函数scale(0.8, 0.8),使得缩小到原来的0.8,再顺时针旋转90°,然后调用绘制路径函数drawPath(starPath)绘制五角星,就得到了第2个五角星。

绘制第3个五角星时首先使坐标复位,即:

painter.resetTransform(); //复位所有坐标变换

这样会复位所有坐标变换,又回到了原始坐标。

3 视口和窗口

1.视口和窗口的定义与原理

绘图设备的物理坐标是基本的坐标系,通过QPainter的平移、旋转等变换可以得到更容易操作的逻辑坐标。

为了实现更方便的坐标,QPainter还提供了视口(Viewport)和窗口(Window)坐标系,通过QPainter内部的坐标变换矩阵自动转换为绘图设备的物理坐标。

视口表示绘图设备的任意一个矩形区域的物理坐标,可以只选取物理坐标的一个矩形区域用于绘图。默认情况下,视口等于绘图设备的整个矩形区。

窗口与视口是同一个矩形,只不过是用逻辑坐标定义的坐标系。窗口可以直接定义矩形区的逻辑坐标范围。图8-13是对视口和窗口的图示说明。

Insert image description here

图8-13 视口和窗口示意图

图8-13左图中的矩形框代表绘图设备的物理大小和坐标范围,假设宽度为300像素,高度为200像素。现在要取其中间的一个正方形区域作为视口,灰色的正方形就是视口,绘图设备的物理坐标中,视口的左上角坐标为(50, 0),右下角坐标为(250, 200)。定义此视口,可以使用QPainter的setViewport()函数,其函数原型为:

void QPainter::setViewport(int x, int y, int width, int height)

要定义图8-13左图中的视口,使用下面的语句:

painter.setViewport(50,0,200,200);

表示从绘图设备物理坐标系统的起点(50, 0)开始,取宽度为200、高度为200的一个矩形区域作为视口。

对于图8-13左图的视口所表示的正方形区域,定义一个窗口(图8-13右图),窗口坐标的中心在正方形中心,并设置正方形的逻辑边长为100。可使用QPainter的setWindow()函数,其函数原型为:

void QPainter::setWindow(int x, int y, int width, int height)

所以,此处定义窗口的语句是:

painter. setWindow (-50,-50,100,100);

它表示对应于视口的矩形区域,其窗口左上角的逻辑坐标是(-50, -50),窗口宽度为100,高度为100。这里设置的窗口还是一个正方形,使得从视口到窗口变换时,长和宽的变化比例是相同的。实际可以任意指定窗口的逻辑坐标范围,长和宽的变化比例不相同也是可以的。

2.视口和窗口的使用实例

使用窗口坐标的优点是,只需按照窗口坐标定义来绘图,而不用管实际的物理坐标范围的大小。例如在一个固定边长为100的正方形窗口内绘图,当实际绘图设备大小变化时,绘制的图形会自动变化大小。这样,就可以将绘图功能与绘图设备隔离开来,使得绘图功能适用于不同大小、不同类型的设备。

实例samp8_3演示了使用视口和窗口的方法,项目创建与samp8_1类似,只在Widegt的paintEvent()事件里添加绘图代码。

void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter(this);
   int W=width();
   int H=height();
   int side=qMin(W,H);//取长和宽的较小值
   QRect rect((W-side)/2, (H-side)/2,side,side); //viewport矩形区
   painter.drawRect(rect); //Viewport的矩形区域
   painter.setViewport(rect);//设置Viewport
   painter.setWindow(-100,-100,200,200); // 设置窗口大小,逻辑坐标
   painter.setRenderHint(QPainter::Antialiasing);
//设置画笔
   QPen   pen;
   pen.setWidth(1); //线宽
   pen.setColor(Qt::red); //划线颜色
   pen.setStyle(Qt::SolidLine);//线的类型 
   painter.setPen(pen);
   for(int i=0; i

运行实例程序samp8_3,可以得到如图8-14所示的图形效果。当窗口的宽度大于高度时,以高度作为正方形的边长;当高度大于宽度时,以宽度作为正方形边长,且图形是自动缩放的。

Insert image description here

Insert image description here

图8-14 实例samp8_3使用窗口坐标的绘图效果

程序首先定义了一个正方形视口,正方形以绘图设备的长、宽中较小者为边长。

Then define the window. The defined window is a square with the origin at the center and a side length of 200.

The graphic effect in Figure 8-14 is actually obtained by drawing 36 circles. The code for the loop part is as follows:

for(int i=0; i<36;i++)
{
    
    
   painter.drawEllipse(QPoint(50,0),50,50);
   painter.rotate(10);
}

The center of each circle is at (50, 0) on the X-axis and the radius is 50. After drawing a circle, rotate the coordinate system by 10°, and then draw the same circle again. This cleverly uses the rotation of the coordinate axis.

4 The effect of drawing overlay

Modify the above program slightly and add settings for gradient fill and overlay effects.

void Widget::paintEvent(QPaintEvent *event)
{
    
    
   QPainter   painter(this);
   int W=width();
   int H=height();
   int side=qMin(W,H);//取长和宽的较小值
   QRect rect((W-side)/2, (H-side)/2,side,side); //viewport矩形区
   painter.drawRect(rect); //Viewport大小
   painter.setViewport(rect);//设置Viewport
   painter.setWindow(-100,-100,200,200); // 设置窗口大小,逻辑坐标
   painter.setRenderHint(QPainter::Antialiasing);
//设置画笔
   QPen   pen;
   pen.setWidth(1); //线宽
   pen.setColor(Qt::red); //划线颜色
   pen.setStyle(Qt::SolidLine);//线的类型
   painter.setPen(pen);
//线性渐变
   QLinearGradient  linearGrad(0,0,100,0);//从左到右,
   linearGrad.setColorAt(0,Qt::yellow);//起点颜色
   linearGrad.setColorAt(1,Qt::green);//终点颜色
   linearGrad.setSpread(QGradient::PadSpread);  //展布模式
   painter.setBrush(linearGrad);
//设置复合模式
  painter.setCompositionMode(QPainter::RasterOp_NotSourceXorDestination);
//   painter.setCompositionMode(QPainter::CompositionMode_Difference);
//   painter.setCompositionMode(QPainter::CompositionMode_Exclusion);
   for(int i=0; i

In the above program, a linear gradient fill is used for a single circle, and the single circle gradually changes from yellow to green from left to right.

Use the QPainter::setCompositionMode() function to set the combination mode, that is, the overlay mode of the picture drawn later and the picture drawn previously. The function parameter is a QPainter::CompositionMode enumeration type value. You can view the Qt help. This enumeration type has nearly 40 values, which represent different superposition operations between the last drawn graphics and the previous graphics.

Figure 8-15 shows the drawing effects in two of the overlay modes. It can be found that using different overlay modes can produce different drawing effects, even unexpectedly brilliant effects. Users can modify the program themselves and set different gradient colors, gradient fill modes, and different overlay modes, and may be able to draw more dazzling graphics.
Insert image description here

Insert image description here

Figure 8-15 Gradient filling and overlay effects, (left) CompositionMode_Difference mode overlay,
(right) RasterOp_NotSourceXorDestination mode overlay

Guess you like

Origin blog.csdn.net/simple_core/article/details/124680965