Qt:如何在笔记本电脑触控板上用两个手指手势在 QGraphicsScene 中实现 Panning/Zooming (win/mac)?
Qt: How to implement Panning/Zooming in QGraphicsScene with two finger gestures on laptop trackpad (win/mac)?
我有一个使用 QGraphicsScene 的 Qt 6.2 应用程序 (Windows/Mac),我想在我的笔记本电脑的触摸板上使用 2 个手指进行平移 - 就像许多其他应用程序一样。
缩放 in/out 工作正常,但使用 2 根手指平移总是会导致缩小。
我找到了一些问题和一些零碎的样本。但没有半途而废的例子:
- Finger Scrolling in QGraphicsView in QT?
- https://forum.qt.io/topic/119221/how-to-listen-to-qtouchevent-originating-from-a-precision-touch-pad
- https://doc.qt.io/qt-5/gestures-overview.html
正确的做法是什么?
到目前为止我尝试了什么(在 Windows 上):
1)
MyGraphicsView::MyGraphicsView(...) : QGraphicsView()
{
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
...
bool MyGraphicsView::viewportEvent ( QEvent * event )
{
switch (event->type())
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
// never called
}
MyDocWin::MyDocWin(...) : CMDIAppDocWin(),
{
setAttribute(Qt::WA_AcceptTouchEvents);
...
bool MyDocWin::event(QEvent *event)
{
switch (event->type())
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
// never called
}
...
std::vector<Qt::GestureType> sgGestureTypes = {Qt::TapGesture, Qt::TapAndHoldGesture,Qt::PanGesture ,Qt::PinchGesture ,Qt::SwipeGesture };
MyGraphicsView::MyGraphicsView(...) : QGraphicsView()
{
for(Qt::GestureType gesture : sgGestureTypes)
grabGesture(gesture);
...
bool MyGraphicsView::event(QEvent *event)
{
switch (event->type())
{
case QEvent::Gesture:
case QEvent::NativeGesture:
// never called
MyDocWin::MyDocWin(...) : CMDIAppDocWin(),
{
for (Qt::GestureType gesture : sgGestureTypes)
grabGesture(gesture);
...
bool MyDocWin::event(QEvent *event)
{
switch (event->type())
{
case QEvent::Gesture:
case QEvent::NativeGesture:
// never called
我终于完成了这项工作。我发现了什么:
平移手势(在 Qt 中)被转换为鼠标滚轮消息,它可以有一个 y 和一个 x 偏移量。这对我来说似乎很奇怪,因为没有带有水平滚轮的鼠标。
更令人困惑的是,根据 MS 定义,Pan 事件被转换为 WM_VSCROLL/WM_HSCROLL 事件 (https://docs.microsoft.com/en-us/windows/win32/wintouch/windows-touch-gestures-overview)
Qt 可以很好地处理其中的大部分(即平移),但不是全部:
- 似乎无法区分触控板上的手势事件和鼠标上的真实滚轮事件。我最初想始终使用鼠标滚轮进行缩放并使用触摸板平移手势。这种组合似乎是不可能的。我现在使用 Ctrl/Shift 进行鼠标滚轮缩放。这解决了问题
我不得不在 Mac 和 Windows 上以不同方式处理两根手指的缩放手势:
- 在 windows 上发送一个带有“(event->modifiers() & Qt::ControlModifier) == true”的车轮事件。就mac 不行。所以我写道:
void myGraphicsView::wheelEvent(QWheelEvent* event)
{
if(event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier))
myZoomFunction(event, 0);
else
QGraphicsView::wheelEvent(event);
}
- 在 MacOs 上,我们必须收听 QEvent::NativeGesture - 但在 Windows 上没有调用:
bool myGraphicsView::viewportEvent ( QEvent * event )
{
switch (event->type())
{
case QEvent::NativeGesture:
auto nge = dynamic_cast<QNativeGestureEvent*>(event);
if (nge)
{
if(nge->gestureType() == Qt::ZoomNativeGesture)
- 在 MacOs 时,滚动 up/down 在 angleDelta().x() 中发送,而不是在 angleDelta().y() 中发送。出于任何原因交换两个值。
我有一个使用 QGraphicsScene 的 Qt 6.2 应用程序 (Windows/Mac),我想在我的笔记本电脑的触摸板上使用 2 个手指进行平移 - 就像许多其他应用程序一样。
缩放 in/out 工作正常,但使用 2 根手指平移总是会导致缩小。
我找到了一些问题和一些零碎的样本。但没有半途而废的例子:
- Finger Scrolling in QGraphicsView in QT?
- https://forum.qt.io/topic/119221/how-to-listen-to-qtouchevent-originating-from-a-precision-touch-pad
- https://doc.qt.io/qt-5/gestures-overview.html
正确的做法是什么?
到目前为止我尝试了什么(在 Windows 上):
1)
MyGraphicsView::MyGraphicsView(...) : QGraphicsView()
{
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
...
bool MyGraphicsView::viewportEvent ( QEvent * event )
{
switch (event->type())
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
// never called
}
MyDocWin::MyDocWin(...) : CMDIAppDocWin(),
{
setAttribute(Qt::WA_AcceptTouchEvents);
...
bool MyDocWin::event(QEvent *event)
{
switch (event->type())
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
// never called
}
...
std::vector<Qt::GestureType> sgGestureTypes = {Qt::TapGesture, Qt::TapAndHoldGesture,Qt::PanGesture ,Qt::PinchGesture ,Qt::SwipeGesture };
MyGraphicsView::MyGraphicsView(...) : QGraphicsView()
{
for(Qt::GestureType gesture : sgGestureTypes)
grabGesture(gesture);
...
bool MyGraphicsView::event(QEvent *event)
{
switch (event->type())
{
case QEvent::Gesture:
case QEvent::NativeGesture:
// never called
MyDocWin::MyDocWin(...) : CMDIAppDocWin(),
{
for (Qt::GestureType gesture : sgGestureTypes)
grabGesture(gesture);
...
bool MyDocWin::event(QEvent *event)
{
switch (event->type())
{
case QEvent::Gesture:
case QEvent::NativeGesture:
// never called
我终于完成了这项工作。我发现了什么:
平移手势(在 Qt 中)被转换为鼠标滚轮消息,它可以有一个 y 和一个 x 偏移量。这对我来说似乎很奇怪,因为没有带有水平滚轮的鼠标。 更令人困惑的是,根据 MS 定义,Pan 事件被转换为 WM_VSCROLL/WM_HSCROLL 事件 (https://docs.microsoft.com/en-us/windows/win32/wintouch/windows-touch-gestures-overview)
Qt 可以很好地处理其中的大部分(即平移),但不是全部:
- 似乎无法区分触控板上的手势事件和鼠标上的真实滚轮事件。我最初想始终使用鼠标滚轮进行缩放并使用触摸板平移手势。这种组合似乎是不可能的。我现在使用 Ctrl/Shift 进行鼠标滚轮缩放。这解决了问题
我不得不在 Mac 和 Windows 上以不同方式处理两根手指的缩放手势:
- 在 windows 上发送一个带有“(event->modifiers() & Qt::ControlModifier) == true”的车轮事件。就mac 不行。所以我写道:
void myGraphicsView::wheelEvent(QWheelEvent* event) { if(event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier)) myZoomFunction(event, 0); else QGraphicsView::wheelEvent(event); }
- 在 MacOs 上,我们必须收听 QEvent::NativeGesture - 但在 Windows 上没有调用:
bool myGraphicsView::viewportEvent ( QEvent * event ) { switch (event->type()) { case QEvent::NativeGesture: auto nge = dynamic_cast<QNativeGestureEvent*>(event); if (nge) { if(nge->gestureType() == Qt::ZoomNativeGesture)
- 在 MacOs 时,滚动 up/down 在 angleDelta().x() 中发送,而不是在 angleDelta().y() 中发送。出于任何原因交换两个值。