文章目录
- 一、绘图
- 1. 理论知识储备
- 2. 画背景图
- 3. 简单绘图
- 4. 手动刷新窗口
- 二、绘图实现代码
- 1. 主窗口头文件 widget.h
- 2. 主窗口头文件 widget.cpp
由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见
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()
}