PDA

View Full Version : magnifying glass with qgraphicsview



pinkiP
30th July 2012, 15:52
Hello,

I like to implement a magnifying glass like on this web page: http://labs.qt.nokia.com/2009/10/07/magnifying-glass/. This zoom function should work on a qgraphicsview. I read many forums and wikis, but I don't know how to do it. Some people say: use the viewport of the qgraphicsview, others say don't use the paintevent() of the qgraphicsview. But nobody says how to do it.

What I've done so far: creating a class MagnifyingGlas and promoted the class to a qgraphicsview in my mainwindow ui. The qpointer was set on the viewport of the qgraphicsview. But nothing happens.



/*
magnifyingglas.h
*/
#ifndef MAGNIFYINGGLAS_H
#define MAGNIFYINGGLAS_H

#include <QWidget>
#include <QGraphicsView>
#include <QBasicTimer>
#include <QImage>
#include <QPixmap>
#include <QPoint>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QPainter>
#include <QPaintEvent>


#define HOLD_TIME 71

class MagnifyingGlas:public QGraphicsView
{
Q_OBJECT
public:
MagnifyingGlas( QWidget *parent = NULL);

void pan(const QPoint &delta);
void activateZoom();

protected:
void timerEvent(QTimerEvent *);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *);
void resizeEvent(QResizeEvent *);
void paintEvent(QPaintEvent *e);
void keyPressEvent(QKeyEvent *event);

private:
QGraphicsScene *scene;
QImage image;
QPixmap smallPixmap;
QPixmap largePixmap;
QPixmap zoomPixmap;
QPixmap maskPixmap;
bool pressed;
bool snapped;
bool zoomed;
QPoint offset;
QPoint pressPos;
QPoint dragPos;
QBasicTimer tapTimer;
};

#endif // MAGNIFYINGGLAS_H




/*
magnifyingglas.cpp
*/
#include "magnifyingglas.h"

#include <QGraphicsItem>

MagnifyingGlas::MagnifyingGlas(QWidget *parent): QGraphicsView(new QGraphicsScene(), parent)
{
pressed = false;
snapped = false;
zoomed = false;

image.load("/home/kuehnel/Development/Unbenannt_2.png");
largePixmap.load("/home/kuehnel/Development/Unbenannt_2.png");
smallPixmap = largePixmap.scaled(largePixmap.size()/2);
offset = QPoint(0,0);

scene = new QGraphicsScene;
this->setScene(scene);
scene->addPixmap(largePixmap);
}
void MagnifyingGlas::pan(const QPoint &delta)
{
offset += delta;
update();
}

void MagnifyingGlas::activateZoom()
{
zoomed = true;
tapTimer.stop();
update();

}

void MagnifyingGlas::timerEvent(QTimerEvent *)
{
if (!zoomed) activateZoom();
update();
}

void MagnifyingGlas::mousePressEvent(QMouseEvent *event)
{
if (event->buttons()!= Qt::LeftButton) return;

pressed = snapped = true;
pressPos = dragPos = event->pos();
tapTimer.start(HOLD_TIME, viewport());
}

void MagnifyingGlas::mouseMoveEvent(QMouseEvent *event)
{
if (!event->buttons()) return;
if (!zoomed)
{
if (!pressed || !snapped)
{
QPoint delta = event->pos() - pressPos;
pressPos = event->pos();
pan(delta);
return;
}
else
{
const int threshold = 10;
QPoint delta = event->pos() - pressPos;
if (snapped)
{
snapped &= delta.x() < threshold;
snapped &= delta.y() < threshold;
snapped &= delta.x() > -threshold;
snapped &= delta.y() >-threshold;
}
if (!snapped) tapTimer.stop();
}
}
else
{
dragPos = event->pos();
update();
}
}

void MagnifyingGlas::mouseReleaseEvent(QMouseEvent *)
{
zoomed = false;
update();
}

void MagnifyingGlas::resizeEvent(QResizeEvent *)
{
zoomed = false;
update();
}

void MagnifyingGlas::paintEvent(QPaintEvent *e)
{
QPainter p(viewport());
p.drawPixmap(offset,smallPixmap);
p.end();
if (zoomed)
{
int dim = qMin(width(), height());
int magnifierSize = dim * 5/6;
int radius = magnifierSize / 2;
int ring = radius - 15;
QSize box = QSize(magnifierSize, magnifierSize);

if(maskPixmap.size() != box)
{
maskPixmap = QPixmap(box);
maskPixmap.fill(Qt::transparent);

QRadialGradient g;
g.setCenter(radius, radius);
g.setFocalPoint(radius, radius);
g.setRadius(radius);
g.setColorAt(1.0, QColor(64, 64, 64, 0));
g.setColorAt(0.5, QColor(0, 0, 0, 255));

QPainter mask(&maskPixmap);
mask.setRenderHint(QPainter::Antialiasing);
mask.setCompositionMode(QPainter::CompositionMode_ Source);
mask.setBrush(g);
mask.setPen(Qt::NoPen);
mask.drawRect(maskPixmap.rect());
mask.setBrush(QColor(Qt::transparent));
mask.drawEllipse(g.center(), ring, ring);
mask.end();
}

QPoint center = dragPos - QPoint(0, radius);
center = center + QPoint(0, radius/2);
QPoint corner = center - QPoint(radius, radius);
QPoint xy = center * 2 - QPoint(radius, radius);


if (zoomPixmap.size() != box) zoomPixmap = QPixmap(box);

if (true)
{
zoomPixmap.fill(Qt::lightGray);
QPainter p(&zoomPixmap);
p.translate(-xy);
p.drawPixmap(offset * 2, largePixmap);
p.end();
}

QPainterPath clipPath;
clipPath.addEllipse(center, ring, ring);

QPainter p(viewport());
p.setRenderHint(QPainter::Antialiasing);
p.setClipPath(clipPath);
p.drawPixmap(corner, zoomPixmap);
p.setClipping(false);
p.drawPixmap(corner, maskPixmap);
p.setPen(Qt::gray);
p.drawPath(clipPath);
update();
}
}

void MagnifyingGlas::keyPressEvent(QKeyEvent *event)
{
if (!zoomed)
{
if (event->key() == Qt::Key_Left) offset += QPoint(20 , 0);
if (event->key() == Qt::Key_Right) offset += QPoint(-20, 0);
if (event->key() == Qt::Key_Up) offset += QPoint(0 , 20);
if (event->key() == Qt::Key_Down) offset += QPoint(0 , -20);
if (event->key() == Qt::Key_Z || event->key() == Qt::Key_Select)
{
dragPos = QPoint(width()/2, height()/2);
activateZoom();
}
update();
}
else
{
if (event->key() == Qt::Key_Z || event->key() == Qt::Key_Select)
{
zoomed = false;
update();
}
QPoint delta(0,0);
if (event->key() == Qt::Key_Left) delta += QPoint(-15, 0);
if (event->key() == Qt::Key_Right) delta += QPoint(15 , 0);
if (event->key() == Qt::Key_Up) delta += QPoint(0 , -15);
if (event->key() == Qt::Key_Down) delta += QPoint(0 , 15);
if (delta != QPoint(0, 0))
{
dragPos += delta;
update();
}
}
}

Ideas are welcome.

Greats.

mcarter
15th November 2012, 16:47
Not sure if you figured this out since it has been a few months, but in case others are looking for an answer, you need to change a few things:
- use 'this' instead of viewport for timer start: tapTimer.start(HOLD_TIME, this)
- change all the update() calls to viewport()->update()
- remove update from paintEvent

also, you should consider changing hold time back to 701 since 71 msec is somewhat quick