说明:这是我们Qt系列文章的一个例子,请先学习2D绘图部分内容,再学习本教程
前面学习了Qt 2D
绘图的基本知识,现在我们将所学习的知识进行一下综合,设计一个简单的画图软件。
因为前面已经有了记事本的例子,所以这里对一些细节知识将不会多讲。而且,这只是个例子,说是软件,其实只是个较大点的程序而已,并不是实际的项目,所以通过这个例子,我们主要为了掌握一个方法和两个知识点。
一个方法:写较复杂程序的方法。 两个知识点:文件菜单的功能实现和利用双缓冲进行绘图。 这个例子共分为三部分进行介绍: 第一部分:进行软件界面的设计。其中一些知识可以参考我博客中的Qt教程四。 第二部分:实现基本的功能,这里会再次详细介绍文件菜单中新建,打开,保存,另存为,关闭等菜单的功能实现。这里你可以参考我博客中的Qt教程六。 第三部分:我们在这里会详细讲解所谓的双缓冲绘图,利用它实现图形(例如矩形,椭圆)的交互式绘制。
第一部分:设计界面
在windows上自带了画图软件,在Qt Creator中也有个绘图软件的例子scribble example
,你可以在帮助中进行查看。
而现在我们要写的绘图程序的例子,也应该包含这些功能,如绘画涂鸦,添加直线或矩形等常用图形,可以插入图片,在图片上进行绘画,可以让它缩放
,旋转
,拉伸
等。想到了这些功能,我们就可以设计软件的界面了。
一.设计菜单
- 在QtCreator中新建Qt4 Gui Application工程,我这里使用的工程名为paint,使用默认的QMainWindow作为主窗口。
- 为了让程序中可以使用中文,我们先在main.cpp中加入头文件
#include <QTextCodec>
,
并加入下面一行代码:QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
- 打开
mainwindow.ui
,先设计菜单。依次是文件
菜单,编辑
菜单,工具
菜单和帮助
菜单。其内容分别如下:
文件菜单
编辑菜单
工具菜单
帮助菜单
- 向工程中添加资源文件,向其中添加要使用的菜单图标。
添加完后记着保存
一下资源文件,不然的话,在资源管理器中可能看不到添加的图标。 - 打开动作编辑器
Action Editor
,编辑已添加的菜单动作。
我们下面只介绍其中“新建
”菜单的编辑,其余菜单照做就行了。
双击action_N
,弹出如下对话框:
单击Icon
后面的按钮,弹出资源管理器:
我们点击上面的Reload
,便能显示出我们已经添加的图标,我们选中其中的新建菜单的图标,点击Ok确认
,如下图所示:
然后我们再在右面的属性窗口中更改statusTip
的内容为“新建文件
”,这样在鼠标放在新建菜单上是,状态栏就会显示
“新建文件”。如下图:
我们按照同样的方法设置其它菜单
,设置完成后如下图所示:
- 我们把其中的一些图标放到
工具栏
上,如下图所示:
这样就完成了菜单的设计。
二.添加绘图工具栏
我们这里的绘图工具栏使用的是一种叫做Dock的窗口
,它与其它窗口的不同就是它可以在其父窗口中浮动,也可以停靠在父窗口的边界,就像一个工具栏一样。
- 我们在左边的部件栏中找到
Dock Widget
,将其拖入到设计区。
添加后它默认在左边框上停靠着。如下图:
- 我们在其属性栏里将其
windowTitle
改为“画图工具
”。 - 向其中拖入相关部件,效果如下图:
其中,画笔线宽
下的部件为Spin Box
,其属性中的objectName
为penWidthSpinBox
,属性栏最下面的minimum
属性改为1
,即最小值为1。
其余部件均为组合框ComboBox
,objectName依次为:
选择图形:shapeComboBox
画笔类型:penStyleComboBox
画笔颜色:penColorComboBox
填充颜色:brushColorComboBox
- 我们给选择框添加条目。
右击“选择图形
”下面的组合框,弹出菜单,如下:
我们点击Edit Items
菜单,弹出下面的条目编辑框,我们点击“+
”按钮,添加新的条目:
我们依次添加“无
”“直线
”“矩形
”“椭圆
”四个条目,如下所示:
同样的我们给“画笔类型
“下的组合框添加两个条目“实线
”和“点线
”。两个颜色组合框的条目以后再添加。 - 最后可以让所有部件处于一个网格布局管理器中。
此时运行程序,效果如下:
拖动画图工具栏后效果如下:
三.添加画布
因为画布是真正实现绘图功能的,所以我们新建一个类来实现所有跟绘图有关的功能。这里先进行操作,对于一些内容到后面我们会详细解释的。
- 往工程中添加新的
C++类
,类名为PaintArea
,以QWidget
作为基类,如下所示:
2.在paintArea.h
中声明对象和函数。
我们这里使用了QImage类
对象进行绘图,其实使用以前讲过的QPixmap类对象也是可以的。
class PaintArea : public QWidget { public: PaintArea(); protected: void paintEvent(QPaintEvent *); //重绘事件 private: QImage image; //QImage类对象,用于在其上绘图 QRgb backColor; //QRgb颜色对象,存储image的背景色 };
- 在
paintarea.cpp
中的构造函数里初始化对象。
先加入头文件声明:#include <QPainter>
再更改构造函数:
PaintArea::PaintArea() { image = QImage(400,300,QImage::Format_RGB32); //画布的初始化大小设为400*300,使用32位颜色 backColor = qRgb(255,255,255); //画布初始化背景色使用白色 image.fill(backColor); }
- 在paintarea.cpp中定义重绘函数。
void PaintArea::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawImage(0,0,image); }
- 将画布添加到主界面的中心区。
因为以后可能要使用很大的画布,这样为了使画布很大时还能显示,我们需要加入滚动条,所以这里使用了QScrollArea
类对象,它提供了横向和纵向的滚动条,如果你有兴趣,可以在帮助中查看它的介绍。
首先,在mainwindow.h
文件中进行如下操作:
添加头文件声明:
#include “paintarea.h” #include <QScrollArea>
在下面的`private`中添加对象的声明:
`PaintArea *area;` `QScrollArea *scrollArea;`
然后在`mainwindow.cpp`文件中的构造函数里添加代码:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); resize(700,500); //主窗口大小设为700*500 area = new PaintArea; scrollArea = new QScrollArea; scrollArea->setBackgroundRole(QPalette::Dark); //scrollArea对象的背景色设为Dark scrollArea->setWidget(area); //将画布添加到scrollArea中 scrollArea->widget()->setMinimumSize(800,600); //scrollArea初始化大小设为800*600 setCentralWidget(scrollArea); //将scrollArea加入到主窗口的中心区 }
这时运行程序,效果如下:
四.实现涂鸦的功能
我们在画布类中添加一些代码,实现最基本的涂鸦功能。
- 在
paintarea.h
中做更改。
添加头文件:
#include <QMouseEvent>
#include <QPoint>
在protected
中添加函数声明:
void mousePressEvent(QMouseEvent *); //鼠标按下事件
void mouseMoveEvent(QMouseEvent *); //鼠标移动事件
void mouseReleaseEvent(QMouseEvent *); //鼠标释放事件
在private
中添加对象声明:
QPoint lastPoint,endPoint; //定义两个坐标对象存放鼠标指针的前后两个坐标
- 在
paintarea.cpp
中添加函数的定义。
void PaintArea::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) //当鼠标左键按下 { lastPoint = event->pos(); //获得鼠标指针的当前坐标作为起始坐标 } } void PaintArea::mouseMoveEvent(QMouseEvent *event) { if(event->buttons()&Qt::LeftButton) //如果鼠标左键按着的同时移动鼠标 { endPoint = event->pos(); //获得鼠标指针的当前坐标作为终止坐标 paint(image); //绘制图形 } } void PaintArea::mouseReleaseEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) //如果鼠标左键释放 { endPoint = event->pos(); paint(image); } } void PaintArea::paint(QImage &theImage) { QPainter pp(&theImage); //在theImage上绘图 pp.drawLine(lastPoint,endPoint); //由起始坐标和终止坐标绘制直线 lastPoint = endPoint; //让终止坐标变为起始坐标 update(); //进行更新界面显示,可引起窗口重绘事件,重绘窗口 }
这样,再次运行程序就能实现涂鸦的功能了,效果如下: