QGraphicsView笔记

一.加载显示图片

1.1 创建QGraphicsPixmapItem、QGraphicsScene

建议使用new创在堆区,PixmapItem设为成员变量(避免可能的加载失败)。

m_GraphPixItem = new QGraphicsPixmapItem(nullptr);//有几率会崩 oeGraphicsPixmapItem
m_GraphPixItem->setAcceptHoverEvents(true);//鼠标不点击也捕捉鼠标移动事件
m_GraphScene = new QGraphicsScene;
m_GraphScene->addItem(m_GraphPixItem);
ui->graphicsView->setScene(m_GraphScene);

QImage img = cvMat2QImage(mat8);
m_GraphPixItem->setPixmap(QPixmap::fromImage(img));//推荐放最后,避免无图

1.2 设置打开时缩放比例(使图像显示略小于控件)

A.构造函数中(长宽不为设定值,也不建议进行缩放等相关操作,fitInView后坐标不符合预期):

B.界面展开显示后/resizeEvent函数中:
rect() =打开后为控件正常设置宽高(400,560,0,0),不再随缩放改变长宽。
Rectf=(400,560,0,0)或(400,560,-199,-279),

fitInView(sceneRect(), Qt::KeepAspectRatio);//方式一

    QRectF bounds = scene->itemsBoundingRect();//图1000x1400 Rectf=(400,560,-199,-279)
    bounds.setWidth(bounds.width()*1.);         // to tighten-up margins
    bounds.setHeight(bounds.height()*1.);       // same as above
    ui->graphicsView->fitInView(bounds, Qt::KeepAspectRatio);//Rectf=(1015,1421,-5,-7)
    //ui->graphicsView->setSceneRect(bounds);//Rectf=(400,560,0,0)
    //ui->graphicsView->scene()->setSceneRect(bounds);//Rectf=(400,560,0,0)
    ui->graphicsView->centerOn(0, 0);//不影响Rectf
float tm11 = this->transform().m11();//查询放大倍数(方便连续加载,补偿到初始倍数)

1.3 QGraphScene导出为图片

void GraphicsView::ExportSceneSlot(QString sPath)
{
    QImage image(m_GraphScene->width(),m_GraphScene->height(),QImage::Format_ARGB32);//QImage::Format_RGB32
    QPainter painter(&image);
    painter.setRenderHint(QPainter::Antialiasing);
    m_GraphScene->render(&painter);
    QString pngName = sPath+"/Draw.jpg";
    bool saveSuccess = image.save(pngName);
    Q_ASSERT(saveSuccess == true);
}

1.4 属性设置

setViewportUpdateMode(QGraphicsView::FullViewportUpdate);//去掉Item可能存在的拖动重影

支持拖拽(QWidget支持拖拽事件需设置属性和重写函数。)

setAcceptDrops(true);//设置属性
void dragEnterEvent(QDragEnterEvent*event);//拖动进入事件
void dropEvent(QDropEvent*event);

void dragMoveEvent(QDragMoveEvent *event);//连续拖拽

二.常用知识点及功能

2.1 鼠标事件的传导顺序:【view】->【scene分类】->【item】。

A.View和Scene同时重写mousePressEvent,仅View响应。
解决方式:在mousePressEvent下调用基类同名函数。

void MyGraphicsView::mousePressEvent(QMouseEvent * e)
{   
    QGraphicsView::mousePressEvent(e) ;// forward to scene (via default view behaviour)
    // ...
}

B.View重写mousePressEvent,item的mousePressEvent响应情况。
View加mousePressEvent,item的mousePressEvent会响应,不加则不会响应。
C.mouseMoveEvent函数中提前return,导致不按鼠标中心点缩放
猜测未将坐标传至scene,return前加mouseMoveEvent。
D.继承QAbstractGraphicsShapeItem时,重写虚函数为mouseMoveEvent(QGraphicsmouseMoveEvent )。
测面验证【scene分类】->【item】

2.2 QGraphicsItem随鼠标拖动

QGraphicsItem鼠标拖动(设置属性或重写事件)

2.3 坐标(场景Scene坐标,视图View坐标)

A.视图坐标(event坐标、控件等)

contentsRect();//较rect()两边各减1。
viewport();//为控件像素宽width()高height()各-1

B.视图坐标转场景坐标

event->scenePos();
mapToScene(event->pos());
//求场景高度
//方式一 contentsRect()转Scene再取boundingRect() 
mapToScene(contentsRect()).boundingRect().height();//
sceneRect();//等于图大小

B.视图坐标转场景坐标

event->scenePos();
mapToScene(event->pos());
//求场景高度
//方式一 contentsRect()转Scene再取boundingRect() 
mapToScene(contentsRect()).boundingRect().height();//
sceneRect();//等于图大小

C.场景坐标转视图坐标

QPointF viewPoint = this->matrix().map(m_lastPoint);//Qt5
QPoint mapFromScene(const QPointF &point) const;//Qt6

QGraphicsView图形视图框架使用(一)坐标变换

2.4 鼠标缩放(以鼠标点为中心)

//QWheelEvent(angleDelta)。QGraphicsSceneWheelEvent(delta)

event->angleDelta;//(0.-120)其y()正(放大)负值可作为判断是否缩放
event->delta;//=event->angleDelta.y() Asap用法 

以鼠标点为中心:
A.参考QGraphicsView::centerOn
QGraphicsView 如何实现百度地图按照鼠标点进行放大缩小效果(滑动条补偿)
B.参考Asap,两次centerOn
C.设置属性(推荐)

setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
setResizeAnchor(QGraphicsView::AnchorUnderMouse);

QT QGraphicsView 在鼠标点击处进行放大缩小

三.进阶

3.1 QGraphicsView缓存刷新(QGraphicsItem::CacheMode,QPixmapCache)。

Qt图形视图框架:QGraphicsView

QGraphicsItem::setZValue

setZvalue()来设置一个item的Z值。默认的Z值是0,具有同样的Z值的item会按照插入的顺序来入栈(stack order)。也就是说,GraphicsView会优先根据item的Z值决定item的层次,只有当Z值相同的情况下才会去理会stack order;
Qt QGraphicsItem的z值怎么用,如何确定上下层关系
Qt—双缓冲绘图

四.异常问题记录

4.1 QImage的load加载invalid。

解决方法:缺少dll库,debug下添加imageformats文件夹(本人用的windeployqt生成)。

4.2 部分情况加载失败,-nan 。

1.场景改为成员变量+new分配内存,猜测该种方式内存分配大、权限高,可支持灵活加载大图。
2.类似除0这种数字越界。

4.3 重写QGraphicsItem。

1.需重写纯虚函数boundingRect。
2.继承增加QObject和增加Q_OBJECT宏。

class UICanvasItemBase : public QObject, public QGraphicsItem
{
    Q_OBJECT
protected:
    QRectF boundingRect() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) final;
}

4.4 重写QGraphicsScene的paintEvent(QPaintEvent* event)。

1.因父类无paintEvent导致无this指针。

4.5 高分辨率屏兼容(contentsRect高度会改变)。

放小会调小。
屏幕分辨率3840x2160(contentsRect高度1807)。
屏幕分辨率1920x1080(contentsRect高度777)。

4.6 QDialog中QGraphicsView的move事件不响应。

设置二属性

ui->graphicsView->setMouseTracking(true);
ui->graphicsView->viewport()->installEventFilter(this);

4.7 多线程中创建Scene、Item,setPixmap,会运行中断报错:

(“bsptreeindexcpp,line348”,“unindexedltems.isEmptyO”)。
理解:QT非gui线程不操作控件相关。

4.8 QPixmap先为空,加载时setPixmap,会以原点镜像翻转

五.开源示例

Draw_Figure(图元绘制及交互)
笔记:
1.重写QAbstractGraphicsShapeItem(继承QGraphicsItem)。
2.重写函数(paint,boundingRect,ContextMenu)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值