QGraphicsView缩放内容时保持鼠标悬停位置不变
有时在QGraphicsView显示一张图片时,我们需要缩放图像同时保持鼠标悬停位置内容的位置不变。这时候就需要我们在缩放时实时控制QGraphicsView的水平和垂直滚动条控件的位置。本文给出一个实现此功能的简单例子。此例子在VS2017和Qt5.9的环境下测试通过。软件效果如下:
头文件:
class MImageView : public QGraphicsView { Q_OBJECT public: MImageView(QWidget* parent = 0); private: void mouseMoveEvent(QMouseEvent* event) override; void wheelEvent(QWheelEvent *event) override; private: QPointF wheelRatio; };
CPP文件。本代码方法是在鼠标移动的时候保存当前鼠标位置的比例,如果鼠标不动则不改变此值。然后在按住鼠标右键同时滚动滚轮时根据前面保存的信息计算视图新的水平和垂直滚动条的值。你可能会想完全可以在wheelEvent(...)中取鼠标位置作为缩放时鼠标的当前位置,但经过测试在此取值计算误差会比较大。尚不知道为什么误差大,可能是鼠标位置是整形而缩放之后的像素位置变成浮点型取整,反复这个操作导致累计误差越来越大:
MImageView::MImageView(QWidget* parent) : QGraphicsView(parent) { setMouseTracking(true); } void MImageView::mouseMoveEvent(QMouseEvent* event) { QPointF scp = mapToScene(event->pos()); QRectF rect = sceneRect(); wheelRatio.setX((scp.x() - rect.x()) / rect.width()); wheelRatio.setY((scp.y() - rect.y()) / rect.height()); } void MImageView::wheelEvent(QWheelEvent *event) { if (!(event->buttons() & Qt::MouseButton::RightButton)) { QGraphicsView::wheelEvent(event); return; } QGraphicsScene* sc = scene(); if (event->delta() > 0) { for (auto item : sc->items()) { item->setScale(item->scale() + 0.1); } } else { for (auto item : sc->items()) { item->setScale(item->scale() - 0.1); } } setSceneRect(sc->itemsBoundingRect()); QScrollBar *hbar = horizontalScrollBar(); int hmin = hbar->minimum(); int hmax = hbar->maximum(); int hstep = hbar->pageStep(); QScrollBar *vbar = verticalScrollBar(); int vmin = vbar->minimum(); int vmax = vbar->maximum(); int vstep = vbar->pageStep(); qreal xval = hmin + (hmax - hmin + hstep) * wheelRatio.x() - event->pos().x(); qreal yval = vmin + (vmax - vmin + vstep) * wheelRatio.y() - event->pos().y(); hbar->setValue(xval); vbar->setValue(yval); }
在主窗口初始化时操作如下。下方代码中QtTest是主窗口类,ui.gvHost是MImageView控件。它的作用就是给图形视图中添加一张图片:
QtTest::QtTest(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); QGraphicsScene* scene = new QGraphicsScene(ui.gvHost); scene->addPixmap(QPixmap(u8"2.bmp")); ui.gvHost->setScene(scene); }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程