Qt学习笔记3

本文详细介绍了Qt框架中的QGraphicsView、QGraphicsScene和QGraphicsItem在2D图形场景中的应用,包括它们的用途、事件处理、交互操作、视觉效果、自定义绘图以及事件传递机制。同时探讨了如何处理窗口间事件传递和优化图形视图性能。
摘要由CSDN通过智能技术生成

1.QGraphicsView

QGraphicsView是Qt框架提供的一个用于显示和编辑2D图形场景的部件。它是基于MVC(模型-视图-控制器)设计模式的视图组件,用于在GUI应用程序中展示图形元素、图形场景或者自定义绘图操作。

QGraphicsView的主要用途包括:

显示图形场景:QGraphicsView提供了一个视图窗口,可以在其中展示QGraphicsScene中的图形元素。它可以显示和滚动包含大量图形元素的场景,并且支持缩放和平移操作。

交互操作:QGraphicsView允许用户与图形元素进行交互操作,例如选择、移动、缩放、旋转等。它提供了一些默认的交互功能,如鼠标选择、拖拽、滚轮缩放等,同时也可以通过派生和重写相关事件来实现自定义的交互行为。

视觉效果:QGraphicsView支持在图形场景中应用一些视觉效果,如渐变、透明度、阴影等。这些效果可以通过设置QGraphicsItem的属性或者自定义绘制来实现。

自定义绘图操作:QGraphicsView可以作为一个画布,允许开发者进行自定义绘图操作。可以通过派生QGraphicsView并重写相关方法来实现自定义的绘图逻辑,例如绘制几何图形、图表、图标等。
一般让图片适应窗口,可以这样做
```

qreal width_scale = this->width() / image.width();
qreal height_scale = this->height() / image.height()
qreal image_scale = image.width() / image.height();
//寻找哪个变化最小变化哪个
if(width_scale > height_scale)
{
	width = this->height * image_scale;
} else
{
	height = this->width / image_scale;
}
```

事件传递
涉及到深层次窗口结构或者窗口封装时,经常会遇到上层窗口接收不到事件的问题。排除这类问题需要了解窗口间的事件传递过程。

应用程序产生事件时,事件会先派发给父窗口,由父窗口在内部派发给子窗口,子窗口会进一步传递给子窗口的子窗口,直到遍历到最后没有子窗口的窗口对象,进入子窗口的用户事件处理函数。从子窗口开始,事件会依次进入到父窗口的事件处理函数中,子窗口可以调用event->accept()来中断事件的向上传递。总结来说是先下沉再上浮。

当发现父窗口没有对应的事件触发用户函数时,首先要确认相关功能是否启用,比如鼠标悬停和拖拽功能。其次需要在子窗口的事件处理函数中,显式调用event->ignore()来使事件继续向上传递。

关于鼠标悬停移动和拖拽事件
具有父子关系的窗口,如果想父窗口接收到上述事件,必须将父窗口和所有的子窗口的相关功能全部启用,否则事件会在中间某个窗口中断传递。

QGraphicsView中的事件
默认view不会将鼠标移动事件传递出来,所以需要显式的在view中重载mouseEvent(),并将事件ignore(),将其传递出来,这样做是为了将事件全部通知所有父子窗口。

QGraphicsScene中的事件
悬停事件在图元重叠时,事件会被上层图元(无父子关系)拦截,但是一般地图应用需求可能需要通知所有下层图元。此问题的解决办法见另一篇文章:解决Qt graphis-view框架中,上层图元接收hover事件导致底层图元接收不到的问题

draw 按我的理解在QGraphicsScene 中它是QGraphicsItem 和QGraphicsObject 承载的主体, 可以用来修饰他们两个,而QGraphicsItem 和QGraphicsObject是主要想展示的东西,你可以完善这个细节,view的话主要是展示这个scene的,想展示那一块就去设置。

  1. 图形项的坐标系:在 QGraphicsScene 中,图形项的坐标系是相对于场景而言的。这意味着图形项的坐标是相对于场景左上角的坐标,而不是相对于视图或窗口的坐标。因此,如果你在 boundingRect() 函数中返回的矩形的左上角坐标是 (0, 0),宽度和高度为 70,那么这个矩形在场景中的位置就是 (0, 0, 70, 70)。
  2. 视图的变换:视图(例如 QGraphicsView)可以进行缩放、平移和旋转等变换操作。这些变换将影响视图中的图形项的显示位置。因此,你看到的视图中的图形项位置可能与它们在场景中的位置不完全一致。鼠标事件坐标是相对于视图的,所以在视图进行了变换后,鼠标事件的坐标与图形项在场景中的位置可能不完全匹配。
  3. 鼠标事件的坐标系:鼠标事件的坐标是相对于接收事件的窗口或视图的坐标系的。如果视图或窗口有边框、标题栏或其他装饰,这些装饰也会影响鼠标事件的坐标。因此,鼠标事件的坐标可能与你在视图中看到的图形项位置不完全一致。

2.QGraphicsScene

QGraphicsScene 是 Qt 框架中的一个类,它提供了一种灵活的方式来管理图形项(QGraphicsItem)的集合。QGraphicsScene 作为一个二维场景,可以用来组织和渲染图形项,处理事件,以及执行其他与场景相关的操作。它是 QGraphicsView 显示内容的后端,负责管理所有的项和布局,而 QGraphicsView 则负责显示这些内容。

以下是 QGraphicsScene 的一些关键特性和用法:

  1. 图形项管理

添加和删除项:你可以通过 addItem() 方法向场景中添加 QGraphicsItem,也可以通过 removeItem() 方法从场景中删除项。
项的查询:QGraphicsScene 提供了多种方法来查询场景中的项,例如 items(), itemAt(), 和 collidingItems()。
2. 事件处理

事件过滤:QGraphicsScene 可以安装事件过滤器来预处理或拦截事件,这对于自定义项的行为非常有用。
鼠标事件:场景可以处理鼠标事件(如 mousePressEvent, mouseMoveEvent, mouseReleaseEvent),这些事件可以传递给场景中的项。
拖拽和悬停事件:场景可以处理拖拽事件(如 dragEnterEvent, dragMoveEvent, dragLeaveEvent)和悬停事件(如 hoverEnterEvent, hoverMoveEvent, hoverLeaveEvent)。
3. 渲染和绘图

视图更新:场景中的项可以通过调用 update() 方法来标记为需要更新。当场景需要重绘时,QGraphicsScene 会负责渲染所有的项。
渲染策略:QGraphicsScene 支持多种渲染策略,包括立即渲染和按需渲染。
4. 场景坐标系

坐标转换:QGraphicsScene 提供了坐标转换功能,可以在场景坐标、视图坐标和设备坐标之间转换。
变换:项可以通过 setTransform() 方法应用变换,如平移、旋转和缩放。
5. 选择和焦点

选择管理:QGraphicsScene 提供了选择管理功能,可以设置和查询场景中的选中项。
焦点项:场景可以有焦点项,类似于 GUI 应用程序中的控件焦点。
6. 性能优化

批处理:QGraphicsScene 支持批处理操作,可以通过调用 beginBatch() 和 endBatch() 来减少重绘次数,提高性能。
渲染优化:场景可以启用或禁用项的反锯齿和边缘抗锯齿,以优化渲染性能。

如果scene未设置size时,scene的size就跟里面的item有关,view的话默认显示为这些item的重心,设置的话默认显示scene的中心。
视图view坐标:

QPoint nViewPoint = event->pos();

通过视图坐标转场景scene坐标:

QPointF fScenePoint = this->mapToScene(nViewPoint);

通过场景坐标转图形项item坐标:

QGraphicsItem* pItem = this->scene()->itemAt(fScenePoint, QTransform()); //图形项指针
if (NULL != pItem)
{
 QPointF fItemPoint = pItem->mapFromScene(fScenePoint);   //获取图形项坐标
}

view的话就相当于直播的摄像头,可以改变大小,显示的位置,展示的item,而scene的话就是那个舞台是固定的,item则是上面表演的演员。

GraphicsView作为一个滚动区域(Scroll Area),为大场景提供了滚动条支持。当场景内容超出视图范围时,滚动条会自动出现,使用户能够轻松浏览场景内容。

滚动条有时候会影响视图的显示,在必要时要关闭

  view
  // 关闭水平滚动条
  this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  // 关闭垂直滚动条
  this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

如果场景的原点 (0, 0) 在视图的中心位置显示时出现了偏移,可能有以下几种情况:

  1. 场景矩形范围的偏移:你可能手动设置了场景的矩形范围,导致场景的原点 (0, 0) 不在视图的中心位置。通过调整场景的矩形范围,你可以将原点放置在视图的中心位置。

  2. 视图的滚动偏移:视图可能进行了滚动操作,导致场景的原点 (0, 0) 在视图中发生了偏移。这可以通过调用 QGraphicsViewcenterOn() 函数将场景的特定点(例如 (0, 0))重新定位到视图的中心位置。

  3. 视图的变换偏移:视图可以应用了平移、缩放、旋转等变换操作,导致场景的原点 (0, 0) 在视图中发生了偏移。你可以通过调整视图的变换矩阵或使用相应的函数(例如 translate()scale()rotate())来恢复场景的原点在视图中心的位置。

    view 一定保持 scene 在视图中间
    setFixedSize() 方法允许你指定窗口部件的固定宽度和高度,使其无法通过鼠标拖动来改变大小。窗口部件将保持指定的大小,无论用户如何尝试拖动或调整窗口。

3.QGraphicsItem

QGraphicsItem 是 Qt 框架中的一个基础类,用于在 QGraphicsScene 场景中表示可渲染的对象。它提供了一套丰富的接口,允许开发者创建各种自定义的图形项,包括形状、文本、图像等。QGraphicsItem 类本身不提供绘制功能,而是通过继承和实现 paint() 函数来自定义绘制行为。

以下是 QGraphicsItem 的一些关键特性和常用方法:

  1. 基本属性和方法

位置和变换:setPos(), pos(), setRotation(), rotation(), setScale(), setTransform() 等方法用于控制项的位置、旋转和缩放。
尺寸:setRect(), boundingRect() 等方法用于设置和获取项的矩形边界框。
可见性:setVisible() 方法用于控制项的可见性。
父项和子项:setParentItem() 方法用于设置项的父项,childItems() 方法用于获取子项列表。
2. 事件处理

鼠标事件:mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent() 等方法用于处理鼠标事件。
悬停事件:hoverEnterEvent(), hoverMoveEvent(), hoverLeaveEvent() 等方法用于处理鼠标悬停事件。
键盘事件:keyPressEvent(), keyReleaseEvent() 等方法用于处理键盘事件。
拖拽事件:dragEnterEvent(), dragMoveEvent(), dragLeaveEvent() 等方法用于处理拖拽事件。
3. 绘制和更新

自定义绘制:通过重写 paint() 函数来实现项的自定义绘制。
更新和重绘:update() 方法用于请求项的重绘,scene() 方法用于获取项所属的场景。
4. 选择和焦点

选择:setSelected() 方法用于设置项的选中状态,isSelected() 方法用于检查项是否被选中。
焦点:setFocus() 方法用于设置项的焦点状态,hasFocus() 方法用于检查项是否有焦点。
5. 碰撞检测

碰撞检测:collidesWithItem(), collidingItems() 等方法用于检测项之间的碰撞。
6. 优化和性能

优化渲染:isObscured() 方法用于检查项是否被其他项遮挡,以优化渲染性能。
批处理更新:advance() 方法用于处理项的更新请求。

想要自定义拖拽操作可以参考下面然后再重写dragEnterEvent, dragMoveEvent,和dropEvent ,设置拖拽状态为true

 //创建拖动操作
        QMimeData* mimeData = new QMimeData;
        mimeData->setText(QString("%1").arg(m_curIndex));
        QDrag* drag = new QDrag(this);
        drag->setMimeData(mimeData);

        //创建一个临时跟随的小图片
        QPixmap pixmap = QPixmap(m_imageNameList[m_curIndex]);
        QSize size(70, 70);
        pixmap = pixmap.scaled(size, Qt::KeepAspectRatio);
//     pixmap.scaled(pixmap.size() * 0.5
        drag->setPixmap(pixmap);

        //设置热点为小图片的中心位置
        drag->setHotSpot(QPoint(pixmap.width() * 0.5, pixmap.height() * 0.5));
        drag->exec();
  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值