Qt Creator实现简易画板代码解析【工具栏】【画板】

演示效果

Qt Creator实现简易画板代码解析【工具栏】【画板】_第1张图片

工具栏通常位于菜单栏的下方,上面存放着一些小按钮,如下图所示。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第2张图片
以下所有功能都是直接通过代码实现,而不是在设计模式下ui界面通过拖拽实现。当然,它是可以用拖拽实现的。

引入图片资源

图片资源主要是用于动作的图标。在工程文件里面创建一个picture文件夹,然后在PPT截图了两张图片用作图标,图片格式没要求。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第3张图片
在该项目的基础上,点击QT菜单栏【文件】→【新建文件或项目】,左边选择【Qt】,中间选择【Qt Resource File】,选择【Chose】,自己命个名,然后不断下一步即可。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第4张图片
会发现工程里面多了Resources文件夹,这个myres就是我刚才命名的。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第5张图片
右键点击Resources,选择【Add Existing Directory】(添加现存的目录),出现以下界面把图片选上就行了。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第6张图片
然后目录就变成了这样,至此已经完成图片资源的导入。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第7张图片

新建工具栏并导入动作

mainwindow.cpp文件内容;

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QToolBar *bar = new QToolBar;   //新建工具栏
    this->addToolBar(bar);          //将工具栏添加到这个窗口

    QActionGroup *group = new QActionGroup(bar);   //新建动作组合

    QAction *drawLineAction = new QAction("Line", bar);
    drawLineAction->setIcon(QIcon(":/picture/line.jpg"));   //图标
    drawLineAction->setToolTip(tr("Draw a line1.")); //工具栏提示
    drawLineAction->setStatusTip(tr("Draw a line."));//下面状态栏文本
    drawLineAction->setCheckable(true);
    drawLineAction->setChecked(true);
    group->addAction(drawLineAction);       //向动作组合添加一个新动作
    bar->addAction(drawLineAction);         //向工具栏添加动作


    QAction *drawRectAction = new QAction("Rectangle", bar);
    drawRectAction->setIcon(QIcon(":/picture/rect.jpg"));
    drawRectAction->setToolTip(tr("Draw a rectangle1."));
    drawRectAction->setStatusTip(tr("Draw a rectangle."));
    drawRectAction->setCheckable(true);
    group->addAction(drawRectAction);
    bar->addAction(drawRectAction);

}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.h文件内容,主要是要引入对应的include。
在这里插入图片描述
效果:
Qt Creator实现简易画板代码解析【工具栏】【画板】_第8张图片

代码解析

    QToolBar *bar = new QToolBar;   //新建工具栏
    this->addToolBar(bar);          //将工具栏添加到这个窗口

工具栏对应的类是QToolBar,使用需要添加#include 。接下来要用addToolBar函数把工具栏添加到主窗口,也就是this对应的指针。addToolBar函数通过名字就很好理解,就是往某个窗口添加工具栏。

QActionGroup *group = new QActionGroup(bar);   //新建动作组合

QActionGroup类对应的是动作组合,使用需要添加#include 。这个类对应的是多个动作,适应的情况是存在多个动作,但是某一时刻只有一个动作是激活状态,即他们是互斥的。比如常见的左对齐、右对齐、居中对齐,他们是仅有一个生效的。利用QActionGroup类可以简单达到这种互斥的效果。

    QAction *drawLineAction = new QAction("Line", bar);
    drawLineAction->setIcon(QIcon(":/picture/line.jpg"));   //图标
    drawLineAction->setToolTip(tr("Draw a line1.")); //工具栏提示
    drawLineAction->setStatusTip(tr("Draw a line."));//下面状态栏文本
    drawLineAction->setCheckable(true);
    drawLineAction->setChecked(true);
    group->addAction(drawLineAction);       //向动作组合添加一个新动作
    bar->addAction(drawLineAction);         //向工具栏添加动作

QAction类对应的是单个动作,使用需要添加#include 。第一句代码就是生成了一个动作实例,父对象是bar,即工具栏。下面对应的是这个动作的不同属性,通过对应的函数分别设置。

1.setIcon函数:图标很好理解,使用图标需要提前导入图片资源,也就是文章最前面部分。并且要用QIcon强制转换为图标类型。
2.setToolTip函数:当鼠标放在图标上面出现的文字提示。
在这里插入图片描述
3.SetStatusTip函数:当鼠标放在图标上,状态栏出现的文字提示。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第9张图片
3.setCheckable函数:
这个函数设定这个动作是否是可复用动作。默认情况它的取值是false,即不复用。对应的表现就是按下动作之后,会自动弹起。类比一下按钮,按一下按钮,按钮会自动恢复。类似保存文件之类动作,按下就执行动作,然后自动弹起,并不存在两种状态,所以保持默认false即可。
如果通过函数设定为true,那就是可复用状态。那这个属性适用于哪种场景呢?比如字体的粗细,按下就是粗体,然后保持粗体,再按下弹起来,恢复正常。这就是动作的复用,存在两种状态。
4.setChecked函数:
这个函数对应的是上面那个属性,只有动作是checkable状态,才可以设置。默认情况下,checked属性是false,即不选中。如果设置为true,当你打开的时候,这个动作就默认已经被选中。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第10张图片

在状态栏添加标签控件

QLabel是标签控件,使用需要#include 。主要用于显示信息。statusBar是新建的MainWindow项目默认的状态栏,然后通过addWidget函数把标签控件加入状态栏,后续可以直接在标签里面设置显示文本,这样状态栏就会出现对应信息。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第11张图片

实现槽与信号的连接

1.新建信号与槽函数

上述我们只是实现了工具栏的框架,只能点一点,看一看,但是没啥反应。

在mainwindow.h中添加自定义的信号和两个槽函数,这个自定义的信号用于发送画线还是画矩形,函数有一个参数来表示shape。Shape类也是自定义的类,后面会继续介绍。

signals:
        void changeCurrentShape(Shape::Code newShape);

private slots:
        void drawLineActionTriggered();
        void drawRectActionTriggered();

在mainwindow.cpp文件实现两个槽函数,即发送对应的信号。至于这两个槽函数由什么控件触发,后续介绍。

void MainWindow::drawLineActionTriggered() 
{ 
    emit changeCurrentShape(Shape::Line); 
} 

void MainWindow::drawRectActionTriggered() 
{ 
    emit changeCurrentShape(Shape::Rect); 
}
2.connect连接

在mainwindow.cpp文件中的MainWindow::MainWindow函数添加三个connect将信号与槽对接起来。

drawLineAction和drawRectAction是上面创建的两个动作,点击这两个动作会发出triggered信号。但是这个信号是不带参数的,而接收信号的画板就区分不了两者。所以才需要新建一个新的带参数的信号。

流程如下:点击画直线图标,触发triggerrd信号,进入槽函数drawLineActionTriggered函数,在此函数emit一个带有Shape::Line参数的信号。这样画板就知道该画直线了。

	//连接信号与槽
    connect(drawLineAction, SIGNAL(triggered()), 
                    this, SLOT(drawLineActionTriggered())); 
    connect(drawRectAction, SIGNAL(triggered()), 
                    this, SLOT(drawRectActionTriggered())); 
    connect(this, SIGNAL(changeCurrentShape(Shape::Code)), 
                    paintWidget, SLOT(setCurrentShape(Shape::Code)));
3.建立画图板

新建下面这些新文件。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第12张图片

1)shape类

先看看shape相关文件,这是Line和Rect的父类。
shape.h

#ifndef SHAPE_H
#define SHAPE_H

#include 
class Shape
{
public:

        enum Code {
                Line,
                Rect
        };

        Shape();

        void setStart(QPoint s)
        {
                start = s;
        }

        void setEnd(QPoint e)
        {
                end = e;
        }

        QPoint startPoint()
        {
                return start;
        }

        QPoint endPoint()
        {
                return end;
        }

        void virtual paint(QPainter & painter) = 0;

protected:
        QPoint start;
        QPoint end;
};
#endif // SHAPE_H

Shape存在两个QPoint点,起点和终点,通过这两个数据确定直线和矩形的大小。paint函数是一个虚函数,实际实现需要子类具体实现。Code是一个枚举向量,用来表示直线还是矩形。
shape.cpp

#include "shape.h"

Shape::Shape()
{
}

2)line类

line.h

#ifndef LINE_H
#define LINE_H
#include "shape.h"

class Line : public Shape
{
public:
        Line();

        void paint(QPainter &painter);
};
#endif // LINE_H

line.cpp

#include "line.h"

Line::Line()
{
}

void Line::paint(QPainter &painter)
{
        painter.drawLine(start, end);
}

line类继承于Shape,主要就是实现了画直线的操作。QPainter类是专门用于画图的类,使用需要#include 。drawLine是内置的画直线函数,只需要起点和终点两个参数,这两参数来自于父类Shape。

3)Rect类

rect.h

#ifndef RECT_H
#define RECT_H
#include "shape.h"

class Rect : public Shape
{
public:
        Rect();

        void paint(QPainter &painter);
};
#endif // RECT_H

rect.cpp

#include "rect.h"

Rect::Rect()
{
}

void Rect::paint(QPainter &painter)
{
    painter.drawRect(start.x(), start.y(),end.x() - start.x(), end.y() - start.y());
}

和Line类的区别就是换了drawRect函数,这是画矩形的专门函数。四个参数分别代表左上角顶点的x、y、矩形的宽度、矩形的高度。start和end是QPoint类,他们的成员函数x()和y()可以获取这个点的xy坐标。

4)paintwidget类

PaintWidget是自定义的画板类,需要添加对应的头文件以及源文件。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第13张图片
paintwidget.h文件。

#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H
#include 
#include 
#include "shape.h"
#include "line.h"
#include "rect.h"
#include 

class PaintWidget : public QWidget
{
        Q_OBJECT

public:
        PaintWidget(QWidget *parent = 0);

public slots:
        void setCurrentShape(Shape::Code s)
        {
                if(s != currShapeCode) {
                        currShapeCode = s;
                }
        }

protected:
        void paintEvent(QPaintEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);

private:
        Shape::Code currShapeCode;
        Shape *shape;
        bool perm;
        QList shapeList;
};
#endif // PAINTWIDGET_H

PaintWidget类定义了一个槽函数,用于接收绘制形状的Shape::Code.

PaintWidget重定义了三个关于鼠标的事件:mousePressEvent,mouseMoveEvent和mouseReleaseEvent。这三个函数是父类的虚函数,我们可以重新定义函数内容。

QList是一个列表,主要是用于存储历史图片。

paintwidget.cpp文件。

#include "paintwidget.h"

PaintWidget::PaintWidget(QWidget *parent)
        : QWidget(parent), currShapeCode(Shape::Line), shape(NULL), perm(false)
{
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}

void PaintWidget::paintEvent(QPaintEvent *event)
{
        QPainter painter(this);
        painter.setBrush(Qt::white);
        painter.drawRect(0, 0, size().width(), size().height());
        foreach(Shape * shape, shapeList) {
                shape->paint(painter);
        }
}

void PaintWidget::mousePressEvent(QMouseEvent *event)
{
        switch(currShapeCode)
        {
        case Shape::Line:
                {
                        shape = new Line;
                        break;
                }
        case Shape::Rect:
                {
                        shape = new Rect;
                        break;
                }
        }
        if(shape != NULL) {
                perm = false;
                shapeList<setStart(event->pos());
                shape->setEnd(event->pos());
        }
}

void PaintWidget::mouseMoveEvent(QMouseEvent *event)
{
        if(shape && !perm) {
                shape->setEnd(event->pos());
                update();
        }
}

void PaintWidget::mouseReleaseEvent(QMouseEvent *event)
{
        perm = true;
}

鼠标点击函数: 根据PaintWidget类的currShapeCode决定绘制直线还是矩形。shape是PaintWidget类一个指向Shape的指针。perm是PaintWidget类的成员,表示绘制是否结束。

将目前的图形shape存入列表shaoeList。将目前鼠标的位置pos设定为图形的起点和终点。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第14张图片
鼠标移动函数:
只要perm标志位没有变为true,在移动的过程中,将鼠标的位置设定为shape的结束点,并且通过update更新画板。

update函数是paintEvent提供的刷新函数,每次调用,都会重绘事件。相当于画笔随着鼠标的移动在不断地画线。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第15张图片
鼠标释放函数:
当鼠标释放的时候,perm变为true,所以此时移动鼠标,就不会改变终点,也不会刷新画板,相当于就图片就确定了。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第16张图片
重绘事件处理函数:
基础控件类QWidget提供的paintEvent函数是一个纯虚函数,继承它的子类想要进行重绘就必须重新实现。通过QPainter类定义了一个画家,通过setBrush函数设置画刷颜色为白色(主要是内部填充)。

drawRect函数就是画了一个和窗口等大的白底框,如果没有这句代码,背景就是灰色的。

foreach就是把shapeList的图形都画出来。比如我们先画了一个矩形,再画直线,直线update的时候就会把矩形给覆盖掉。所以每次刷新都需要把之前的图案再次画出来。
Qt Creator实现简易画板代码解析【工具栏】【画板】_第17张图片
在mainwindow.cpp文件中的MainWindow::MainWindow函数添加画板。

    //定义一块画图板
    PaintWidget *paintWidget = new PaintWidget(this);
    //设置为中心窗口
    setCentralWidget(paintWidget);  

参考文章:
Qt 一个简易画板的实现(QWidget)

你可能感兴趣的:(QT学习记录,qt,开发语言)