在图形视图框架中,QGraphicsScene 提供一个快速的接口,用于管理大量 item,QGraphicsItem 是场景中 item 的基类。
图形视图提供了一些典型形状的标准 item,当然,我们也可以自定义 item。除此之外,QGraphicsItem 还支持以下特性:
-
鼠标按下、移动、释放和双击事件,以及鼠标悬浮事件、滚轮事件和上下文菜单事件
-
键盘输入焦点和键盘事件
-
拖放
-
分组:通过父子关系,或 QGraphicsItemGroup
-
碰撞检测
下面,一起来看看 QGraphicsScene 对 QGraphicsItem 的管理,主要包括:单击、选择、移动、缩放、删除等。
为了实现以上功能,我们主要实现了 QGraphicsScene 和 QGraphicsItem 对应的事件,通过鼠标和键盘来操作。
操作细节主要包括:
-
选择:点击左键、按 Shift 键可以单选,按下 Ctrl 可进行多选。
-
添加:点击左键
-
删除:点击右键,删除鼠标下的 item;当按下 Ctrl 选择多个 items 时,按下 Backspace 键,将选中的全部删除。
-
移动:点击左键,选择 item,然后移动鼠标;当按下 Ctrl 选择多个 items 时,可以移动选中的 items。
-
缩放:按 Alt 键,然后鼠标拖拽 item 的边界。
在对应操作的事件中,我们输出了一些调试信息,以便跟踪。
custom_item.h:
#ifndef CUSTOM_ITEM_H
#define CUSTOM_ITEM_H
#include <QGraphicsRectItem>
#include <QGraphicsScene>
class CustomItem : public QGraphicsRectItem
public:
explicit CustomItem(QGraphicsItem *parent = 0);
protected:
// Shift+左键:进行选择 Alt:准备缩放
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
int type() const;
private:
QPointF m_centerPointF;
bool m_bResizing;
class CustomScene : public QGraphicsScene
protected:
// 左键:添加item 右键:移除item
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
#endif // CUSTOM_ITEM_H
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
custom_item.cpp:
#include <QKeyEvent>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include "custom_item.h"
CustomItem::CustomItem(QGraphicsItem *parent)
: QGraphicsRectItem(parent)
QPen p = pen();
p.setWidth(2);
p.setColor(QColor(0, 160, 230));
setPen(p);
setBrush(QColor(247, 160, 57));
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
qDebug() << "Custom item left clicked with shift key.";
setSelected(true);
} else if (event->modifiers() == Qt::AltModifier) {
qDebug() << "Custom item left clicked with alt key.";
double radius = boundingRect().width() / 2.0;
QPointF topLeft = boundingRect().topLeft();
m_centerPointF = QPointF(topLeft.x() + pos().x() + radius, topLeft.y() + pos().y() + radius);
QPointF pos = event->scenePos();
qDebug() << boundingRect() << radius << this->pos() << pos << event->pos();
double dist = sqrt(pow(m_centerPointF.x()-pos.x(), 2) + pow(m_centerPointF.y()-pos.y(), 2));
if (dist / radius > 0.8) {
qDebug() << dist << radius << dist / radius;
m_bResizing = true;
} else {
m_bResizing = false;
} else {
qDebug() << "Custom item left clicked.";
QGraphicsItem::mousePressEvent(event);
event->accept();
} else if (event->button() == Qt::RightButton) {
qDebug() << "Custom item right clicked.";
event->ignore();
void CustomItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
if ((event->modifiers() == Qt::AltModifier) && m_bResizing) {
QPointF pos = event->scenePos();
double dist = sqrt(pow(m_centerPointF.x()-pos.x(), 2) + pow(m_centerPointF.y()-pos.y(), 2));
setRect(m_centerPointF.x()-this->pos().x()-dist, m_centerPointF.y()-this->pos().y()-dist, dist*2, dist*2);
} else if(event->modifiers() != Qt::AltModifier) {
qDebug() << "Custom item moved.";
QGraphicsItem::mouseMoveEvent(event);
qDebug() << "moved" << pos();
void CustomItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if ((event->modifiers() == Qt::AltModifier) && m_bResizing) {
m_bResizing = false;
} else {
QGraphicsItem::mouseReleaseEvent(event);
int CustomItem::type() const
return UserType + 1;
void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
qDebug() << "Custom scene clicked.";
QGraphicsScene::mousePressEvent(event);
if (!event->isAccepted()) {
if (event->button() == Qt::LeftButton) {
QPointF point = event->scenePos();
CustomItem *item = new CustomItem();
item->setRect(point.x()-25, point.y()-25, 60, 60);
addItem(item);
} else if (event->button() == Qt::RightButton) {
QGraphicsItem *itemToRemove = NULL;
foreach (QGraphicsItem *item, items(event->scenePos())) {
if (item->type() == QGraphicsItem::UserType+1) {
itemToRemove = item;
break;
if (itemToRemove != NULL)
removeItem(itemToRemove);
void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
qDebug() << "Custom scene moved.";
QGraphicsScene::mouseMoveEvent(event);
void CustomScene::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Backspace) {
qDebug() << "selected items " << selectedItems().size();
while (!selectedItems().isEmpty()) {
removeItem(selectedItems().front());
} else {
QGraphicsScene::keyPressEvent(event);
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
使用很简单,将 item 添加至 scene 中,通过 view 显示即可。
#include <QApplication>
#include <QGraphicsView>
#include "custom_item.h"
int main(int argc, char *argv[])
QApplication a(argc, argv);
CustomItem *pItem = new CustomItem();
pItem->setRect(20, 20, 60, 60);
CustomScene scene;
scene.setSceneRect(0, 0, 400, 300);
scene.addItem(pItem);
QGraphicsView view;
view.setScene(&scene);
view.show();
return a.exec();
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
来源:http://blog.csdn.net/liang19890820/article/details/53504323简述在图形视图框架中,QGraphicsScene 提供一个快速的接口,用于管理大量 item,QGraphicsItem 是场景中 item 的基类。图形视图提供了一些典型形状的标准 item,当然,我们也可以自定义 item。除此之
Qt中提供的Item未必能够满足需要,因此有必要实现自定义的
QGraphicsItem
对象。与QPushButton一样,如果发生鼠标事件,那么为了更换被点击按钮的图像,可以使用paint实现用户自定义
QGraphicsItem
。
2.一个简单的实验
#include
#include "MyItem.h"
#include
#include
#define W
GraphicsView框架结构主要包括三个类:
QGraphicsScene
(场景)、QGraphicsView(视图)、
QGraphicsItem
(图元)。
主要应用方式是:GraphicsView绘图时首先创建一个场景,然后创建图元对象(如一个直线对象、一个多边形对象),再使用场景的add()函数,将图元对象添加到场景中,最后通过视图进行显示,部分代码如下:
Header: #include <
QGraphicsItem
>
qmake: QT += widgets
Inherited By: QAbstractGraphicsShapeItem,
QGraphicsItem
Group, QGraphicsLineItem, QGraphicsObject, and QGraphicsPixmapItem;
//此枚举描述
QGraphicsItem
的缓存模式。缓存通过分配和渲染到屏幕外像素缓冲区来加速渲.
QGraphicsItem
是 Qt 中的一个类,用于在
QGraphicsScene
中展示 2D 图形。如果要实现点击右下角进行拉伸
缩放
,需要重写
QGraphicsItem
的 mousePressEvent、mouseReleaseEvent 和 mouseMoveEvent 三个事件。
在 mousePressEvent 中,需要获取到鼠标点击的位置,判断是否处于右下角的范围内。如果是,则鼠标此时处于拉伸
缩放
状态。在 mouseMoveEvent 中,需要根据鼠标
移动
的距离计算出要拉伸的大小,并对图形进行更新。在 mouseReleaseEvent 中,则表示拉伸
缩放
已经结束。
具体实现可参考以下步骤:
1. 在
QGraphicsItem
中添加变量 m_resizing 和 m_rectSize,用于表示当前是否处于拉伸
缩放
状态和图形的大小。
2. 在 mousePressEvent 中判断是否在右下角的范围内。如果是,则将 m_resizing 设为 true,并记录下当前鼠标位置和图形大小。
3. 在 mouseMoveEvent 中计算出要拉伸的大小,并通过 setRect 函数更新图形的大小。
4. 在 mouseReleaseEvent 中将 m_resizing 设为 false。
代码示例:
class MyItem : public
QGraphicsItem
public:
MyItem()
m_resizing = false;
m_rectSize = QRectF(0, 0, 100, 100);
QRectF boundingRect() const override
return m_rectSize;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override
painter->drawRect(boundingRect());
void mousePressEvent(
QGraphicsScene
MouseEvent *event) override
QPointF pos = event->pos();
QRectF rect = boundingRect();
if (pos.x() >= rect.right() - 10 && pos.y() >= rect.bottom() - 10)
m_resizing = true;
m_resizePos = pos;
m_resizeRect = rect;
void mouseMoveEvent(
QGraphicsScene
MouseEvent *event) override
if (m_resizing)
QPointF delta = event->pos() - m_resizePos;
QRectF newRect = m_resizeRect.adjusted(0, 0, delta.x(), delta.y());
setRect(newRect);
void mouseReleaseEvent(
QGraphicsScene
MouseEvent *event) override
m_resizing = false;
private:
bool m_resizing;
QRectF m_rectSize;
QPointF m_resizePos;
QRectF m_resizeRect;