这一次将介绍如何使用Graphics View来实现前面所说的画板。前面说了很多有关Graphics View的好话,但是没有具体的实例很难说究竟好在哪里。现在我们就把前面的内容使用Graphics View重新实现一下,大家可以对比一下看有什么区别。
同前面相似的内容就不再叙述了,我们从上次代码的基础上进行修改,以便符合我们的需要。首先来看MainWindow的代码:
mainwindow.cpp
#include
"mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QToolBar *bar =
this
->addToolBar(
"Tools"
);
QActionGroup *group =
new
QActionGroup(bar);
QAction *drawLineAction =
new
QAction(
"Line"
, bar);
drawLineAction->setIcon(QIcon(
":/line.png"
));
drawLineAction->setToolTip(tr(
"Draw a line."
));
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(
":/rect.png"
));
drawRectAction->setToolTip(tr(
"Draw a rectangle."
));
drawRectAction->setStatusTip(tr(
"Draw a rectangle."
));
drawRectAction->setCheckable(
true
);
group->addAction(drawRectAction);
bar->addAction(drawRectAction);
QLabel *statusMsg =
new
QLabel;
statusBar()->addWidget(statusMsg);
PaintWidget *paintWidget =
new
PaintWidget(
this
);
QGraphicsView *view =
new
QGraphicsView(paintWidget,
this
);
setCentralWidget(view);
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)));
}
void
MainWindow::drawLineActionTriggered()
{
emit changeCurrentShape(Shape::Line);
}
void
MainWindow::drawRectActionTriggered()
{
emit changeCurrentShape(Shape::Rect);
}
由于mainwindow.h的代码与前文相同,这里就不再贴出。而cpp文件里面只有少数几行与前文不同。由于我们使用Graphics
View,所以,我们必须把item添加到QGprahicsScene里面。这里,我们创建了scene的对象,而scene对象需要通过view进行
观察,因此,我们需要再使用一个QGraphcisView对象,并且把这个view添加到MainWindow里面。
我们把PaintWidget当做一个scene,因此PaintWidget现在是继承QGraphicsScene,而不是前面的QWidget。
paintwidget.h
#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H
#include <QtGui>
#include <QDebug>
#include
"shape.h"
#include
"line.h"
#include
"rect.h"
class
PaintWidget :
public
QGraphicsScene
{
Q_OBJECT
public
:
PaintWidget(QWidget *parent = 0);
public
slots:
void
setCurrentShape(Shape::Code s)
{
if
(s != currShapeCode) {
currShapeCode = s;
}
}
protected
:
void
mousePressEvent(QGraphicsSceneMouseEvent *
event
);
void
mouseMoveEvent(QGraphicsSceneMouseEvent *
event
);
void
mouseReleaseEvent(QGraphicsSceneMouseEvent *
event
);
private
:
Shape::Code currShapeCode;
Shape *currItem;
bool
perm;
};
#endif
// PAINTWIDGET_H
paintwidget.cpp
#include
"paintwidget.h"
PaintWidget::PaintWidget(QWidget *parent)
: QGraphicsScene(parent), currShapeCode(Shape::Line), currItem(NULL), perm(
false
)
{
}
void
PaintWidget::mousePressEvent(QGraphicsSceneMouseEvent *
event
)
{
switch
(currShapeCode)
{
case
Shape::Line:
{
Line *line =
new
Line;
currItem = line;
addItem(line);
break
;
}
case
Shape::Rect:
{
Rect *rect =
new
Rect;
currItem = rect;
addItem(rect);
break
;
}
}
if
(currItem) {
currItem->startDraw(
event
);
perm =
false
;
}
QGraphicsScene::mousePressEvent(
event
);
}
void
PaintWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *
event
)
{
if
(currItem && !perm) {
currItem->drawing(
event
);
}
QGraphicsScene::mouseMoveEvent(
event
);
}
void
PaintWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *
event
)
{
perm =
true
;
QGraphicsScene::mouseReleaseEvent(
event
);
}
我们把继承自QWidget改成继承自QGraphicsScene,同样也会有鼠标事件,只不过在这里我们把鼠标事件全部转发给具体的item进行处理。这个我们会在下面的代码中看到。另外一点是,每一个鼠标处理函数都包含了调用其父类函数的语句。
shape.h
#ifndef SHAPE_H
#define SHAPE_H
#include <QtGui>
class
Shape
{
public
:
enum
Code {
Line,
Rect
};
Shape();
virtual
void
startDraw(QGraphicsSceneMouseEvent *
event
) = 0;
virtual
void
drawing(QGraphicsSceneMouseEvent *
event
) = 0;
};
#endif
// SHAPE_H
shape.cpp
#include
"shape.h"
Shape::Shape()
{
}
Shape类也有了变化:还记得我们曾经说过,Qt内置了很多item,因此我们不必全部重写这个item。所以,我们要使用Qt提供的类,就
不需要在我们的类里面添加新的数据成员了。这样,我们就有了不带有额外的数据成员的Shape。那么,为什么还要提供Shape呢?因为我们在scene
的鼠标事件中需要修改这些数据成员,如果没有这个父类,我们就需要按照Code写一个长长的switch来判断是那一个图形,这样是很麻烦的。所以我们依
然创建了一个公共的父类,只要调用这个父类的draw函数即可。
line.h
#ifndef LINE_H
#define LINE_H
#include <QGraphicsLineItem>
#include
"shape.h"
class
Line :
public
Shape,
public
QGraphicsLineItem
{
public
:
Line();
void
startDraw(QGraphicsSceneMouseEvent *
event
);
void
drawing(QGraphicsSceneMouseEvent *
event
);
};
#endif
// LINE_H
line.cpp
#include
"line.h"
Line::Line()
{
}
void
Line::startDraw(QGraphicsSceneMouseEvent *
event
)
{
setLine(QLineF(
event
->scenePos(),
event
->scenePos()));
}
void
Line::drawing(QGraphicsSceneMouseEvent *
event
)
{
QLineF newLine(line().p1(),
event
->scenePos());
setLine(newLine);
}
Line类已经和前面有了变化,我们不仅仅继承了Shape,而且继承了QGraphicsLineItem类。这里我们使用了C++的多继承
机制。这个机制是很危险的,很容易发生错误,但是这里我们的Shape并没有继承其他的类,只要函数没有重名,一般而言是没有问题的。如果不希望出现不推
荐的多继承(不管怎么说,多继承虽然危险,但它是符合面向对象理论的),那就就想办法使用组合机制。我们之所以使用多继承,目的是让Line类同时具有
Shape和QGraphicsLineItem的性质,从而既可以直接添加到QGraphicsScene中,又可以调用startDraw()等函
数。
同样的还有Rect这个类:
rect.h
#ifndef RECT_H
#define RECT_H
#include <QGraphicsRectItem>
#include
"shape.h"
class
Rect :
public
Shape,
public
QGraphicsRectItem
{
public
:
Rect();
void
startDraw(QGraphicsSceneMouseEvent *
event
);
void
drawing(QGraphicsSceneMouseEvent *
event
);
};
#endif
// RECT_H
rect.cpp
#include
"rect.h"
Rect::Rect()
{
}
void
Rect::startDraw(QGraphicsSceneMouseEvent *
event
)
{
setRect(QRectF(
event
->scenePos(), QSizeF(0, 0)));
}
void
Rect::drawing(QGraphicsSceneMouseEvent *
event
)
{
QRectF r(rect().topLeft(),
QSizeF(
event
->scenePos().x() - rect().topLeft().x(),
event
->scenePos().y() - rect().topLeft().y()));
setRect(r);
}
Line和Rect类的逻辑都比较清楚,和前面的基本类似。所不同的是,Qt并没有使用我们前面定义的两个Qpoint对象记录数据,而是在
QGraphicsLineItem中使用QLineF,在QGraphicsRectItem中使用QRectF记录数据。这显然比我们的两个点的数据
记录高级得多。其实,我们也完全可以使用这样的数据结构去重定义前面那些Line之类。
这样,我们的程序就修改完毕了。运行一下你会发现,几乎和前面的实现没有区别。这里说“几乎”,是在第一个点画下的时候,scene会移动一段距离。这是因为scene是自动居中的,由于我们把Line的第一个点设置为(0, 0),因此当我们把鼠标移动后会有一个偏移。
看到这里或许并没有显示出Graphics View的优势。不过,建议在Line或者Rect的构造函数里面加上下面的语句,
setFlag(QGraphicsItem::ItemIsMovable,
true
);
setFlag(QGraphicsItem::ItemIsSelectable,
true
);
此时,你的Line和Rect就已经支持选中和拖放了!值得试一试哦!不过,需要注意的是,我们重写了scene的鼠标控制函数,所以这里的拖动会很粗糙,甚至说是不正确,你需要动动脑筋重新设计我们的类啦!
本文出自 “豆子空间
” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/244181
分享到:
相关推荐
本教程将基于Qt框架,介绍如何创建一个简单的画板应用,旨在帮助初学者理解Qt界面编程的基础以及绘图功能的实现。 首先,我们需要了解Qt的Widgets模块,它是构建用户界面的基础。在这个简易画板项目中,我们将使用...
现代OpenGL+Qt学习笔记之二:程序框架http://blog.csdn.net/chaojiwudixiaofeixia/article/details/77917697源码。
QT GraphicsView框架是Qt库中的一个强大组件,用于创建复杂的2D图形用户界面。这个框架是基于三层架构设计的,包括视图(View)、场景(Scene)和图形项(Graphics Item)。下面将详细阐述这三个核心组件以及它们在...
一个简易画板的实现 有简单的画图,画图形,改颜色功能
这个简易画板程序是学习Qt GUI编程的一个良好起点,涵盖了基本的窗口创建、事件处理和图形绘制。随着技能的提升,可以进一步优化程序,如添加撤销/重做功能、多层绘图、自定义形状工具等。Qt提供的强大功能使得...
总的来说,"QT做的简易画板"是一个很好的学习和实践Qt编程的例子,它涉及到GUI设计、事件处理、绘图操作等多个关键领域,同时也展示了Qt框架在开发高效、功能丰富的应用程序方面的强大能力。通过这个项目,开发者...
QT Graphics View Framework 是一个强大的图形视图框架,用于在Qt应用程序中创建复杂的、交互式的2D图形用户界面。这个框架提供了丰富的功能,如缩放、旋转、拖动以及高效的图形渲染,非常适合开发需要大量视觉元素...
综上所述,QT简易画板提供了一个简单易用的环境,让用户能够轻松地进行基本的图形绘制和编辑,同时利用了QT库的强大功能,实现了图形的高效管理和操作。无论是学习还是实际应用,这款工具都有其独特价值。
【Qt简易画板】是一个基于Qt框架开发的简单绘图应用程序,主要利用了QPainterPath类的强大功能,为用户提供一个可以自由绘制各种图形的平台。这个项目虽然在类设计上可能略显粗糙,但对于初学者来说,是一个很好的...
在IT领域,尤其是在GUI应用程序开发中,`QGraphicsView`框架是Qt库中的一个重要组成部分,它为创建复杂的、可交互的2D图形视图提供了强大的支持。本篇将深入探讨`QGraphicsView`框架实现画板的相关知识点,以及如何...
Qt Graphics View是Qt库中的一个强大框架,专为创建复杂的、图形密集型用户界面而设计。这个框架允许开发者以一种灵活、高效的方式处理2D图形,包括缩放、旋转、平移以及对象交互等操作。在Qt应用中,Graphics View...
1. **Qt GraphicsView框架**:GraphicsView框架是Qt提供的一组类,包括QGraphicsScene、QGraphicsView和QGraphicsItem等,用于构建基于 scenegraph 的2D图形系统。它允许开发者创建复杂的交互式图形界面,支持缩放、...
Graphics View框架的绘图过程通常包括以下几个步骤:创建一个场景,创建图元对象(如直线对象、多边形对象等),使用场景的add()函数将图元对象添加到场景中,最后通过视图进行显示。对于复杂的图像,管理图元对象比...
12. "GRAPHICSVIEWFRAMEWORK" 和 "一个简易画板的实现" 可能是关于Qt的Graphics View框架,这是一个用于管理和显示大量自定义2D图形的框架。 13. "国际化" 讨论了如何为应用程序添加多语言支持。 14. "QT容器类之...
在Qt框架中,Graphics View是用于创建复杂图形用户界面(GUI)的一个强大模块,它允许开发者以图形化的方式展示和操作对象。本教程将详细解析如何使用Qt 5.14.2版本中的Graphics View来绘制图形,这对于初学者来说是...
现代OpenGL+Qt学习笔记之三:显示一个彩色三角形http://blog.csdn.net/chaojiwudixiaofeixia/article/details/77927876源码。
现代OpenGL+Qt学习笔记之四:使用Uniform变量实现对模型的旋转http://blog.csdn.net/chaojiwudixiaofeixia/article/details/77944140源码
在本案例中,"QT实现画板源代码(雏形)"是一个基于QT的项目,目的是提供一个基本的绘图板实现,帮助初学者理解和实践如何在QT环境中进行图形绘制。这个项目的代码来源于一篇名为《QT零基础绘图3》的教程,其目标是...
### Qt学习之路知识点总结 #### 一、前言:Qt简介与选择 - **Qt**是一种跨平台的应用程序开发框架,广泛应用于桌面、移动设备及嵌入式系统的GUI应用程序开发。 - C++的GUI编程并非C++标准的一部分,因此开发者在...
QT的GraphicsView框架是Qt库中的一个重要组成部分,它提供了一个高度可定制的2D图形视图,用于在窗口中显示和操作复杂的图形元素。GraphicsView框架适用于创建绘图应用程序、图表、游戏等,其核心是GraphicsView、...