PDA

View Full Version : GraphicsScene navigation widget



EricTheFruitbat
30th March 2007, 22:06
I was wondering if anyone here has implemented a custom GraphicsView with a navigation widget different from the ordinary scrollbars.

Specifically I was thinking about the navigation widget used in GoogleEarth. It has some really nice benefits.

Completely intuitive
Looks pretty
Easier to use on a tablet where scrollbars might be difficult to hit with a stylus.

I'll reverse-engineer one for my own purposes, if I must. I was just trying to save myself some work on that front by asking if anybody'd done anything similar already. I'm really attached to that last benefit.

wysota
1st April 2007, 10:09
Since noone else answered this question I decided it's time to do it :)

Based on the number of answers to this thread I think it is safe to assume such widget doesn't exist. Implementing it is not a problem, a completely different thing is how to use it. The way I see it is that it would have to be a separate widget placed on top of the view. It means you'd need to subclass the view and add the navigation widget and make sure it is always in a proper position regardless of the view's geometry.

aamer4yu
2nd April 2007, 05:04
I was just wondering if people have come across this (http://labs.trolltech.com/blogs/2007/03/09/qgraphicsview-widgets-on-the-canvas/) . Guess when it will be available :D

wysota
2nd April 2007, 10:00
It's already available, just probably hardly usable :) And completely useless in the case discussed in this thread.

EricTheFruitbat
2nd April 2007, 22:11
I've already figured out how to do a widget overlay on a scroll area, when I was working on a compass rose for geospatial imagery.

I was hoping, that failing to find a navigation prefabbed widget (which I expected), the discussion might morph into one about usability, my primary reason for even asking for the widget.

So far I've only seen scrollbars and the GoogleEarth widget for geospatial stuff. Perhaps some gamers know of additional interesting means of navigating a large QGraphicsScene?

Anyway, here was my solution for the compass rose. The trick was to have the rose paint on itself (with transparent background), and have the parent widget move it to an appropriate place. For QScrollArea this meant NOT painting on the viewport.



/**
* @short A widget that displays a compass rose in the top right corner.
*
*/
class CompassRose : public QWidget
{
public:
CompassRose( QWidget *parent );

protected:
void paintEvent( QPaintEvent *pe );

private:
qreal m_angle; //angle is degrees
};



and the really interesting part


void CompassRose::paintEvent( QPaintEvent *e )
{
QFont font = QFont("Sans Serif", 8);
font.setStyleStrategy(QFont::ForceOutline);

int fontheight = QFontMetrics(font).ascent();
int fontwidth = QFontMetrics(font).boundingRect("N").width();

QMatrix matrix;
matrix.translate( width()/2, height()/2 );

QPainter p(this);
p.setMatrix( matrix );
p.setRenderHint(QPainter::Antialiasing, true);

// draw the surrounding ellipse
p.setPen( QPen(Qt::black, 1) );
p.setBrush(QColor(192,192,192,192));

int offset = qMax( fontheight, fontwidth ) +5;
int size = qMin( width(), height() );
int radius = (size-1)/2 - offset;
p.drawEllipse( -radius, -radius, radius*2, radius*2 );

// draw the text
qreal midx = (fontwidth/2+radius+4)*cos(-m_angle*DTOR);
qreal midy = (fontheight/2+radius+4)*sin(-m_angle*DTOR);
QRectF rect( midx-fontwidth/2, midy-fontheight/2, fontwidth, fontheight );

QPainterPath path;
path.addText( QPointF(midx-fontwidth/2, midy+fontwidth/2), font, "N" );

p.setPen(QPen( QColor(192,192,192,192), 3 ));
p.setBrush( Qt::black );
p.drawPath( path );
p.setPen( Qt::NoPen );
p.drawPath( path );

// draw the compass
matrix.rotate( -m_angle );
p.setMatrix( matrix );

int outer = radius-5;
int inner = radius/4;

static const QPointF polyblack[3] = {
QPointF( outer, 0 ),
QPointF( inner*cos(45.*DTOR), -inner*sin(45.*DTOR) ),
QPointF( 0, 0 )
};
static const QPointF polywhite[3] = {
QPointF( outer, 0 ),
QPointF( inner*cos(45.*DTOR), inner*sin(45.*DTOR) ),
QPointF( 0, 0 )
};

p.setPen( Qt::NoPen );
for (int i=0; i<4; ++i) {
matrix.rotate( 90. );
p.setMatrix(matrix);

p.setBrush( Qt::black );
p.drawPolygon( polyblack, 3 );

p.setBrush( Qt::white );
p.drawPolygon( polywhite, 3 );
}
}


Usage is something like so...


ScrollArea::ScrollArea( QWidget *parent )
:QScrollArea( parent )
{
d = new ScrollAreaPrivate();
d->compass = new CompassRose( this );

setObjectName( "pss::ScrollArea" );
setAttribute( Qt::WA_StaticContents );

//setWidget(new myWidget(this));
viewport()->setFocusProxy( this );
viewport()->setFocusPolicy( Qt::StrongFocus );
//widget()->setAttribute( Qt::WA_OpaquePaintEvent );
//widget()->setAttribute( Qt::WA_NoSystemBackground );
//widget()->setMouseTracking( true );
setWidgetResizable( true );

}

void ScrollArea::resizeEvent( QResizeEvent *re )
{
qDebug() << "sa resize event" << re;
QScrollArea::resizeEvent(re);
//d->compass->resize(viewport()->size());
d->compass->move( viewport()->width() - d->compass->width(), 0 );
}