一、简介

图形视图框架中的事件都是首先由视图进行接收,然后传递给场景,再由场景传递给相应的图形项。而对于键盘事件,它会传递给获得焦点的图形项,可以使用QGraphicsScene类的setFocusItem()函数或者图形项自身调用setFocus()函数来设置焦点图形项。默认的,如果场景没有获得焦点,那么所有的键盘事件都会被丢弃。场景中的图形项获得了焦点,场景也会自动获得焦点。

对于鼠标悬停效果,QGraphicsScene会调度悬停事件。如果一个图形项可以接收悬停事件,那么当鼠标进入它的区域之中时,它就会收到一个GraphicsSceneHoverEnter事件。如果鼠标继续在图形项的区域之中进行移动,那么QGraphicsScene就会向该图形项发送GraphicsSceneHoverMove事件。当鼠标离开图形项的区域时,它将会收到一个GraphicsSceneHoverLeave事件。图形项默认是无法接收悬停事件的,可 以使用QGraphicsItem类的setAcceptHoverEvents()函数使图形项可以接收悬停事件。

所有的鼠标事件都会传递到当前鼠标抓取的图形项,一个图形项如果可以接收鼠标事件(默认可以)而且鼠标在它的上面被按下,那么它就会成为场景的鼠标抓取的图形项。

二、实例

下面来看一个例子。新建空的Qt项目,名称为myView。完成后先向本项目中添加一个Myltem自定 义图形项,然后在myitem.h文件中声明boundingRect()和paint()两个纯虚函数,再声明并定义一个公共的用于设置图形项填充色的函数和变量,最后添加一些事件处理函数的声明,完成后myitem.h文件内容如下:

#ifndef MYITEM_H
#define MYITEM_H #include <QGraphicsItem> class MyItem : public QGraphicsItem
{
public:
MyItem(); //返回要绘制图形项的矩形区域
QRectF boundingRect() const; //用来执行实际的绘图操作
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget); //用来设置图形项填充色
void setColor(const QColor &color) { brushColor = color; } protected:
//鼠标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观
void mousePressEvent(QGraphicsSceneMouseEvent *event); //键盘按下事件处理函数,判断是否是向下方向键,如果是,则向下移动图形项
void keyPressEvent(QKeyEvent *event); //悬停事件处理函数,设置光标外观和提示
void hoverEnterEvent(QGraphicsSceneHoverEvent *event); //右键菜单事件处理函数,为图形项添加一个右键菜单
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); private:
QColor brushColor; //画刷颜色 }; #endif // MYITEM_H

使用了变量作为画刷的颜色,就可以动态指定图形项的填充色了,默认情况下图形项的填充色设置为红色。

然后myitem.cpp文件修改如下:

#include "myitem.h"
#include <QPainter>
#include <QCursor>
#include <QKeyEvent>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <QMenu> MyItem::MyItem()
{
brushColor = Qt::red; setFlag(QGraphicsItem::ItemIsFocusable);
setFlag(QGraphicsItem::ItemIsMovable);
setAcceptHoverEvents(true);
} //返回要绘制图形项的矩形区域
QRectF MyItem::boundingRect() const
{
qreal adjust = 0.5;
return QRectF(-10 - adjust, -10 - adjust,
20 + adjust, 20 + adjust);
} //用来执行实际的绘图操作
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option); //标明该参数没有使用
Q_UNUSED(widget); //根据图形项是否获得焦点来使用不同颜色绘制图形项的轮廓
if(hasFocus())
{
painter->setPen(QPen(QColor(255,255,255,200)));
}
else
{
painter->setPen(QPen(QColor(100,100,100,100)));
} //动态指定图形项的填充色
painter->setBrush(brushColor);
painter->drawRect(-10, -10, 20, 20);
} //鼠标按下事件处理函数,设置被点击的图形项获得焦点,并改变光标外观
void MyItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event); setFocus();
setCursor(Qt::ClosedHandCursor);
} //键盘按下事件处理函数,判断是否是向下方向键,如果是,则向下移动图形项
void MyItem::keyPressEvent(QKeyEvent *event)
{
//实现视图的下移
if(event->key() == Qt::Key_Down)
moveBy(0, 10);
} //悬停事件处理函数,设置光标外观和提示
void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event); setCursor(Qt::OpenHandCursor);
setToolTip("I am item");
} //右键菜单事件处理函数,为图形项添加一个右键菜单
void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QMenu menu;
QAction *moveAction = menu.addAction("move back");
QAction *selectedAction = menu.exec(event->screenPos()); if(selectedAction == moveAction)
{
setPos(0, 0);
}
}
  • 在鼠标按下事件处理函数中,为鼠标单击的图形项设置了焦点,这样当按下键盘时该图形项就会接收到按键事件。
  • 然后是键盘按下事件处理函数,如果按下了键盘的向下方向键,那么获得焦点的图形项就会向下移动,这里使用了 moVeBy(qreal dx, qreal dy)函数,它用来进行相对移动,就是相对于当前位置在水平方向移动dx,在垂直方向移动dy。在进行项目移动时,经常使用到该函数。
  • 然后是悬停事件处理函数,如果将鼠标光标移动到一个图形项上,可以看到光标外观改变了,而且出现了工具提示。
  • 然后是右键菜单事件,在一个图形项上右击,就会弹出一个菜单,如果选中该菜单,那么图形项会移动到场景原点。

然后myview.h文件修改如下:

#ifndef MYVIEW_H
#define MYVIEW_H #include <QGraphicsView> class MyView : public QGraphicsView
{
Q_OBJECT
public:
explicit MyView(QWidget *parent = 0); protected:
//键盘按下事件处理函数
void keyPressEvent(QKeyEvent *event); signals: public slots: }; #endif // MYVIEW_H

然后myview.cpp文件修改如下:

#include "myview.h"
#include <QKeyEvent> MyView::MyView(QWidget *parent) :
QGraphicsView(parent)
{
} //键盘按下事件处理函数
void MyView::keyPressEvent(QKeyEvent *event)
{
switch (event->key())
{
//数字“-”键
case Qt::Key_Plus :
scale(1.2, 1.2);
break; //数字“+”键
case Qt::Key_Minus :
scale(1 / 1.2, 1 / 1.2);
break; //右方向键
case Qt::Key_Right :
rotate(30);
break;
} QGraphicsView::keyPressEvent(event);
}

这里使用不同的按键来实现视图的缩放和旋转等操作。一定要注意,在视图的事件处理函数的最后一定要调用QGraphicsView类的keyPressEvent()函数,不然在场景或者图形项中就无法再接收到该事件了。

最后修改main.cpp文件,并且将其内容更改如下:

#include <QApplication>
#include "myitem.h"
#include "myview.h"
#include <QTime> int main(int argc,char* argv[ ])
{
QApplication app(argc,argv); qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); QGraphicsScene scene;
scene.setSceneRect(-200, -150, 400, 300); for(int i = 0; i < 5; ++i)
{
MyItem *item = new MyItem;
item->setColor(QColor(qrand() % 256, qrand() % 256, qrand() % 256));
item->setPos(i * 50 - 90, -50);
scene.addItem(item);
} MyView view;
view.setScene(&scene);
view.setBackgroundBrush(QPixmap("../myView/background.png"));
view.show(); return app.exec();
}

这里在场景中添加了 5个图形项,分别为它们设置了随机颜色,然后将它们排成一行。可以使用键盘上的“ + ”和“-”键来放大和缩小视图,也可以使用向右方向键来旋转视图。

三、效果

执行程序,最初的效果如下:

按右方向键后,旋转视图后:

鼠标拖动图形项后:

Qt 2D绘图之六:图形视图框架的事件处理与传播的更多相关文章

  1. Qt开发技术:图形视图框架(二)场景QGraphicsScene、QGraphicsItem与QGraphicsView详解

    前话   Qt的图形视图框架,最核心的三个类为:QGraphicsScene.QGraphicsItem与QGraphicsView.   基于图形框架的高级白板软件Demo QGraphicsSce ...

  2. Qt开发技术:图形视图框架(一)基本介绍

    前话   使用到Qt的视图框架.   Qt视图框架介绍 简介   图形视图框架(The Graphic View Framework)用于管理和与大量定制的二维图形项目交互,以及用于可视化项目的视图小 ...

  3. Qt 2D绘图之五:图形视图框架的结构和坐标系统

    一.图形视图框架的结构 在前面讲的基本绘图中,我们可以自己绘制各种图形,并且控制它们.但是,如果需要同时绘制很多个相同或不同的图形,并且要控制它们的移动.检测它们的碰撞和叠加:或者我们想让自己绘制的图 ...

  4. Qt之图形视图框架

    简述 图形视图(Graphics View)提供了一个平台,用于大量自定义2D图元的管理与交互,并提供了一个视图部件(view widget)来显示可以缩放和旋转的图元. 框架包括一个事件传播架构,支 ...

  5. QT 图形视图框架

    https://blog.csdn.net/qq769651718/article/details/79357936 使用QPushButton.QLabel.QCheckBox等构成GUI的控件或自 ...

  6. Qt图形视图框架公开课资料

    接受CSDN学院的邀请,讲一次公开课,主题是Qt图形视图框架,报名链接在这里:http://edu.csdn.net/huiyiCourse/detail/228. 内容有两部分:自定义Item和拖放 ...

  7. 用Qt图形视图框架开发拼图游戏

    用Qt的图形视图框架(Graphics View Framework)做了一个拼图游戏DEMO,演示了: QGraphicsView.QGraphicsScene.QGraphicsItem的基本用法 ...

  8. Qt-MVC图形视图框架初识

    使用QPushButton.QLabel.QCheckBox等构成GUI的控件或自定义图形时,开发应用程序会变得很简单.但是如果想在GUI中使用数十个或者数百个图形对象,向用户完美展示控制场景,则会受 ...

  9. Qt-MVC图形视图框架分解

    前面在<Qt-MVC图形视图框架出识>中我们了解了Qt图形视图框架中三个最基本的类,弄清他们的关系,本片小文,我们将对QGraphicsView,QGraphiceScene,QGraph ...

随机推荐

  1. LVS集群的负载调度

    LVS集群的负载调度 章文嵩 (wensong@linux-vs.org) 转自LVS官方资料 2002 年 5 月 本文主要讲述了LVS集群的IP负载均衡软件IPVS在内核中实现的各种连接调度算法. ...

  2. malloc、calloc、realloc和alloca各种的区别

    需要先包含头文件 #include"malloc.h" malloc是标准的在堆中开辟新的空间 比如 char *pt=(char *)malloc(10*sizeof(char) ...

  3. Java JSON数据创建和读取

    Java  json数据创建 package com.JavaTest; import com.google.gson.JsonArray; import com.google.gson.JsonOb ...

  4. 关于Linux启动文件rc.local的解惑

    背景 首先,rc.local是Linux启动程序在login程序前执行的最后一个脚本,有的服务器中在rc.local中可能会有一句touch /var/lock/subsys/local,这是干什么的 ...

  5. httpd 隐藏文件

    问题情况, 因磁盘空间问题,使用rsync将 php工作目录下文件copy到新盘中后,出现 php服务很多目录访问返回 404,路径找不到,其实文件都存在,而且路径都是对的 解决思路. 根目录下 有个 ...

  6. android实现文字渐变效果和歌词进度的效果

    要用TextView使用渐变色,那我们就必须要了解LinearGradient(线性渐变)的用法. LinearGradient的参数解释 LinearGradient也称作线性渲染,LinearGr ...

  7. C语言中的字符数组和字符串

    在C语言中,没有字符串类型,但是可以通过字符数组来模拟字符串. 字符串可以在栈上,堆上,静态区和常量区进行分配. char buf[50]  = "abc"; char buf[] ...

  8. No result defined for action cn.crm.action.LinkManAction and result input

    这是struts2的一个拦截器报的错误,当你的form中的数据有问题,比如说<input type="text" name="receiverLoginID&quo ...

  9. bzoj1195

    AC自动机+状压dp 多串匹配要想ac自动机 dp[i][S]表示在i状态选中S 转移就用bfs,每个点通过fail收集信息,不要忘记通过fail传递 昨天搞不明白为什么自动机每次只可以转移儿子,不可 ...

  10. <正则吃饺子> :关于Guava中 Joiner 和 Splitter 的简单使用

    在现在项目中经常看到 这两个类的使用,开始时候不明白具体是做的什么事情,就单独拿出来学习下了,参照了网上的博文,这里主要是简单的讲讲用法. 具体对这两个类,不做过多介绍,有个在线文档,需要的可以自己去 ...