fix:图像显示修复触摸屏下放大缩小问题
This commit is contained in:
parent
7225f03ded
commit
76b63103af
@ -620,6 +620,11 @@ void PointCloudGLWidget::drawPrimitives(const QMatrix4x4& mvp,
|
|||||||
glUniformMatrix4fv(m_mvpLocation, 1, GL_FALSE, mvp.constData());
|
glUniformMatrix4fv(m_mvpLocation, 1, GL_FALSE, mvp.constData());
|
||||||
glUniform1f(m_pointSizeLocation, pointSize);
|
glUniform1f(m_pointSizeLocation, pointSize);
|
||||||
glUniform1f(m_alphaLocation, alpha);
|
glUniform1f(m_alphaLocation, alpha);
|
||||||
|
if (!m_dynamicVbo.isCreated())
|
||||||
|
{
|
||||||
|
m_dynamicVbo.create();
|
||||||
|
}
|
||||||
|
m_dynamicVbo.setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||||
if (depthTest) {
|
if (depthTest) {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
} else {
|
} else {
|
||||||
@ -2889,6 +2894,7 @@ void PointCloudGLWidget::clearBasicShapeSegments()
|
|||||||
void PointCloudGLWidget::addPosePoints(const QVector<PosePoint>& poses)
|
void PointCloudGLWidget::addPosePoints(const QVector<PosePoint>& poses)
|
||||||
{
|
{
|
||||||
m_posePoints.append(poses);
|
m_posePoints.append(poses);
|
||||||
|
computeBoundingBox();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2993,66 +2999,138 @@ void PointCloudGLWidget::drawLineSegmentList(const QVector<LineSegment>& segment
|
|||||||
|
|
||||||
void PointCloudGLWidget::drawPosePoints()
|
void PointCloudGLWidget::drawPosePoints()
|
||||||
{
|
{
|
||||||
if (m_posePoints.isEmpty()) {
|
if (m_posePoints.isEmpty())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glLineWidth(2.0f);
|
// 从视图矩阵取相机右/上方向,把轴线拉成面向屏幕的窄带,避免 GLES2 线宽被钳成 1 像素。
|
||||||
|
const QMatrix4x4 invView = m_view.inverted();
|
||||||
|
const QVector3D camRight = invView.column(0).toVector3D().normalized();
|
||||||
|
const QVector3D camUp = invView.column(1).toVector3D().normalized();
|
||||||
|
const float pixelWorld = m_distance *
|
||||||
|
std::tan(qDegreesToRadians(22.5f)) /
|
||||||
|
static_cast<float>(qMax(1, height() / 2));
|
||||||
|
|
||||||
for (const auto& pose : m_posePoints) {
|
auto applyEulerRotation = [this](QMatrix4x4& poseLocal, const PosePoint& pose)
|
||||||
// 移动到姿态点位置,并按欧拉角顺序旋转(QMatrix4x4::rotate 与 glRotatef 同为右乘)
|
{
|
||||||
QMatrix4x4 modelView;
|
switch (m_eulerRotationOrder)
|
||||||
modelView.setToIdentity();
|
{
|
||||||
modelView.translate(pose.x, pose.y, pose.z);
|
case EulerRotationOrder::ZYX:
|
||||||
switch (m_eulerRotationOrder) {
|
poseLocal.rotate(pose.rx, 1, 0, 0);
|
||||||
case EulerRotationOrder::ZYX: // Yaw-Pitch-Roll(最常用)
|
poseLocal.rotate(pose.ry, 0, 1, 0);
|
||||||
modelView.rotate(pose.rx, 1, 0, 0);
|
poseLocal.rotate(pose.rz, 0, 0, 1);
|
||||||
modelView.rotate(pose.ry, 0, 1, 0);
|
|
||||||
modelView.rotate(pose.rz, 0, 0, 1);
|
|
||||||
break;
|
break;
|
||||||
case EulerRotationOrder::XYZ: // Roll-Pitch-Yaw
|
case EulerRotationOrder::XYZ:
|
||||||
modelView.rotate(pose.rz, 0, 0, 1);
|
poseLocal.rotate(pose.rz, 0, 0, 1);
|
||||||
modelView.rotate(pose.ry, 0, 1, 0);
|
poseLocal.rotate(pose.ry, 0, 1, 0);
|
||||||
modelView.rotate(pose.rx, 1, 0, 0);
|
poseLocal.rotate(pose.rx, 1, 0, 0);
|
||||||
break;
|
break;
|
||||||
case EulerRotationOrder::ZXY: // Yaw-Roll-Pitch
|
case EulerRotationOrder::ZXY:
|
||||||
modelView.rotate(pose.ry, 0, 1, 0);
|
poseLocal.rotate(pose.ry, 0, 1, 0);
|
||||||
modelView.rotate(pose.rx, 1, 0, 0);
|
poseLocal.rotate(pose.rx, 1, 0, 0);
|
||||||
modelView.rotate(pose.rz, 0, 0, 1);
|
poseLocal.rotate(pose.rz, 0, 0, 1);
|
||||||
break;
|
break;
|
||||||
case EulerRotationOrder::YXZ: // Pitch-Roll-Yaw
|
case EulerRotationOrder::YXZ:
|
||||||
modelView.rotate(pose.rz, 0, 0, 1);
|
poseLocal.rotate(pose.rz, 0, 0, 1);
|
||||||
modelView.rotate(pose.rx, 1, 0, 0);
|
poseLocal.rotate(pose.rx, 1, 0, 0);
|
||||||
modelView.rotate(pose.ry, 0, 1, 0);
|
poseLocal.rotate(pose.ry, 0, 1, 0);
|
||||||
break;
|
break;
|
||||||
case EulerRotationOrder::XZY: // Roll-Yaw-Pitch
|
case EulerRotationOrder::XZY:
|
||||||
modelView.rotate(pose.ry, 0, 1, 0);
|
poseLocal.rotate(pose.ry, 0, 1, 0);
|
||||||
modelView.rotate(pose.rz, 0, 0, 1);
|
poseLocal.rotate(pose.rz, 0, 0, 1);
|
||||||
modelView.rotate(pose.rx, 1, 0, 0);
|
poseLocal.rotate(pose.rx, 1, 0, 0);
|
||||||
break;
|
break;
|
||||||
case EulerRotationOrder::YZX: // Pitch-Yaw-Roll
|
case EulerRotationOrder::YZX:
|
||||||
modelView.rotate(pose.rx, 1, 0, 0);
|
poseLocal.rotate(pose.rx, 1, 0, 0);
|
||||||
modelView.rotate(pose.rz, 0, 0, 1);
|
poseLocal.rotate(pose.rz, 0, 0, 1);
|
||||||
modelView.rotate(pose.ry, 0, 1, 0);
|
poseLocal.rotate(pose.ry, 0, 1, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const QMatrix4x4 mvp = m_projection * modelView;
|
auto appendWorld = [](QVector<float>& dst, const QVector3D& p)
|
||||||
|
{
|
||||||
|
dst.append(p.x());
|
||||||
|
dst.append(p.y());
|
||||||
|
dst.append(p.z());
|
||||||
|
};
|
||||||
|
|
||||||
// 绘制坐标系(右手坐标系:X红右,Y绿上,Z蓝前)
|
auto appendAxisBand = [&](QVector<float>& positions,
|
||||||
const float positions[] = {
|
QVector<float>& colors,
|
||||||
0.0f, 0.0f, 0.0f, pose.scale, 0.0f, 0.0f, // X轴 - 红色
|
const QVector3D& start,
|
||||||
0.0f, 0.0f, 0.0f, 0.0f, pose.scale, 0.0f, // Y轴 - 绿色
|
const QVector3D& end,
|
||||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, pose.scale // Z轴 - 蓝色
|
const QVector3D& color,
|
||||||
|
float halfWidth)
|
||||||
|
{
|
||||||
|
QVector3D side = QVector3D::crossProduct(end - start, camUp);
|
||||||
|
if (side.lengthSquared() < 1.0e-12f)
|
||||||
|
{
|
||||||
|
side = QVector3D::crossProduct(end - start, camRight);
|
||||||
|
}
|
||||||
|
if (!side.isNull())
|
||||||
|
{
|
||||||
|
side.normalize();
|
||||||
|
side *= halfWidth;
|
||||||
|
}
|
||||||
|
const QVector3D s0 = start - side;
|
||||||
|
const QVector3D s1 = start + side;
|
||||||
|
const QVector3D e0 = end - side;
|
||||||
|
const QVector3D e1 = end + side;
|
||||||
|
const QVector3D quad[6] = {s0, e0, e1, s0, e1, s1};
|
||||||
|
for (const QVector3D& p : quad)
|
||||||
|
{
|
||||||
|
appendWorld(positions, p);
|
||||||
|
appendWorld(colors, color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& pose : m_posePoints)
|
||||||
|
{
|
||||||
|
QMatrix4x4 poseLocal;
|
||||||
|
poseLocal.setToIdentity();
|
||||||
|
poseLocal.translate(pose.x, pose.y, pose.z);
|
||||||
|
applyEulerRotation(poseLocal, pose);
|
||||||
|
|
||||||
|
const float axisLength = qMax(1.0f, pose.scale);
|
||||||
|
const QVector3D origin = poseLocal.map(QVector3D(0.0f, 0.0f, 0.0f));
|
||||||
|
const QVector3D xEnd = poseLocal.map(QVector3D(axisLength, 0.0f, 0.0f));
|
||||||
|
const QVector3D yEnd = poseLocal.map(QVector3D(0.0f, axisLength, 0.0f));
|
||||||
|
const QVector3D zEnd = poseLocal.map(QVector3D(0.0f, 0.0f, axisLength));
|
||||||
|
const float halfWidth = qMax(axisLength * 0.02f, pixelWorld * 2.0f);
|
||||||
|
|
||||||
|
QVector<float> bandPositions;
|
||||||
|
QVector<float> bandColors;
|
||||||
|
bandPositions.reserve(54);
|
||||||
|
bandColors.reserve(54);
|
||||||
|
appendAxisBand(bandPositions, bandColors, origin, xEnd, QVector3D(1.0f, 0.0f, 0.0f), halfWidth);
|
||||||
|
appendAxisBand(bandPositions, bandColors, origin, yEnd, QVector3D(0.0f, 1.0f, 0.0f), halfWidth);
|
||||||
|
appendAxisBand(bandPositions, bandColors, origin, zEnd, QVector3D(0.0f, 0.0f, 1.0f), halfWidth);
|
||||||
|
|
||||||
|
// 关闭深度测试,避免姿态轴被周围点云挡住。
|
||||||
|
drawPrimitives(m_mvp,
|
||||||
|
bandPositions.constData(),
|
||||||
|
bandPositions.size() / 3,
|
||||||
|
GL_TRIANGLES,
|
||||||
|
bandColors.constData(),
|
||||||
|
QVector3D(1.0f, 1.0f, 1.0f),
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
false);
|
||||||
|
|
||||||
|
const float tipPositions[] = {
|
||||||
|
origin.x(), origin.y(), origin.z(),
|
||||||
|
xEnd.x(), xEnd.y(), xEnd.z(),
|
||||||
|
yEnd.x(), yEnd.y(), yEnd.z(),
|
||||||
|
zEnd.x(), zEnd.y(), zEnd.z()
|
||||||
};
|
};
|
||||||
const float colors[] = {
|
const float tipColors[] = {
|
||||||
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
1.0f, 1.0f, 1.0f,
|
||||||
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
1.0f, 0.0f, 0.0f,
|
||||||
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f
|
||||||
};
|
};
|
||||||
drawPrimitives(mvp, positions, 6, GL_LINES, colors,
|
drawPrimitives(m_mvp, tipPositions, 4, GL_POINTS, tipColors,
|
||||||
QVector3D(1.0f, 1.0f, 1.0f), 1.0f, 1.0f, true);
|
QVector3D(1.0f, 1.0f, 1.0f), 10.0f, 1.0f, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
glLineWidth(1.0f);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,12 @@
|
|||||||
#include <Qt>
|
#include <Qt>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
class QEvent;
|
||||||
|
class QGestureEvent;
|
||||||
class QGraphicsPixmapItem;
|
class QGraphicsPixmapItem;
|
||||||
class QGraphicsScene;
|
class QGraphicsScene;
|
||||||
class QMouseEvent;
|
class QMouseEvent;
|
||||||
|
class QPinchGesture;
|
||||||
class QWheelEvent;
|
class QWheelEvent;
|
||||||
|
|
||||||
// 可缩放、可平移的图片显示控件。
|
// 可缩放、可平移的图片显示控件。
|
||||||
@ -48,6 +51,7 @@ signals:
|
|||||||
void zoomRatioChanged(double ratio);
|
void zoomRatioChanged(double ratio);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool viewportEvent(QEvent* event) override;
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
void wheelEvent(QWheelEvent* event) override;
|
void wheelEvent(QWheelEvent* event) override;
|
||||||
void mousePressEvent(QMouseEvent* event) override;
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
@ -56,8 +60,11 @@ protected:
|
|||||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool handleGestureEvent(QGestureEvent* event);
|
||||||
|
void handlePinchGesture(QPinchGesture* gesture);
|
||||||
void updateZoomLabel();
|
void updateZoomLabel();
|
||||||
void updateZoomRatio(double ratio, bool keepCenter);
|
void updateZoomRatio(double ratio, bool keepCenter);
|
||||||
|
void updateZoomRatioAt(double ratio, const QPoint& viewportAnchor);
|
||||||
void repositionZoomLabel();
|
void repositionZoomLabel();
|
||||||
|
|
||||||
QGraphicsScene* m_scene;
|
QGraphicsScene* m_scene;
|
||||||
@ -69,6 +76,8 @@ private:
|
|||||||
double m_maximumZoomRatio;
|
double m_maximumZoomRatio;
|
||||||
Qt::Alignment m_imageAlignment;
|
Qt::Alignment m_imageAlignment;
|
||||||
bool m_panning;
|
bool m_panning;
|
||||||
|
bool m_pinching;
|
||||||
bool m_needsInitialFit;
|
bool m_needsInitialFit;
|
||||||
|
double m_pinchStartZoomRatio;
|
||||||
QPoint m_lastMousePosition;
|
QPoint m_lastMousePosition;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,19 +1,24 @@
|
|||||||
#include "ImageView.h"
|
#include "ImageView.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QGestureEvent>
|
||||||
#include <QGraphicsPixmapItem>
|
#include <QGraphicsPixmapItem>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QPinchGesture>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QtWidgets/QScrollBar>
|
#include <QtWidgets/QScrollBar>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
constexpr double kDefaultMinimumZoom = 0.02;
|
constexpr double kDefaultMinimumZoom = 0.02;
|
||||||
constexpr double kDefaultMaximumZoom = 20.0;
|
constexpr double kDefaultMaximumZoom = 20.0;
|
||||||
constexpr double kZoomStep = 1.25;
|
constexpr double kZoomStep = 1.25;
|
||||||
|
const QColor kDefaultBackgroundColor(37, 38, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageView::ImageView(QWidget* parent)
|
ImageView::ImageView(QWidget* parent)
|
||||||
@ -26,10 +31,12 @@ ImageView::ImageView(QWidget* parent)
|
|||||||
m_maximumZoomRatio(kDefaultMaximumZoom),
|
m_maximumZoomRatio(kDefaultMaximumZoom),
|
||||||
m_imageAlignment(Qt::AlignCenter),
|
m_imageAlignment(Qt::AlignCenter),
|
||||||
m_panning(false),
|
m_panning(false),
|
||||||
m_needsInitialFit(false)
|
m_pinching(false),
|
||||||
|
m_needsInitialFit(false),
|
||||||
|
m_pinchStartZoomRatio(1.0)
|
||||||
{
|
{
|
||||||
setScene(m_scene);
|
setScene(m_scene);
|
||||||
setBackgroundBrush(QColor(35, 35, 35));
|
setBackgroundBrush(kDefaultBackgroundColor);
|
||||||
setFrameShape(QFrame::NoFrame);
|
setFrameShape(QFrame::NoFrame);
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
@ -39,6 +46,10 @@ ImageView::ImageView(QWidget* parent)
|
|||||||
setDragMode(QGraphicsView::NoDrag);
|
setDragMode(QGraphicsView::NoDrag);
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
|
|
||||||
|
// 手势由 QGraphicsView 的视口接收,支持触摸屏双指捏合缩放。
|
||||||
|
viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
|
||||||
|
viewport()->grabGesture(Qt::PinchGesture);
|
||||||
|
|
||||||
m_zoomLabel->setObjectName(QStringLiteral("imageViewZoomLabel"));
|
m_zoomLabel->setObjectName(QStringLiteral("imageViewZoomLabel"));
|
||||||
m_zoomLabel->setAlignment(Qt::AlignCenter);
|
m_zoomLabel->setAlignment(Qt::AlignCenter);
|
||||||
m_zoomLabel->setMinimumWidth(58);
|
m_zoomLabel->setMinimumWidth(58);
|
||||||
@ -197,6 +208,65 @@ Qt::Alignment ImageView::imageAlignment() const
|
|||||||
return m_imageAlignment;
|
return m_imageAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImageView::viewportEvent(QEvent* event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::Gesture)
|
||||||
|
{
|
||||||
|
return handleGestureEvent(static_cast<QGestureEvent*>(event));
|
||||||
|
}
|
||||||
|
return QGraphicsView::viewportEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageView::handleGestureEvent(QGestureEvent* event)
|
||||||
|
{
|
||||||
|
QGesture* gesture = event->gesture(Qt::PinchGesture);
|
||||||
|
if (!gesture)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPinchGesture* pinchGesture = static_cast<QPinchGesture*>(gesture);
|
||||||
|
handlePinchGesture(pinchGesture);
|
||||||
|
event->accept(pinchGesture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageView::handlePinchGesture(QPinchGesture* gesture)
|
||||||
|
{
|
||||||
|
if (!gesture)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gesture->state() == Qt::GestureStarted)
|
||||||
|
{
|
||||||
|
// 双指手势开始后停止单指模拟产生的鼠标拖拽。
|
||||||
|
m_pinching = true;
|
||||||
|
m_panning = false;
|
||||||
|
m_pinchStartZoomRatio = m_zoomRatio;
|
||||||
|
setCursor(Qt::OpenHandCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasImage() &&
|
||||||
|
(gesture->state() == Qt::GestureStarted || gesture->state() == Qt::GestureUpdated))
|
||||||
|
{
|
||||||
|
const double scaleFactor = gesture->totalScaleFactor();
|
||||||
|
if (qIsFinite(scaleFactor) && scaleFactor > 0.0)
|
||||||
|
{
|
||||||
|
// 使用累计缩放比例,避免连续事件带来的比例漂移。
|
||||||
|
updateZoomRatioAt(m_pinchStartZoomRatio * scaleFactor,
|
||||||
|
gesture->centerPoint().toPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gesture->state() == Qt::GestureFinished ||
|
||||||
|
gesture->state() == Qt::GestureCanceled)
|
||||||
|
{
|
||||||
|
m_pinching = false;
|
||||||
|
setCursor(Qt::OpenHandCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ImageView::resizeEvent(QResizeEvent* event)
|
void ImageView::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
QGraphicsView::resizeEvent(event);
|
QGraphicsView::resizeEvent(event);
|
||||||
@ -221,6 +291,11 @@ void ImageView::wheelEvent(QWheelEvent* event)
|
|||||||
|
|
||||||
void ImageView::mousePressEvent(QMouseEvent* event)
|
void ImageView::mousePressEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
|
if (m_pinching)
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (event->button() == Qt::LeftButton && hasImage()) {
|
if (event->button() == Qt::LeftButton && hasImage()) {
|
||||||
m_panning = true;
|
m_panning = true;
|
||||||
m_lastMousePosition = event->pos();
|
m_lastMousePosition = event->pos();
|
||||||
@ -233,6 +308,11 @@ void ImageView::mousePressEvent(QMouseEvent* event)
|
|||||||
|
|
||||||
void ImageView::mouseMoveEvent(QMouseEvent* event)
|
void ImageView::mouseMoveEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
|
if (m_pinching)
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (m_panning) {
|
if (m_panning) {
|
||||||
const QPoint delta = event->pos() - m_lastMousePosition;
|
const QPoint delta = event->pos() - m_lastMousePosition;
|
||||||
m_lastMousePosition = event->pos();
|
m_lastMousePosition = event->pos();
|
||||||
@ -246,6 +326,11 @@ void ImageView::mouseMoveEvent(QMouseEvent* event)
|
|||||||
|
|
||||||
void ImageView::mouseReleaseEvent(QMouseEvent* event)
|
void ImageView::mouseReleaseEvent(QMouseEvent* event)
|
||||||
{
|
{
|
||||||
|
if (m_pinching)
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (event->button() == Qt::LeftButton && m_panning) {
|
if (event->button() == Qt::LeftButton && m_panning) {
|
||||||
m_panning = false;
|
m_panning = false;
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
@ -300,6 +385,34 @@ void ImageView::updateZoomRatio(double ratio, bool keepCenter)
|
|||||||
emit zoomRatioChanged(m_zoomRatio);
|
emit zoomRatioChanged(m_zoomRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageView::updateZoomRatioAt(double ratio, const QPoint& viewportAnchor)
|
||||||
|
{
|
||||||
|
if (!hasImage())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ratio = qBound(m_minimumZoomRatio, ratio, m_maximumZoomRatio);
|
||||||
|
if (qFuzzyCompare(ratio, m_zoomRatio) && !transform().isIdentity())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩放前后保持双指中心对应同一个图像位置。
|
||||||
|
const QPointF sceneAnchor = mapToScene(viewportAnchor);
|
||||||
|
resetTransform();
|
||||||
|
scale(ratio, ratio);
|
||||||
|
m_zoomRatio = ratio;
|
||||||
|
const QPointF mappedAnchor = mapFromScene(sceneAnchor);
|
||||||
|
const QPointF viewportDelta = mappedAnchor - viewportAnchor;
|
||||||
|
horizontalScrollBar()->setValue(
|
||||||
|
horizontalScrollBar()->value() + qRound(viewportDelta.x()));
|
||||||
|
verticalScrollBar()->setValue(
|
||||||
|
verticalScrollBar()->value() + qRound(viewportDelta.y()));
|
||||||
|
updateZoomLabel();
|
||||||
|
emit zoomRatioChanged(m_zoomRatio);
|
||||||
|
}
|
||||||
|
|
||||||
void ImageView::repositionZoomLabel()
|
void ImageView::repositionZoomLabel()
|
||||||
{
|
{
|
||||||
if (!m_zoomLabel) {
|
if (!m_zoomLabel) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user