I've subclassed QGraphicsView for a custom canvas to be used in a CAD application. I've successfully reimplemented QGraphicsView::wheelEvent to check the keyboard modifiers for the control key and, if the control key is pressed, to zoom. I'm trying to implement a horizontal scroll when the user holds shift and uses the wheel.
The problem I'm having is that the horizontal scrolling also always scrolls up by 0.279. Not a huge problem, but hugely annoying and it points to something else being wrong.
So, here are the questions:
Thanks in advance. Code and sample output below
void myView::zoom(int delta)
{
double factor = pow(1.2, delta/abs(delta));
this->scale(factor, factor);
}
void myView::scrollHorizontal(int level)
{
QPointF center = mapToScene(viewport()->rect().center());
qDebug() << "center: " << center.x() << ", " << center.y();
centerOn(QPointF(center.x() - level, center.y()));
}
void myView::wheelEvent(QWheelEvent *event)
{
//qDebug() << "delta: " << event->delta();
if (event->modifiers() & Qt::ControlModifier)
{
this->zoom(event->delta());
}
else if (event->modifiers() & Qt::ShiftModifier)
{
this->scrollHorizontal(event->delta());
}
else
QGraphicsView::wheelEvent(event);
}
sample output from the qDebug() line in scrollHorizontal when at the left-edge of the scene:
center: 261.5 , 615.654
center: 261.5 , 615.375
center: 261.5 , 615.096
center: 261.5 , 614.817
center: 261.5 , 614.538
center: 261.5 , 614.259
center: 261.5 , 613.98
center: 261.5 , 613.701
center: 261.5 , 613.421
Horizontal scrolling can be achieved by clicking and dragging a horizontal scroll bar, swiping sideways on a desktop trackpad or trackpad mouse, pressing left and right arrow keys, or swiping sideways with one's finger on a touchscreen.
A horizontal scroll bar enables the user to scroll the content of a window to the left or right. A vertical scroll bar enables the user to scroll the content up or down.
Horizontal scrolling saves a lot of vertical screen space. Rather than displaying all the content at once on a very long page, horizontal layouts introduce users to smaller chunks of information. The layout is much more flexible. One can add content in both directions — vertical and horizontal.
Horizontal scroll is a navigation technique for exploring web content. Instead of moving through a website page vertically from top to bottom, horizontal scrolling websites take readers through a left-to-right experience—magically, text and visuals move sideways.
Your issue comes from the fact that mapToScene()
processes an integer point, not a floating point point. The rounding error is always pointed the same way for a particular viewport size, thus you always add some delta.
You want to be directly modifying the scroll bar's value
property or sending the event to the horizontal scroll bar. I've implemented the latter, it's simple enough.
On a Mac, you must absolutely disable the scrollbar inertia for your application. Otherwise as soon as you release the modifier and lift your finger off the trackpad/scroll wheel, vertical scrolling will continue due to inertia. This would make Mac users' experience suck and they would hate you for it :)
gview-scroll.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = gview-scroll
TEMPLATE = app
macx {
LIBS += -framework Foundation
OBJECTIVE_SOURCES += helper.m
}
SOURCES += main.cpp
helper.m
//helper.m
#include <Foundation/NSUserDefaults.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSString.h>
void disableMomentumScroll(void)
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"NO" forKey:@"AppleMomentumScrollSupported"];
[defaults registerDefaults:appDefaults];
}
main.cpp
//main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QtCore/qmath.h>
#include <QScrollBar>
#include <QWheelEvent>
#include <QDebug>
class View : public QGraphicsView {
public:
void zoom(int delta) {
double factor = qPow(1.2, delta/qAbs(delta));
scale(factor, factor);
}
void wheelEvent(QWheelEvent *event) {
if (event->modifiers() & Qt::ControlModifier) {
zoom(event->delta());
}
else if (event->modifiers() & Qt::ShiftModifier) {
horizontalScrollBar()->event(event);
}
else {
QGraphicsView::wheelEvent(event);
}
}
public:
explicit View(QWidget *parent=0) : QGraphicsView(parent) {}
explicit View(QGraphicsScene *scene, QWidget *parent=0) : QGraphicsView(scene, parent) {}
};
#ifndef Q_OS_MAC
void disableMomentumScroll() {}
#else
extern "C" { void disableMomentumScroll(); }
#endif
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
disableMomentumScroll();
QGraphicsScene s;
s.addEllipse(-50, -50, 100, 100, QPen(Qt::red), QBrush(Qt::gray));
View w(&s);
w.show();
return a.exec();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With