在自定义 QGraphicsView 中移动 QGraphicsItem 问题
Posted
技术标签:
【中文标题】在自定义 QGraphicsView 中移动 QGraphicsItem 问题【英文标题】:Issue moving an QGraphicsItem in a custom QGraphicsView 【发布时间】:2020-04-16 23:25:47 【问题描述】:我在自定义 QGraphicView 类中移动 QGraphicItem 时遇到问题。我希望能够做的是通过单击鼠标左键选择该项目,然后将其移动到我单击鼠标右键的位置。
我强烈怀疑我的问题是 QGraphicsItem::setPos() 要求坐标位于父坐标中,我不确定要使用哪个 for of QMouseEvent::*Pos() 以及如何将其转换为父坐标。
屏幕截图显示正在发生的事情,而不是我遵循代码的内容。
main.cpp:(这里是简单的 main,标准测试工具)
#include "QtTest.h"
#include <QApplication>
int main(int argc, char *argv[])
QApplication a(argc, argv);
QtTest w;
w.show();
return a.exec();
QtTest.h:(这定义了主应用程序窗口)
#pragma once
#include <QtWidgets/QMainWindow>
class QGraphicsView;
class QGraphicsScene;
class QGraphicsItem;
class QMouseEvent;
class QtTest : public QMainWindow
Q_OBJECT
public:
QtTest(QWidget *parent = Q_NULLPTR);
private:
QGraphicsView* m_gv;
QGraphicsScene* m_pScene;
void setupUI();
;
QtTest.cpp:(应用程序主窗口的实现)
#include "QtTest.h"
#include "testGV.h"
#include <QVariant>
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QMainWindow>
#include <QMouseEvent>
#include <QWidget>
QtTest::QtTest(QWidget *parent): QMainWindow(parent)
setupUI();
void QtTest::setupUI()
QWidget *centralWidget;
if (objectName().isEmpty())
setObjectName("QtTestClass");
resize(600, 400);
centralWidget = new QWidget(this);
centralWidget->setObjectName("centralWidget");
m_gv = new testGV(centralWidget);
m_gv->setObjectName("graphicsView");
m_gv->setGeometry(QRect(100, 10, 441, 331));
setCentralWidget(centralWidget);
testGV.h:(自定义小部件的定义)
#pragma once
#include <QGraphicsView>
#include <QGraphicsItem>
class testGV : public QGraphicsView
Q_OBJECT
public:
testGV(QWidget* parent);
protected:
void mousePressEvent(QMouseEvent*);
private:
QGraphicsScene* m_pScene;
QGraphicsItem* m_pItem;
void createScene();
;
testGV.cpp:(自定义小部件的实现)
#include "testGV.h"
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QMouseEvent>
testGV::testGV(QWidget* parent) : QGraphicsView(parent)
createScene();
void testGV::createScene()
m_pScene = new QGraphicsScene();
m_pScene->addRect(QRect(30, 30, 150, 150), QPen(Qt::black), QBrush(Qt::black, Qt::NoBrush));
QGraphicsEllipseItem* pTemp = m_pScene->addEllipse(QRect(0, 0, 15, 15), QPen(Qt::black), QBrush(Qt::red, Qt::SolidPattern));
pTemp->setFlag(QGraphicsItem::ItemIsMovable);
pTemp->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
setScene(m_pScene);
void testGV::mousePressEvent(QMouseEvent* pEvent)
if (pEvent->button() == 1) // left button click
m_pItem = itemAt(pEvent->pos());
else if (pEvent->button() == 2) // right button click
m_pItem->setPos(pEvent->pos());
m_pScene->update();
左边的图像是初始显示,当我右键单击红点,然后单击大约黑点所在的正方形时,我得到了右边的图像。我要的是红点移动到我点击的地方。
【问题讨论】:
【参考方案1】:问题的原因是QMouseEvent在view的坐标中有位置信息,但是item使用的是场景的坐标。这种情况下的解决方案是将视图的坐标映射到场景的坐标:
void testGV::mousePressEvent(QMouseEvent* pEvent)
if (pEvent->button() == Qt::LeftButton)
m_pItem = itemAt(pEvent->pos());
else if (pEvent->button() == Qt::RightButton)
if(m_pItem)
m_pItem->setPos(mapToScene(pEvent->pos()));
但即使这样也有问题,你的物品的位置是相对于左上角的,所以位移会有误差,如果你想避免这种偏差,那么你必须考虑左键的位置:
void testGV::mousePressEvent(QMouseEvent* pEvent)
if (pEvent->button() == Qt::LeftButton)
m_pItem = itemAt(pEvent->pos());
m_pItem->setData(0, mapToScene(pEvent->pos()));
else if (pEvent->button() == Qt::RightButton)
if(m_pItem)
QPointF p = m_pItem->data(0).toPointF();
QPointF sp = mapToScene(pEvent->pos());
m_pItem->setPos(m_pItem->pos() + sp - p);
m_pItem->setData(0, sp);
注意:创建指针时,它指向任何内存位置,因此可能会导致问题,因此我建议将其初始化为 nullptr 并检查指针是否有效:
testGV::testGV(QWidget* parent) : QGraphicsView(parent), m_pItem(nullptr)
createScene();
【讨论】:
以上是关于在自定义 QGraphicsView 中移动 QGraphicsItem 问题的主要内容,如果未能解决你的问题,请参考以下文章
在 QGraphicsView/QGraphicsScene 中移动 QGraphicsProxyWidget 中的嵌入式小部件