PDA

View Full Version : QScrollView Overlay



EricTheFruitbat
26th December 2006, 22:26
I'm working on writing yet another geospatial imagery viewing application. Since I have to deal with large images, I've already created a subclass of QWidget specifically for rendering QImage's. I can readily put that into a QScrollArea without any problems.

I would like to add a compass-rose as an overlay on top of the image displayed within my scroll area. It would have to be rendered in a fixed position (say, in the upper right corner) as the user scrolls around the image. I've tried subclassing QScrollArea, and re-implementing the paintEvent but that paints in the background behind the loaded widget, and so gets obscured by the image.

I've googled extensively, but haven't been able to find anything very informative, much less any examples from which to bootstrap myself. Any help would be greatly appreciated.

wysota
26th December 2006, 22:31
Subclass the scroll area, and reimplement the paintEvent. Inside it first call the base class implementation and then draw the rose. This way you'll be painting over the image and not under it.

EricTheFruitbat
26th December 2006, 22:46
my current implementation of paintEvent is this
(it's not a real rose, I know, it's just a test)


void myScrollArea::paintEvent(QPaintEvent* event)
{
QScrollArea::paintEvent(event);
QPainter painter(viewport());

painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(Qt::black, 12, Qt::DashDotLine, Qt::RoundCap));
painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
painter.drawEllipse(80,80,200,240);

}

Instead of using 'viewport()' I also tried 'this' and 'widget()' as an object to paint on. I received the following error for both trials, and neither one painted anything at all.


QPainter::begin: Widget painting can only begin as a result of a paintEvent
Painter must be active to set rendering hints.

wysota
27th December 2006, 00:57
The painter has to be opened on the viewport. Do you get that error message even if you open the painter on the viewport? That shouldn't happen...

This code works fine for me:


#include <QApplication>
#include <QScrollArea>
#include <QPainter>


class MyScrollArea : public QScrollArea {
public:
MyScrollArea(QWidget *parent=0) : QScrollArea(parent){}
protected:
void paintEvent(QPaintEvent *e){
QScrollArea::paintEvent(e);
QPainter painter(viewport());
painter.setBrush(Qt::red);
painter.drawEllipse(20, 20, 40, 40);
}
};

int main(int argc, char **argv){
QApplication app(argc, argv);
MyScrollArea sa;
sa.show();
return app.exec();
}

EricTheFruitbat
27th December 2006, 04:57
Sorry about focusing on the error messages too much. Using viewport() works nicely, without error, but doesn't do what I want. So I experimented with 'widget()' and 'this' as attempts to get different behavior (neither worked).

So, continuing with viewport() since that's really where I want to paint...

The code you have will draw an ellipse nicely. However, if you put anything in the ScrollArea, it is rendered atop the custom painter, despite first calling QScrollArea:: paintEvent().


int main(int argc, char **argv){
QApplication app(argc, argv);
MyScrollArea sa;

QLabel *label = new QLabel;
QImage image("./test.png");
label->setPixmap( QPixmap::fromImage(image) );

sa.setWidget(label);
sa.show();
return app.exec();
}

If you choose an image that doesn't completely cover up the painter, then you can see what I'm talking about. The painter is in the background below the image, whereas I'm looking for things to be the other way around.

wysota
27th December 2006, 09:29
The easiest way would be to delegate the painting to the widget (the one with the image) itself. Another possibility is to make the rose a widget as well, just don't put it inside the viewport layout.