文章目录
由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见
QT 学习笔记(一)
提示:具体项目准备工作和细节讲解见
QT 学习笔记(二)
一、绘图
- 生成一个新的项目,具体步骤过程见提示。
1. 理论知识储备
使用 QT 画图的操作比较类似对文件进行操作,不会太难,控件较多。
QT 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制。
整个绘图系统基于 QPainter,QPainterDevice 和 QPaintEngine 三个类。
QPainter 是用来执行绘制的操作;
QPaintDevice 是一个二维空间的抽象,这个二维空间允许QPainter在其上面进行绘制,也就是QPainter工作的空间;
QPaintEngine 提供了画笔(QPainter)在不同的设备上进行绘制的统一的接口。QPaintEngine 类应用于 QPainter 和 QPaintDevice 之间,通常对开发人员是透明的。除非需要自定义一个设备,否则是不需要关心 QPaintEngine 这个类的。
因此,我们可以把 QPainter 理解成画笔;把 QPaintDevice 理解成使用画笔的地方,比如纸张、屏幕等;而对于纸张、屏幕而言,肯定要使用不同的画笔绘制,为了统一使用一种画笔,我们设计了 QPaintEngine 类,这个类让不同的纸张、屏幕都能使用一种画笔。
下图给出了这三个类之间的层次结构:
- 由这个层次结构可知,QT 的绘图系统实际上是,使用 QPainter 在 QPainterDevice 上进行绘制,它们之间使用 QPaintEngine 进行通讯(也就是翻译 QPainter 的指令)。
2. 画背景图
在使用 QT 进行窗口绘图时,一定要选择 QWidget。
在绘图事件当中,我们需要注意的是:
(1) 在主窗口头文件 widget.h 当中的 protected 下进行重写绘图事件的定义。
(2) 如果我们想要在窗口绘图,就必须放在绘图事件里实现。
(3) 当窗口需要重绘的时候,也就是窗口的状态发生改变,就像我们点击按钮,调整窗口的大小使其发生变化等操作,绘图事件会内部自动调用。
当我们进行绘图事件构造函数的编写时,通过调用帮助文档(如下图所示),得知需要指定一个绘图设备,指定当前设备使用 this 指针即可。
对于绘图事件当中,绘图设备的指定有如下方法:
方法一:QPainter p(this);然后直接进行绘图操作。
方法二:首先,创建画家对象 QPainter p;然后指定当前窗口为绘图设备 p.begin(this);但是需要在结束时使用 p.end();在 begin 和 end 之间进行绘图操作,p.drawxxx()。
在上述工作完成后,开始进行背景图的绘制。背景图的绘制函数为:
//画背景图
//画背景图 p.drawPixmap(0,0,width(),height(),QPixmap("../tuoian/5.jpg")); //p.drawPixmap(rect(),QPixmap("../tuoian/5.jpg"));
在我们一般背景图的绘制过程当中,通常是窗口有多大就绘制多大。因此,从 0,0 坐标开始,也就是窗口的左上角,然后选择窗口的宽度函数 width() 和窗口的高度函数 height(),最后定义图片的标签,这里需要注意的是,图片所在的路径要与代码所在的上一级路径相同,不要放到代码所在的文件夹当中,除非是资源,否则会看不到图片。路径放置如下图所示:
得到如下实现结果:
当我们用鼠标更改图片大小时,背景图不会发生变化。
3. 简单绘图
- 记住要先画背景,在画其他的,否则会被背景覆盖。
- 在绘图函数中不要进行太过于复杂的数据处理,否则程序运行很慢。
- 画直线:这四个参数分别表示起点的 x 坐标和 y 坐标,终点的 x 坐标和 y 坐标。
//画直线 p.drawLine(50,50,150,50); p.drawLine(50,50,50,150);
- 在这里,我们发现画的直线有点窄,可能会导致在实际情况当中看不清。因此,我们要定义一个画笔。
- 画笔:画笔的头文件是 QPen ,这里的宽度单位是像素。当设置好画笔的线宽之后,仍需将把画笔交给画家,这样我们设置的线宽才会发生作用。
//定义画笔 QPen pen; pen.setWidth(5);//设置线宽 //把画笔交给画家 p.setPen(pen);
- 除了对线宽进行设置外,还可以对线的颜色、样式等属性进行设置(具体现象不做演示,只讲方法)。
- 颜色有两种设置方法:可以直接使用 red、blue 等简单颜色;也可以使用 RGB 对颜色进行设置(这里有一个小技巧,我们可以将鼠标放到设置的颜色上,就会显现出具体的颜色)。
- 样式可以通过调用帮助文档,选择我们所需要的(其他的属性也是一样的道理,通过 f1 调用帮助文档查看即可)。
画图形:
p.drawRect() 是矩形绘画函数,其参数分别表示起点的 x 坐标,起点的 y 坐标,矩形的长度,矩形的宽度(起点坐标是相对于窗口的右上角而言的)。
p.drawEllipse() 是圆形绘画函数,其参数分别表示圆心所在点的坐标,水平上圆的半径,垂直上圆的半径(当水平半径和垂直半径相同时就是圆,不同就是椭圆)
//画矩形 p.drawRect(150,150,100,50); //画圆 p.drawEllipse(QPoint(150,150),50,25);
- 在这里我们发现,只有所画图形的轮廓,如果我们想要将其内部进行填充,就需要使用画刷工具。
- 画刷:画刷的头文件是 QBrush 。画刷的颜色和样式设置方法与画笔相同,在此就不过多赘述了。将画刷的各项属性设置完成后,还需将画刷交给画家,这样子才可以正确使用。
//创建画刷对象 QBrush brush; brush.setColor(Qt::red);//设置简单颜色 brush.setStyle(Qt::Dense1Pattern);//设置样式 //把画刷交给画家 p.setBrush(brush);
4. 手动刷新窗口
手动刷新窗口,需要我们对窗口进行重绘。其现象应该是当我们按下按钮,整个窗口进行重绘,图形按指定方式进行移动,因此,要先在 ui 界面上放置一个按钮,并将按钮转到槽函数,单击 on_pushButton_clicked() 函数即可。代码和实现现象如下所示:
void Widget::on_pushButton_clicked() { x+=20;//每点击一下水平向右移动20 if(x>width()) { x=0; } //刷新窗口,让窗口重绘,整个窗口都刷新 update();//间接调用paintEvent() }
这里需要注意的是,update() 不要放在 paintEvent() 函数下,否则会造成死循环。
二、绘图实现代码
1. 主窗口头文件 widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget(); protected: //重写绘图事件,虚函数 //如果在窗口绘图,必须放在绘图事件里实现 //绘图事件内部自动调用,窗口需要重绘的时候(窗口状态改变,例如:点击按钮,窗口大小变化) void paintEvent(QPaintEvent *); private slots: void on_pushButton_clicked(); private: Ui::Widget *ui; int x; }; #endif // WIDGET_H
2. 主窗口头文件 widget.cpp
#include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QPen> #include <QBrush> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); x=0;//初始坐标设置为0 } Widget::~Widget() { delete ui; } void Widget::paintEvent(QPaintEvent *) { // 方法一: //QPainter p(this); //方法二: QPainter p; //创建画家对象 p.begin(this); //指定当前窗口为绘图设备 //begin和end之间是绘图操作 //p.drawxxx(); //画背景图 p.drawPixmap(0,0,width(),height(),QPixmap("../tuoian/5.jpg")); //p.drawPixmap(rect(),QPixmap("../tuoian/5.jpg")); //定义画笔 QPen pen; pen.setWidth(5);//设置线宽 //pen.setColor(Qt::red);//设置简单颜色 pen.setColor(QColor(124,9,234));//RGB设置颜色 pen.setStyle(Qt::DashLine);//设置线的风格 //把画笔交给画家 p.setPen(pen); //画直线 p.drawLine(50,50,150,50); p.drawLine(50,50,50,150); //创建画刷对象 QBrush brush; brush.setColor(Qt::red);//设置简单颜色 brush.setStyle(Qt::Dense1Pattern);//设置样式 //把画刷交给画家 p.setBrush(brush); //画矩形 p.drawRect(150,150,100,50); //画圆 p.drawEllipse(QPoint(150,150),50,25); //画运动图形 p.drawPixmap(x,180,80,80,QPixmap("../tuoian/6.jpg")); p.end(); } void Widget::on_pushButton_clicked() { x+=20;//每点击一下水平向右移动20 if(x>width()) { x=0; } //刷新窗口,让窗口重绘,整个窗口都刷新 update();//间接调用paintEvent() }