问题描述
我正在尝试实现可以放大图像并将图像移向光标的代码,但不会完全以光标为中心(类似于 Google 地图的工作方式,或完全类似于 Picasa 照片查看器的工作方式)如果有人看到的话,曾经可以工作)。关键是它需要放大图像,并具有与鼠标光标下相同的像素,仍然在其下。
this question 的已接受答案中提供的示例代码很接近,但不能完全解决问题,因为这是一个关于如何放大 光标并避开 QGraphicsView 固有的问题。
问题是:如标题中示例代码的注释所示,如果视图大于图像,则无法执行此功能。换句话说,如果你把图片缩小到没有滚动条,然后再放大,图片会放大到中心,而不是鼠标光标;只有通过放大到有水平和垂直滚动条,它才会放大光标并保持光标下方相同的像素。
这似乎是 QGraphicsView 的一个基本问题: QGraphicsView::setTransformationAnchor(QGraphicsView::AnchorUnderMouse) 可以达到几乎完全相同的结果,但 Qt 文档报告了同样的问题:
请注意,当只有一部分场景可见时(即有滚动条时),此属性的效果很明显。否则,如果整个场景适合视图,QGraphicsScene 使用视图对齐来定位视图中的场景。
我怀疑这是因为这两种方法都滚动视口,但如果图像与视口相比太小,则无法实际滚动它。
我怀疑该解决方案可能需要放弃滚动并实际移动图像,但我无法弄清楚如何移动图像以使相同的像素停留在鼠标光标下方。
这是我已经实现但不起作用的一些代码:
Graphics_view_zoom.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();
};
Graphics_view_zoom.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;
}
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:
#pragma once
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
};
mainwindow.cpp:
#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);
}
}
我也尝试了找到 here 的修复,但这也有完全相同的问题:如果图像放大到足够远,像素将仅保持在光标下提供垂直和水平滚动选项。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)