c++ - QT - 无法使用 mouseMove 移动场景
问题描述
我有简单的 cpp 代码。我想用鼠标移动 QGraphicsScene:
// MainWindow.cpp code ------------------------------
void MainWindow::initializeMainViewWidget() {
/* some code */
itemsFrame->setLayout(layout);
mView = std::make_unique<ui::MainView>();
layout->addWidget(mView.get());
mScene = std::make_unique<ui::MainScene>();
mView->setScene(mScene.get());
QObject::connect(mScene.get(), &ui::MainScene::openItem, this, &MainWindow::openUpdateItemDialog);
mView->show();
}
// MainView.cpp code -------------------------------
void MainView::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::RightButton) {
// Store original position.
mPos0 = event->position(); //mPos0 is QPointF
event->accept();
setCursor(Qt::ClosedHandCursor);
return;
} else if (event->button() == Qt::LeftButton) {
event->ignore();
}
QGraphicsView::mousePressEvent(event);
}
void MainView::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
event->ignore();
} else if (event->buttons() & Qt::RightButton) {
QPointF trans = event->position() - mPos0;
mPos0 = event->position();
event->accept();
translate(trans.x(), trans.y());
return;
}
QGraphicsView::mouseMoveEvent(event);
}
但是当我通过添加项目时: addItem(someQGraphicsItem);
显示项目。我可以拖动它……但不能用 RMB 和 mouseMove 移动场景。
解决方案
我从SO: Zoom features using Qt中获取了我的旧示例,并添加了代码以通过鼠标拖动来平移内容:
#include <QtWidgets>
// class for widget to demonstrate zooming
class Canvas: public QGraphicsView {
// variables:
private:
// start position for pan
QPoint _posRMB;
// methods:
public:
// constructor.
Canvas() = default;
// destructor.
virtual ~Canvas() = default;
// disabled:
Canvas(const Canvas&) = delete;
Canvas& operator=(const Canvas&) = delete;
protected:
virtual void mousePressEvent(QMouseEvent *pQEvent) override
{
if (pQEvent->button() == Qt::RightButton) {
_posRMB = pQEvent->pos();
pQEvent->accept();
setCursor(Qt::ClosedHandCursor);
}
}
virtual void mouseMoveEvent(QMouseEvent *pQEvent) override
{
if (pQEvent->buttons() & Qt::RightButton) {
// pos() -> virtual canvas, _posRMB -> virtual canvas
QPointF delta = mapToScene(pQEvent->pos()) - mapToScene(_posRMB);
// modify transform matrix
translate(delta.x(), delta.y());
_posRMB = pQEvent->pos();
// force update
update();
pQEvent->accept();
}
}
virtual void mouseReleaseEvent(QMouseEvent *pQEvent)
{
if (pQEvent->button() == Qt::RightButton) {
unsetCursor();
}
}
virtual void wheelEvent(QWheelEvent *pQEvent) override
{
//qDebug() << "Wheel Event:";
// pos() -> virtual canvas
QPointF pos = mapToScene(pQEvent->pos());
// scale from wheel angle
float delta = 1.0f + pQEvent->angleDelta().y() / 1200.0f;
// modify transform matrix
QTransform xform = transform();
xform.translate(pos.x(), pos.y()); // origin to spot
xform.scale(delta, delta); // scale
xform.translate(-pos.x(), -pos.y()); // spot to origin
setTransform(xform);
// force update
update();
pQEvent->accept();
}
};
QRectF toScr(QWidget *pQWidget, float x, float y, float w, float h)
{
const int wView = pQWidget->width(), hView = pQWidget->height();
const int s = wView < hView ? wView : hView;
return QRectF(
(0.5f * x + 0.5f) * s, (0.5f * y + 0.5f) * s,
0.5f * w * s, 0.5f * h * s);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
Canvas canvas;
canvas.setTransformationAnchor(QGraphicsView::NoAnchor);
canvas.setDragMode(QGraphicsView::NoDrag);
canvas.resize(256, 256);
canvas.show();
// prepare scene
QGraphicsScene qGScene;
qGScene.addRect(toScr(canvas.viewport(), -1.0f, -1.0f, 2.0f, 2.0f), QColor(0x000000u));
qGScene.addRect(toScr(canvas.viewport(), -0.2f, -0.2f, 0.4f, 0.4f), QColor(0x00ff00u));
qGScene.addRect(toScr(canvas.viewport(), -0.8f, -0.8f, 0.4f, 0.4f), QColor(0xff0000u));
qGScene.addRect(toScr(canvas.viewport(), -0.8f, 0.4f, 0.4f, 0.4f), QColor(0x0000ffu));
qGScene.addRect(toScr(canvas.viewport(), 0.4f, 0.4f, 0.4f, 0.4f), QColor(0xff00ffu));
qGScene.addRect(toScr(canvas.viewport(), 0.4f, -0.8f, 0.4f, 0.4f), QColor(0xffff00u));
canvas.setScene(&qGScene);
// runtime loop
return app.exec();
}
输出:
我挣扎了一段时间让它按预期运行,直到我意识到
QPointF delta = mapToScene(pQEvent->pos() - _posRMB); // Not working!
不一样
QPointF delta = mapToScene(pQEvent->pos()) - mapToScene(_posRMB);
此外,禁用自动适应视图很重要QGraphicsView
:
canvas.setTransformationAnchor(QGraphicsView::NoAnchor);
在再次考虑 OP 问题时,我意识到另一个可能的问题:
如果场景小于视图,它会自动对齐。(涉及到QGraphicsView::alignment。)
在我的演示会话中,我从放大开始,以防止这个问题。
另一种选择是让场景即使比视图更小也可以拖动——可以通过显式设置QGraphicsView::sceneRect来调整场景大小。
在滚动文档时。QGraphicsView我注意到:
拖动模式:拖动模式
此属性保存按下鼠标左键时在场景上拖动鼠标的行为。
该属性定义了当用户点击场景背景并拖动鼠标时应该发生什么(例如,使用指向手形光标滚动视口内容,或使用橡皮筋选择多个项目)。默认值 NoDrag 不执行任何操作。
此行为仅影响未由任何项目处理的鼠标单击。您可以通过创建 QGraphicsView 的子类并重新实现 mouseMoveEvent() 来定义自定义行为。
我觉得值得一提。
推荐阅读
- gtkmm - 如何覆盖 TextBuffer 的默认信号处理程序
- postgresql - 为什么在单个 POSTGRES 分区上工作会影响父表?
- go - 两个结构指针之间的类型转换
- elasticsearch - 一个大的 Elasticsearch 查找索引,还是几个较小的?
- javascript - 问题总数除以总机会。仅使用 JavaScript。div 元素
- arduino - Arduino Uno 的中断问题
- heroku - 如何查看哪个 github 存储库连接到 heroku 应用程序?
- listview - Flutter 从父级更新列表视图
- php - 如何用大写字母分隔单词?
- libgdx - Libgdx 使 getStatuscode 仅在 update() 中调用一次