【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
? ? ? ? 稍微复杂一点的软件,一般都是带有绘图功能。绘图的意义,不仅仅是像CAD一样,可以进行模型的设计、比对和调试。它还可以是流程、仿真和测试功能。当然,如果仿真做的好一点,还可以根据实时传感器拿到的数据进行动画演示。比如大家如果经常看卫星发射,对于仿真界面肯定不陌生。特别是火箭发射的后期,星箭分离的时候,这个时候基本只有动画展示了。
? ? ? ? 如今,我们正好借助于qt平台,看看在qt平台上面是如何进行软件的绘制的。
? ? ? ? 今天,我们实现的功能比较简单,就是利用鼠标实现一个画线的操作。当鼠标被按下去的时候,记录第一个点。在鼠标移动或者鼠标松开的时候,将之前保存的点、当前的点进行直线绘制,同时把当前的点设置为最新的点,为下一次绘制做准备。
? ? ? ? 整个窗口继承了父类QMainWindow。这里面需要实现四个函数,即绘制函数、鼠标按下函数、鼠标移动函数、鼠标松开的函数。注意,这四个函数都是虚函数,我们只需要重新实现即可。另外为了配合着四个函数,还添加pix、lastPoint、endPoint。pix表示画图,lastPoint表示前一个点,end表示当前点。
#pragma once
#include <QtWidgets/QMainWindow>
#include <QMouseEvent>
#include "ui_QtWidgetsApplication.h"
class QtWidgetsApplication : public QMainWindow
{
Q_OBJECT
public:
QtWidgetsApplication(QWidget *parent = nullptr);
~QtWidgetsApplication();
private:
Ui::QtWidgetsApplicationClass ui;
QPixmap pix;
QPoint lastPoint;
QPoint endPoint;
protected:
void paintEvent(QPaintEvent *) override;
void mousePressEvent(QMouseEvent *) override;
void mouseMoveEvent(QMouseEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
};
? ? ? ? 实现过程中主要分成三个部分。第一,需要查看下构造函数是怎么初始化的。这里面比较重要的其实就是pix变量。大家可以把这个pix看成是一个画布,画布上面就是我们绘制的各个形状。当然,画布的内容如果需要显示到窗口上面,还需要调用drawPixelmap拷贝一下。
#include <QPainter>
#include "QtWidgetsApplication.h"
QtWidgetsApplication::QtWidgetsApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
resize(600, 500); // windows size is 600 by 500
pix = QPixmap(600, 500);
pix.fill(Qt::white);
flag = 0;
}
QtWidgetsApplication::~QtWidgetsApplication()
{}
? ? ? ? 前面我们说过,鼠标按下、移动、松开,这三个部分都是重载函数,我们直接重写即可,
void QtWidgetsApplication::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) // mouse left down
lastPoint = event->pos();
}
void QtWidgetsApplication::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons()&Qt::LeftButton) // mouse left down and move
{
endPoint = event->pos();
update(); // trigger painter function
}
}
void QtWidgetsApplication::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) //mouse left release
{
endPoint = event->pos();
update();
}
}
? ? ? ? 鼠标按下的时候,所做的工作就是记录下一个lastPoint。鼠标移动和松开的时候,稍微复杂一点,除了记录endPoint之外,还要trigger一下update。有了这个update,系统就会调用paintEvent这个重载函数,重新绘制下界面。所以,这个函数我们也需要重新编写一下。
void QtWidgetsApplication::paintEvent(QPaintEvent *)
{
QPainter pp(&pix); // pix is the QPixmap
pp.setPen(QPen(QBrush(Qt::black), 3, Qt::SolidLine)); // set width
pp.drawLine(lastPoint, endPoint); // paint line now
lastPoint = endPoint;
QPainter painter(this);
painter.drawPixmap(0, 0, pix);
}
? ? ? ? paintEvent这个函数,个人觉得是整个练习当中最重要的函数。首先pix当中已经有了很多的绘制。这里不过是再增加一条直线而已。所以pp变量绘制的其实是画布的内容。但是仅仅有画布是不够的,我们看到这里还有一个painter变量,它的入参是this,也就是代表这里的绘制才是窗口的绘制,所以它会调用drawPixmap函数,把pix画布的内容拷贝到当前窗口里面。也只有这样,才能实现窗口的内容更新。
? ? ? ? 代码全部设计好之后,就可以开始编译了。编译没有问题,我们打开软件,利用鼠标开始测试的。测试的方法也不复杂,就是在窗口内依次按下鼠标、移动鼠标、松开鼠标,看看窗口上是不是真的有线条出现,如果是这样,那代表编码没有问题,反之就要回头查查原因了。