C++ QGraphicsView当图像小于视图时将图像缩放到光标

C++ QGraphicsView当图像小于视图时将图像缩放到光标,c++,image,qt,scroll,qgraphicsview,C++,Image,Qt,Scroll,Qgraphicsview,我正在尝试实现一个代码,它可以放大图像并将图像移向光标,但不能完全重新定位光标的中心(类似于谷歌地图的工作方式,或者完全类似于Picasa Photo Viewer过去的工作方式,如果有人看到的话)。关键是,它需要放大图像,并使鼠标光标下的像素保持不变 的可接受答案中提供的示例代码很接近,但并不能完全解决问题,因为这是moreso的问题,因此如何使用光标放大并避开QGraphicsView中固有的问题 问题是:正如示例代码标题中的注释所示,如果视图大于图像,则无法执行此功能。换句话说,如果您缩小

我正在尝试实现一个代码,它可以放大图像并将图像移向光标,但不能完全重新定位光标的中心(类似于谷歌地图的工作方式,或者完全类似于Picasa Photo Viewer过去的工作方式,如果有人看到的话)。关键是,它需要放大图像,并使鼠标光标下的像素保持不变

的可接受答案中提供的示例代码很接近,但并不能完全解决问题,因为这是moreso的问题,因此如何使用光标放大并避开QGraphicsView中固有的问题

问题是:正如示例代码标题中的注释所示,如果视图大于图像,则无法执行此功能。换句话说,如果您缩小图像,使其没有滚动条,然后放大,图像将放大到中心,而不是鼠标光标;只有放大到有水平和垂直滚动条的程度,它才能放大到光标,并在光标下保持相同的像素

这似乎是QGraphicsView的一个基本问题:QGraphicsView::setTransformationAnchor(QGraphicsView::AnchorUnderMouse)可以获得几乎完全相同的结果,但Qt文档报告了相同的问题:

请注意,当只有场景的一部分可见时(即,当存在滚动条时),此属性的效果是明显的。否则,如果整个场景适合视图,QGraphicscene将使用视图对齐在视图中定位场景

我怀疑这是因为这两种方法都在滚动视口,但如果图像与视口相比太小,则无法实际滚动图像

我怀疑解决方案可能需要放弃滚动并实际移动图像,但我不知道如何移动图像,使相同的像素停留在鼠标光标下

以下是一些我已经实现但不起作用的代码:

图形\视图\缩放。h:

#include <QObject>
#include <QGraphicsView>

/*!
 * This class adds ability to zoom QGraphicsView using mouse wheel. The point under cursor
 * remains motionless while it's possible.
 *
 * Note that it becomes not possible when the scene's
 * size is not large enough comparing to the viewport size. QGraphicsView centers the picture
 * when it's smaller than the view. And QGraphicsView's scrolls boundaries don't allow to
 * put any picture point at any viewport position.
 *
 * When the user starts scrolling, this class remembers original scene position and
 * keeps it until scrolling is completed. It's better than getting original scene position at
 * each scrolling step because that approach leads to position errors due to before-mentioned
 * positioning restrictions.
 *
 * When zommed using scroll, this class emits zoomed() signal.
 *
 * Usage:
 *
 *   new Graphics_view_zoom(view);
 *
 * The object will be deleted automatically when the view is deleted.
 *
 * You can set keyboard modifiers used for zooming using set_modified(). Zooming will be
 * performed only on exact match of modifiers combination. The default modifier is Ctrl.
 *
 * You can change zoom velocity by calling set_zoom_factor_base().
 * Zoom coefficient is calculated as zoom_factor_base^angle_delta
 * (see QWheelEvent::angleDelta).
 * The default zoom factor base is 1.0015.
 */
class Graphics_view_zoom : public QObject {
  Q_OBJECT
public:
  Graphics_view_zoom(QGraphicsView* view);
  void gentle_zoom(double factor);
  void set_modifiers(Qt::KeyboardModifiers modifiers);
  void set_zoom_factor_base(double value);

private:
  QGraphicsView* _view;
  Qt::KeyboardModifiers _modifiers;
  double _zoom_factor_base;
  QPointF target_scene_pos, target_viewport_pos;
  bool eventFilter(QObject* object, QEvent* event);

signals:
  void zoomed();
};
#包括
#包括
/*!
*此类增加了使用鼠标滚轮缩放QGraphicsView的功能。光标下的点
*尽可能保持静止。
*
*请注意,当场景的
*与视口大小相比,大小不够大。QGraphicsView使图片居中
*当它小于视图时。QGraphicsView的卷轴边界不允许
*在任何视口位置放置任何图片点。
*
*当用户开始滚动时,此类会记住原始场景位置和
*保留它直到滚动完成。这比在一个位置获取原始场景位置要好
*由于上述原因,每个滚动步骤都会导致位置错误
*定位限制。
*
*当使用scroll进行僵尸化时,此类会发出Zomed()信号。
*
*用法:
*
*新图形\视图\缩放(视图);
*
*删除视图时,对象将自动删除。
*
*可以使用set_modified()设置用于缩放的键盘修改器。变焦将是一个巨大的挑战
*仅在修改器组合完全匹配的情况下执行。默认的修改器是Ctrl。
*
*可以通过调用set_zoom_factor_base()更改缩放速度。
*缩放系数计算为缩放系数^基准^角度^增量
*(请参见QWheelEvent::angleDelta)。
*默认的缩放因子基数为1.0015。
*/
类图形\视图\缩放:公共QObject{
Q_对象
公众:
图形视图缩放(QGraphicsView*视图);
void和u缩放(双因子);
void set_修饰符(Qt::keyboard修饰符修饰符);
无效集\缩放\系数\基准(双倍值);
私人:
QGraphicsView*\u视图;
Qt::键盘修饰符_修饰符;
双缩放因子基数;
QPointF目标\场景\位置、目标\视口\位置;
bool事件过滤器(QObject*对象,QEvent*事件);
信号:
void缩放();
};
图形\视图\缩放.cpp:

#include "Graphics_view_zoom.h"
#include <QMouseEvent>
#include <QApplication>
#include <QScrollBar>
#include <qmath.h>

Graphics_view_zoom::Graphics_view_zoom(QGraphicsView* view)
  : QObject(view), _view(view)
{
  _view->viewport()->installEventFilter(this);
  _view->setMouseTracking(true);
  _modifiers = Qt::ControlModifier;
  _zoom_factor_base = 1.0015;
}

void Graphics_view_zoom::gentle_zoom(double factor) {
  _view->scale(factor, factor);
  _view->centerOn(target_scene_pos);
  QPointF delta_viewport_pos = target_viewport_pos - QPointF(_view->viewport()->width() / 2.0,
                                                             _view->viewport()->height() / 2.0);
  QPointF viewport_center = _view->mapFromScene(target_scene_pos) - delta_viewport_pos;
  _view->centerOn(_view->mapToScene(viewport_center.toPoint()));
  emit zoomed();
}

void Graphics_view_zoom::set_modifiers(Qt::KeyboardModifiers modifiers) {
  _modifiers = modifiers;

}

void Graphics_view_zoom::set_zoom_factor_base(double value) {
  _zoom_factor_base = value;
}

bool Graphics_view_zoom::eventFilter(QObject *object, QEvent *event) {
  if (event->type() == QEvent::MouseMove) {
    QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
    QPointF delta = target_viewport_pos - mouse_event->pos();
    if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5) {
      target_viewport_pos = mouse_event->pos();
      target_scene_pos = _view->mapToScene(mouse_event->pos());
    }
  } else if (event->type() == QEvent::Wheel) {
    QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
    if (QApplication::keyboardModifiers() == _modifiers) {
      if (wheel_event->orientation() == Qt::Vertical) {
        double angle = wheel_event->angleDelta().y();
        double factor = qPow(_zoom_factor_base, angle);
        gentle_zoom(factor);
        return true;
      }
    }
  }
  Q_UNUSED(object)
  return false;
}
#包括“Graphics_view_zoom.h”
#包括
#包括
#包括
#包括
图形视图缩放::图形视图缩放(QGraphicsView*视图)
:QObject(视图),\u视图(视图)
{
_视图->视口()->installEventFilter(此);
_查看->设置鼠标追踪(真);
_修饰符=Qt::ControlModifier;
_缩放系数\基数=1.0015;
}
无效图形\视图\缩放::柔和\缩放(双因素){
_查看->比例(因子,因子);
_查看->中心(目标\场景\位置);
QPointF delta_viewport_pos=目标_viewport_pos-QPointF(_view->viewport()->width()/2.0,
_视图->视口()->高度()/2.0);
QPointF viewport\u center=\u view->mapFromScene(target\u scene\u pos)-delta\u viewport\u pos;
_视图->中心点(_视图->地图场景(viewport_center.toPoint());
发射缩放();
}
无效图形\视图\缩放::设置\修改器(Qt::键盘修改器){
_修饰符=修饰符;
}
无效图形\视图\缩放::设置\缩放\系数\基础(双值){
_缩放系数\基准=值;
}
bool Graphics\u view\u zoom::eventFilter(QObject*object,QEvent*event){
如果(事件->类型()==QEvent::MouseMove){
QMouseEvent*鼠标事件=静态播放(事件);
QPointF delta=target_viewport_pos-鼠标事件->pos();
if(qab(delta.x())>5 | | qab(delta.y())>5){
目标\视口\位置=鼠标\事件->位置();
目标\场景\位置=\视图->映射场景(鼠标\事件->位置());
}
}else if(事件->类型()==QEvent::Wheel){
QWheelEvent*wheel_事件=静态_投射(事件);
如果(QApplication::keyboardModifiers()==\u修饰符){
如果(车轮事件->方向()==Qt::垂直){
双角度=车轮事件->角度增量();
双因子=qPow(缩放因子、基准、角度);
平缓变焦(系数);
返回true;
}
}
}
Q_未使用(对象)
返回false;
}
main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
#包括“mainwindow.h”
#包括
int main(int argc,char*argv[])
{
质量保证申请a(argc、argv);
主窗口w;
w、 show();
返回a.exec();
}
主风
#pragma once

#include <QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
};
#include "mainwindow.h"

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPixmap>
#include <Graphics_view_zoom.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setFixedSize(1000,1000);

    QGraphicsScene* s = new QGraphicsScene(this);
    QGraphicsView*  v = new QGraphicsView(this);
    Graphics_view_zoom* z = new Graphics_view_zoom(v);
    z->set_modifiers(Qt::NoModifier);

    v->setScene(s);
    v->setFixedSize(1000,1000);

    QPixmap pix;
    if(pix.load("C:\\full\\path\\to_an_image_file.jpg"))
    {
        s->addPixmap(pix);
    }
}