Qt 5:缩放图像的鼠标滚轮事件行为
Qt 5 : Mouse Wheel event behaviour for zooming image
我有一个 window,其中有一个 QGraphicsView,它将显示图像。我已经实现了 wheelEvent()。我的图像大多会比 window 大,所以我在 window 中得到滚动条。
当我们在 Windows 照片查看器中查看图像时旋转轮子时,我们通常观察到的是,当我们向上移动轮子(朝向它的电线)时,图像会放大,而当我们向下移动轮子时,图像会放大(向外 body),图像缩小。
我得到的是当我将滚轮移向自己(缩小)图像而不是缩小图像时,首先向下滚动,并且仅当滚动条触及其最底部时才开始缩小。
最好通过尝试代码来理解问题。我想我无法解释。
我想要标准行为。怎么办?
代码
#include "viewer.h"
#include "ui_viewer.h"
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QGraphicsPixmapItem>
#include <QWheelEvent>
#include <QDebug>
#include <QImage>
#include <QImageReader>
#include <QApplication>
#include <QDesktopWidget>
viewer::viewer(QWidget *parent) : QWidget(parent),ui2(new Ui::viewer)
{
ui2->setupUi(this);
}
viewer::~viewer()
{
delete ui2;
}
int viewer::show_changes(QString folder)
{
QDesktopWidget *desktop = QApplication::desktop();
int screenWidth = desktop->width();
int screenHeight = desktop->height();
QString filename = "image_bigger_than_window.jpg";
QPixmap pixmap = QPixmap(filename);
QImageReader reader(filename);
QImage image = reader.read();
QSize size = image.size();
int width = 800;
int height = (width * size.height()) / size.width();
int x = (screenWidth - width) / 2;
int y = (screenHeight - height) / 2 - 30;
setGeometry(x,y,width, height);
setWindowTitle("OUTPUT");
ui2->graphicsView->setGeometry(0,0,width,height);
QGraphicsScene* viewScene = new QGraphicsScene(QRectF(0, 0,width, height), 0);
QGraphicsPixmapItem *item = viewScene->addPixmap(pixmap.scaled(QSize((int)viewScene->width(), (int)viewScene->height()),
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
viewScene->addItem(item);
ui2->graphicsView->fitInView(QRectF(0, 0, width, height),Qt::IgnoreAspectRatio);
ui2->graphicsView->setScene(viewScene);
ui2->graphicsView->show();
return 0;
}
void viewer::wheelEvent(QWheelEvent * event)
{
const int degrees = event->delta() / 8;
qDebug() << degrees;
int steps = degrees / 15;
double scaleFactor = 1.0;
const qreal minFactor = 1.0;
const qreal maxFactor = 10.0;
qreal h11 = 1.0, h22 = 0;
if(steps > 0)
{
h11 = (h11 >= maxFactor) ? h11 : (h11 + scaleFactor);
h22 = (h22 >= maxFactor) ? h22 : (h22 + scaleFactor);
}
else
{
h11 = (h11 <= minFactor) ? minFactor : (h11 - scaleFactor);
h22 = (h22 <= minFactor) ? minFactor : (h22 - scaleFactor);
}
ui2->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
ui2->graphicsView->setTransform(QTransform(h11, 0, 0,0, h22, 0, 0,0,1));
}
编辑
1)从 viewer.cpp
中删除了函数 void viewer::wheelEvent(QWheelEvent * event)
2) 将 bool viewer::eventFilter(QObject *obj, QEvent *event)
作为受保护函数放在原位,将 void viewer::handleWheelOnGraphicsScene(QGraphicsSceneWheelEvent* scrollevent)
作为 public 插槽放在 viewer.h
中
bool viewer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneWheel)
{
QGraphicsSceneWheelEvent *scrollevent = static_cast<QGraphicsSceneWheelEvent *>(event);
handleWheelOnGraphicsScene(scrollevent);
return true;
}
// Other events should propagate - what do you mean by propagate here?
return false;
}
void viewer::handleWheelOnGraphicsScene(QGraphicsSceneWheelEvent* scrollevent)
{
const int degrees = scrollevent->delta() / 8;
qDebug() << degrees;
int steps = degrees / 15;
qDebug() << steps;
double scaleFactor = 1.0; //How fast we zoom
const qreal minFactor = 1.0;
const qreal maxFactor = 10.0;
if(steps > 0)
{
h11 = (h11 >= maxFactor) ? h11 : (h11 + scaleFactor);
h22 = (h22 >= maxFactor) ? h22 : (h22 + scaleFactor);
}
else
{
h11 = (h11 <= minFactor) ? minFactor : (h11 - scaleFactor);
h22 = (h22 <= minFactor) ? minFactor : (h22 - scaleFactor);
}
ui2->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
ui2->graphicsView->setTransform(QTransform(h11, 0, 0,0, h22, 0, 0,0,1));
}
代码显示您没有使用子class QGraphicsView
,而是在您自己的小部件中使用了一个。
wheel 事件将首先发送到实际的图形视图小部件。它是用 Qt 的默认行为处理的,即滚动。仅当您滚动到底部时,图形视图无法处理滚轮事件,并且它会传播到其父级,即您的 class。这就是为什么您只能在滚动到边框时才能缩放。
要解决此问题,您应该 install an event filter。这允许您拦截 wheel 事件并在 class:
中处理它
// Outline, not tested
viewer::viewer(QWidget *parent) : QWidget(parent),ui2(new Ui::viewer)
{
ui2->setupUi(this);
// Let me handle your events
ui2->graphicsView->installEventFilter(this);
}
// should be protected
bool viewer::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::GraphicsSceneWheel) {
// Your implementation.
// You can't use QWheelEvent, as Graphicscene works with its own events...
handleWheelOnGraphicsScene(static_cast<QGraphicsSceneWheelEvent*> (event));
// Don't propagate
return true;
}
// Other events should propagate
return false;
}
更新
我刚刚发现事件过滤器不会接收图形视图上的 GraphicsSceneWheel 事件。相反,您必须在图形场景上安装过滤器。此外,您必须调用 event->accept()
以便它不会传播。
所以更新了代码:
// In Constructor, or where appropriate
ui2->graphicsView->scene()->installEventFilter(this);
bool viewer::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::GraphicsSceneWheel) {
handleWheelOnGraphicsScene(static_cast<QGraphicsSceneWheelEvent*> (event));
// Don't propagate
event->accept();
return true;
}
return false;
}
另请注意 handleWheelOnGraphicsScene
或任何您想调用的名称,应该是私有方法,而不必是插槽。
我有一个 window,其中有一个 QGraphicsView,它将显示图像。我已经实现了 wheelEvent()。我的图像大多会比 window 大,所以我在 window 中得到滚动条。
当我们在 Windows 照片查看器中查看图像时旋转轮子时,我们通常观察到的是,当我们向上移动轮子(朝向它的电线)时,图像会放大,而当我们向下移动轮子时,图像会放大(向外 body),图像缩小。
我得到的是当我将滚轮移向自己(缩小)图像而不是缩小图像时,首先向下滚动,并且仅当滚动条触及其最底部时才开始缩小。
最好通过尝试代码来理解问题。我想我无法解释。
我想要标准行为。怎么办?
代码
#include "viewer.h"
#include "ui_viewer.h"
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QGraphicsPixmapItem>
#include <QWheelEvent>
#include <QDebug>
#include <QImage>
#include <QImageReader>
#include <QApplication>
#include <QDesktopWidget>
viewer::viewer(QWidget *parent) : QWidget(parent),ui2(new Ui::viewer)
{
ui2->setupUi(this);
}
viewer::~viewer()
{
delete ui2;
}
int viewer::show_changes(QString folder)
{
QDesktopWidget *desktop = QApplication::desktop();
int screenWidth = desktop->width();
int screenHeight = desktop->height();
QString filename = "image_bigger_than_window.jpg";
QPixmap pixmap = QPixmap(filename);
QImageReader reader(filename);
QImage image = reader.read();
QSize size = image.size();
int width = 800;
int height = (width * size.height()) / size.width();
int x = (screenWidth - width) / 2;
int y = (screenHeight - height) / 2 - 30;
setGeometry(x,y,width, height);
setWindowTitle("OUTPUT");
ui2->graphicsView->setGeometry(0,0,width,height);
QGraphicsScene* viewScene = new QGraphicsScene(QRectF(0, 0,width, height), 0);
QGraphicsPixmapItem *item = viewScene->addPixmap(pixmap.scaled(QSize((int)viewScene->width(), (int)viewScene->height()),
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
viewScene->addItem(item);
ui2->graphicsView->fitInView(QRectF(0, 0, width, height),Qt::IgnoreAspectRatio);
ui2->graphicsView->setScene(viewScene);
ui2->graphicsView->show();
return 0;
}
void viewer::wheelEvent(QWheelEvent * event)
{
const int degrees = event->delta() / 8;
qDebug() << degrees;
int steps = degrees / 15;
double scaleFactor = 1.0;
const qreal minFactor = 1.0;
const qreal maxFactor = 10.0;
qreal h11 = 1.0, h22 = 0;
if(steps > 0)
{
h11 = (h11 >= maxFactor) ? h11 : (h11 + scaleFactor);
h22 = (h22 >= maxFactor) ? h22 : (h22 + scaleFactor);
}
else
{
h11 = (h11 <= minFactor) ? minFactor : (h11 - scaleFactor);
h22 = (h22 <= minFactor) ? minFactor : (h22 - scaleFactor);
}
ui2->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
ui2->graphicsView->setTransform(QTransform(h11, 0, 0,0, h22, 0, 0,0,1));
}
编辑
1)从 viewer.cpp
void viewer::wheelEvent(QWheelEvent * event)
2) 将 bool viewer::eventFilter(QObject *obj, QEvent *event)
作为受保护函数放在原位,将 void viewer::handleWheelOnGraphicsScene(QGraphicsSceneWheelEvent* scrollevent)
作为 public 插槽放在 viewer.h
bool viewer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneWheel)
{
QGraphicsSceneWheelEvent *scrollevent = static_cast<QGraphicsSceneWheelEvent *>(event);
handleWheelOnGraphicsScene(scrollevent);
return true;
}
// Other events should propagate - what do you mean by propagate here?
return false;
}
void viewer::handleWheelOnGraphicsScene(QGraphicsSceneWheelEvent* scrollevent)
{
const int degrees = scrollevent->delta() / 8;
qDebug() << degrees;
int steps = degrees / 15;
qDebug() << steps;
double scaleFactor = 1.0; //How fast we zoom
const qreal minFactor = 1.0;
const qreal maxFactor = 10.0;
if(steps > 0)
{
h11 = (h11 >= maxFactor) ? h11 : (h11 + scaleFactor);
h22 = (h22 >= maxFactor) ? h22 : (h22 + scaleFactor);
}
else
{
h11 = (h11 <= minFactor) ? minFactor : (h11 - scaleFactor);
h22 = (h22 <= minFactor) ? minFactor : (h22 - scaleFactor);
}
ui2->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
ui2->graphicsView->setTransform(QTransform(h11, 0, 0,0, h22, 0, 0,0,1));
}
代码显示您没有使用子class QGraphicsView
,而是在您自己的小部件中使用了一个。
wheel 事件将首先发送到实际的图形视图小部件。它是用 Qt 的默认行为处理的,即滚动。仅当您滚动到底部时,图形视图无法处理滚轮事件,并且它会传播到其父级,即您的 class。这就是为什么您只能在滚动到边框时才能缩放。
要解决此问题,您应该 install an event filter。这允许您拦截 wheel 事件并在 class:
中处理它// Outline, not tested
viewer::viewer(QWidget *parent) : QWidget(parent),ui2(new Ui::viewer)
{
ui2->setupUi(this);
// Let me handle your events
ui2->graphicsView->installEventFilter(this);
}
// should be protected
bool viewer::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::GraphicsSceneWheel) {
// Your implementation.
// You can't use QWheelEvent, as Graphicscene works with its own events...
handleWheelOnGraphicsScene(static_cast<QGraphicsSceneWheelEvent*> (event));
// Don't propagate
return true;
}
// Other events should propagate
return false;
}
更新
我刚刚发现事件过滤器不会接收图形视图上的 GraphicsSceneWheel 事件。相反,您必须在图形场景上安装过滤器。此外,您必须调用 event->accept()
以便它不会传播。
所以更新了代码:
// In Constructor, or where appropriate
ui2->graphicsView->scene()->installEventFilter(this);
bool viewer::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::GraphicsSceneWheel) {
handleWheelOnGraphicsScene(static_cast<QGraphicsSceneWheelEvent*> (event));
// Don't propagate
event->accept();
return true;
}
return false;
}
另请注意 handleWheelOnGraphicsScene
或任何您想调用的名称,应该是私有方法,而不必是插槽。