PDA

View Full Version : [Qt 3.3.4] How do I repaint anything using QCanvas or QPainter?



EnQ
20th March 2006, 14:48
I can paint using QCanvas or QPainter with no problems but when the Widget gets resized my overloaded drawContents method doesn't work the way I want it to:

Using QPainter it only paints to the difference area of the picture and messes everything up. I have to change windows/cover the widget by something else to get it repainted correctly. I already tried setWindow, setViewport, drawArea, update, setAllChanged and setClipping but nothing helps. I also tried to create a workaround by hiding and then showing the widget again. Unfortunately I was unable to get rid of the infinite loop I created by that.

Using QCanvas it repaints everything correctly - but I didn't find any method that clears all QCanvasItems linked to it, so it paints more and more and more each time the method gets called.

The goal is to draw a chart. I am not allowed to use any external program, KDE classes, Qt>3.3.4 or similar, so I am stuck with QCanvas and QPainter. The chart should be able to be completely repainted (scale!) if the size gets changed, so I can't use QCanvas without a method to get rid of everything. I also tried to create a new instance of QCanvas and link it to QCanvasView but unfortunately this also creates an infinite loop.

Trolltech's examples and documentation could not help me with that problem. Unfortunately it has to be solved till tomorrow, so it's quite urgent. Please tell me what I am doing wrong - I would be just fine if I could either clear QCanvas' drawing stack, reinstantiate it or being able to paint to the whole space using QPainter.

Thanks for any comments on this!

audiochart.h:


#ifndef INCLUDED_AUDIOCHART_H
#define INCLUDED_AUDIOCHART_H

#include <qcanvas.h>

class AudioChart : protected QCanvasView {
Q_OBJECT

public:
AudioChart( QWidget *parent, const char *name );
void drawContents ( QPainter * p, int cx, int cy, int cw, int ch );
private:
QCanvas* myCanvas;
int border;
};

#endif


audiochart.cpp


#include "audiochart.h"
#include <qpainter.h>
#include "guicommonhelper.h"
#include <iostream>

AudioChart::AudioChart( QWidget *parent=0, const char *name=0 ) : QCanvasView::QCanvasView( parent, name ) {
//QLabel* tmp = new QLabel( "implement me", parent );

this->myCanvas = new QCanvas( this, "" );
this->setCanvas( this->myCanvas );
this->myCanvas->setBackgroundColor( QColor( 255, 255, 255 ) );

this->border = 10;
this->setVScrollBarMode( QScrollView::AlwaysOff );
this->setHScrollBarMode( QScrollView::AlwaysOff );

//this->myCanvas->setDoubleBuffering( false );
}

void AudioChart::drawContents( QPainter * p, int cx, int cy, int cw, int ch ) {
this->myCanvas->resize(this->visibleWidth(), this->visibleHeight());

QPen pen = QPen( white, 0 );
QBrush brush = QBrush( white );

p->setClipping( false );
p->setPen( pen );
p->fillRect( 0, 0, this->myCanvas->width(), this->myCanvas->height(), brush );

pen = QPen( black, 1 );
QFont font = QFont( "Helvetica [Cronyx]", 8 );
QFontMetrics* fm = new QFontMetrics( font );

char tmpString[255];

p->setPen( pen );
p->drawLine( 20, 50, 50, 20 );
p->setFont( font );

int w, h, x, y;

int max = 10;
int offsetXAxis = 10;
int totalWidth = this->myCanvas->width() - 2*this->border - 10 - offsetXAxis;
int totalHeight = this->myCanvas->height() - 2*this->border;

std::cout<<"w "<<totalWidth<<" h "<<totalHeight<<std::endl;

std::cout<<"-"<<std::endl;
for (int i = 0; i <= max; i++) {
QString string = QString(intToChar(tmpString, i*3823/max));
w = fm->width(string);
h = fm->height();

x = totalWidth*i/max + this->border + offsetXAxis;
y = totalHeight + this->border;

std::cout<<i<<": x "<<x<<" y "<<y<<std::endl;

p->drawText( x, y, string );
//p->drawRect( x, y-h, w, h );
p->drawLine( x+w/2-1, y-h, x+w/2-1, y-h-2 );
}
std::cout<<"-"<<std::endl;

p->flush();
this->myCanvas->setAllChanged();
this->update();
}

yogeshm02
20th March 2006, 15:39
I think you should use a normal widget for drawing.

BTW where are the canvas items you needed to be deleted?

high_flyer
20th March 2006, 15:41
Using QPainter it only paints to the difference area of the picture and messes everything up.
This can be contolled with the widget flags.
Try playing with Qt::WStaticContents and Qt::WNoAutoErase and see if it helps.

EnQ
20th March 2006, 16:10
Thanks for the hint, unfortunately it still doesn't work.

WStaticContents seems to be exactly what I want to avoid while WNoAutoErase sounds like a solution. But it still looks the same:

The original painter output:

http://www.energiequant.de/images/qpainter_1_1.png

Window shrinked:

http://www.energiequant.de/images/qpainter_1_2.png

Window enlarged again:

http://www.energiequant.de/images/qpainter_1_3.png

Window repainted due to putting another window in front of it:

http://www.energiequant.de/images/qpainter_1_4.png


Do you have any other ideas?

EnQ
20th March 2006, 17:26
Okay, just wanted to let you know I am using a very dirty workaround for now as time is slowly running out.

As I thought it is possible to call hide() and show() on the widget to get it repainted (repaint() didn't work for me neither...). Since I can't call it from drawContents I decided to write a small event handler for the resized() signal emitted by QCanvas. Unfortunately this is only half the way: It works great but only when enlarging the widget.

I couldn't find any better way to repaint it on being shrinked but by creating a QTimer that calls an event handler to check for decrease in the main widgets size and then calls hide() and show() on all widgets that need it.

As I said that's veeeery dirty but at least it works.

jacek
20th March 2006, 18:03
What do you need QCanvas for? Where are the QCanvasItems?

EnQ
20th March 2006, 19:51
As I said I cannot use QCanvasItems since I draw dynamically changing content and don't know how to clear a QCanvas from all its items.

jacek
20th March 2006, 20:03
As I said I cannot use QCanvasItems since I draw dynamically changing content and don't know how to clear a QCanvas from all its items.
So why do you use QCanvas and QCanvasView? Wouldn't it be easier to use plain QWidget?