PDA

View Full Version : Inheritance and QpaintEvent



djoul
29th June 2006, 14:53
Hi, I'm a Qt beginner.
I've got problems dealing with inheritance and qwidget :
I've got a class that does all the painting stuff on a widget : class Current.
I've got a class Mother, and a class Son and a class Daugther that inherit from her.

In my class Current, I've got a static list of Mother elements(that can either be Son or Daughter) : static QList<Mother*> mother_list.
I do some : mother_list.append(new Son(attributes));

What I want is : for all the elements of my mother_list, I throw a method draw (virtual) so that the Son and Daughter can do some painting stuff themselves. So they have to have some link with the widget created in the Current Class.

The problem I have is that when I call "draw", the method is never called in the class Son or Daughter.
I think I've done big mistakes with passing the arguments, with the inheritance. Here is a part of the .h :


class Mother: public QWidget
{
public :
Mother(QWidget *parent, const Obj1&o1, const Obj2&ob2);
virtual ~Mother();
virtual void draw()=0;
......




class Son: public Mother
{


public :
Son(QWidget *parent, const Obj1&ob1, const Obj2&ob1, const Obj3&Ob3, const Obj4&Ob4);
~Son();
void draw();
...
protected :
void paintEvent(QPaintEvent *);




Daugher is the same as son.

So when in my current class I call mother_list.at(i)->draw();
Nothing is called.
Can you help me please !!!

munna
29th June 2006, 15:00
Just call mother_list.at(i)->repaint() which will automatically call the paintEvent().

djoul
29th June 2006, 16:11
I tried it, but I've got the same result : the paintEvent is not called :(
It even doesn't call my class Mother paintEvent if I implement him !!!

fullmetalcoder
29th June 2006, 16:13
try declaring the destructor, the paintEvent and the draw method as "virtual"...

djoul
29th June 2006, 16:17
You mean I call virtual even my Son and Daughter methods ? I thought it was just for the Mother class !

fullmetalcoder
29th June 2006, 16:20
You mean I call virtual even my Son and Daughter methods ? I thought it was just for the Mother class ! At this point thoughtq won't make your code work... ;) Try it and see...

djoul
29th June 2006, 16:24
It still doesn t work ...

fullmetalcoder
1st July 2006, 17:39
class Mother : public QWidget
{
Q_OBJECT

public:
Mother();
virtual ~Mother();

protected:
virtual paintEvent(QPaintEvent *e) {}
};

class Son : public Mother
{
Q_OBJECT

public:
Son();
virtual ~Son();

protected:
virtual paintEvent(QPaintEvent *e) { qDebug("Son : paintEvent"); }
}

// somewhere in the code :
Son *pSon = ...
pSon->update();


What does such a code outputs?

djoul
3rd July 2006, 09:37
In my code, I added the Q_OBJECT that I had forgotten, I tried what you wrote and this is weird, the Son's paintEvent method is never called !!!
I even tried adding a public method draw in my Son class,with just update() in its body.
And then trying son->draw() but nothing happens.
And, if I put just virtual to the Son and Mother paintEvent method I get the error :

V4 error LNK2001: symbole externe non rÚsolu "protected: virtual void __thiscall Mother::paintEvent(class QPaintEvent *)" (?paintEvent@Weather@@MAEXPAVQPaintEvent@@@Z)

I must add =0 to the virtual paintEvent in the Mother class,
or delete the virtual in virtual paintEvent in my Son class.

For me, the natural code would be in the Mother class : virtual void paintEvent(...)=0 and the destructor virtual.
And in My son class : void paintEvent(...){.........} with the destructor not virtual.
(But I almost tried all the possible configurations)

jacek
3rd July 2006, 16:40
And then trying son->draw() but nothing happens.
What should happen? How did you try to invoke it? How did you create that object?
Could you prepare minimal compilable example that reproduces the problem?

djoul
3rd July 2006, 16:56
What should happen? How did you try to invoke it? How did you create that object?
Could you prepare minimal compilable example that reproduces the problem?

In my Son paintEvent I create a file and write some stuff in it and I try to draw some text on my widget to be sure the function is called but the file is never created, so my paintEvent method is never called.
In anoter class I just do Son *son = new Son(...);
son->draw() and as I specified draw as public it should work.

I'll try to prepare a minimal example

gfunk
3rd July 2006, 20:47
Might doublecheck that your Son isVisible() or has updatesEnabled() ?

djoul
4th July 2006, 10:00
Might doublecheck that your Son isVisible() or has updatesEnabled() ?
Hehe, some news : updtatesEnabled do nothing but I tried some Son *son = new Son(...).
son->setVisible(true); and then son->update();
And now my paintEvent is called, but I ve new problems : My class Son is supposed to write on a widget but now (I've got a timer that calls update() every second) it creates a new widget each seconds and writes on it.
But that s a different problem, I think it comes from passing the original widget to the Son, I ll dig on it.
Thank you all for your help !

jacek
4th July 2006, 11:18
it creates a new widget each seconds and writes on it.
But that s a different problem, I think it comes from passing the original widget to the Son, I ll dig on it.
Why do you create new widgets if Son is a widget too? Wouldn't it be enough to redraw Son?

djoul
4th July 2006, 11:35
Why do you create new widgets if Son is a widget too? Wouldn't it be enough to redraw Son?

But I don t want to create new ones ! Qt does ...
The architecture is :
I've got a class Bck1 and Bck2. In both classes I do some drawing with QPaintEvent (the 2 classes are Widgets).
I ve got then the class Mother with his Son.
And I want the Son to do some drawings in bot he Bck1 and Bck2.
My problem is : Son is not a Widget but he must inherit from QWidget to know where he must paint ?





#include <QWidget>

class Bck1: public QWidget
{
Q_OBJECT

public :
Bck1(QWidget *parent = 0);
~Bck2();
...
protected :
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
...}

#include <QWidget>

class Bck2: public QWidget
{
Q_OBJECT

public :
Bck2(QWidget *parent = 0);
~Bck2();

protected :
void paintEvent(QPaintEvent *event);
}


#include <QWidget>


class Mother: public QWidget
{
Q_OBJECT

public :
Mother(QWidget *parent=0);
virtual ~Mother();
protected :
virtual void paintEvent(QPaintEvent *event)=0;


};

#include <QWidget>

class Son : public Mother
{

Q_OBJECT

public :
Son(.....);//do I need to put Son(QWidget *parent=0) ... ?????
~Son();

protected :
void paintEvent(QPaintEvent *event);
}

Does it seems ok ? I never know if I need to specify *parent or *parent=0, and if I need to put Qwidget *parent in the Son constructor ???

jacek
4th July 2006, 17:23
But I don t want to create new ones ! Qt does ...
Qt does only what you tell it to do.

Indeed, the problem is in constructor. If you create a widget without a parent, it will be created as a standalone window. So your constructor should be implemented like this:
Son::Son( QWidget *parent )
: Mother( parent )
{
...
}
And the Mother class must pass this parent to QWidget's constructor.


I never know if I need to specify *parent or *parent=0
That "= 0" part only indicates a default value for the parameter.

djoul
5th July 2006, 09:33
Qt does only what you tell it to do.

Indeed, the problem is in constructor. If you create a widget without a parent, it will be created as a standalone window. So your constructor should be implemented like this:
Son::Son( QWidget *parent )
: Mother( parent )
{
...
}
And the Mother class must pass this parent to QWidget's constructor.


That "= 0" part only indicates a default value for the parameter.

Ok now my paintEvent is called (the File is created).
But if try to do some Basics drawings nothing appears on the screen.
My Son is not a Widget, it just writes on the widget passed in the argument, so I don t need all the setVisible(true) or autofillBackgound stuff ...
But I m happy the paintEvent is now called, it smells the end of the problem.

jacek
5th July 2006, 13:51
But if try to do some Basics drawings nothing appears on the screen.
When do you draw on that widget? And how do you create QPainter?


My Son is not a Widget,
It is a widget, since it inherits from Mother which is derived from QWidget.

djoul
5th July 2006, 14:02
When do you draw on that widget? And how do you create QPainter?
In my Son paintEvent method. I create it y doing QPainter painter(this) or QPAinter * painter = new QPainter(this).
As my son inherit from Mother (that inherit from Qwidget) this is suppose to have a link with the widget I want to draw on ? I can t do painter(parent).



It is a widget, since it inherits from Mother which is derived from QWidget.
Ok, in my vision Son is an Object that is not a widget because it's not a "window", it s just a class that can draw on widgets (so it must inherit from QWidget indirectly with Mother).

That s really weird, in my Son paintEvent method I tried doing
painter.fillRect(2,2,width()-4, height()-4, QBrush(QColor(0,0,0)));
and in my Widget (Bck1) in top left corner a little rectangle, maybe 50*30 pixels has become black instead of red !!! and I never gave such dimensions for the widget

jacek
5th July 2006, 14:11
Ok, in my vision Son is an Object that is not a widget because it's not a "window"
If it's just "an object" then you shouldn't derive it from QWidget. Everything what inherits QWidget is a widget.

In Qt4 you can draw on widgets only in their paintEvent() method. This means that you have to invoke Son::draw() from your widget's paintEvent().


That s really weird [...] has become black instead of red !!! and I never gave such dimensions for the widget
No it's not, you just see the Son widget.

djoul
5th July 2006, 14:25
If it's just "an object" then you shouldn't derive it from QWidget. Everything what inherits QWidget is a widget.

In Qt4 you can draw on widgets only in their paintEvent() method. This means that you have to invoke Son::draw() from your widget's paintEvent().

Ok, so here what I don t understand :
In my Current class, where I do all the drawing in the Current::paintEvent.
I create a Son(which is not a Widget), and I call Son->draw().
I want this function for example to draw an ellipse on the Current (which is the widget).
So in Son::draw I just do update(), which calls the Son::paintEvent which will draw the Ellipse.
Then, in my Son::paintEvent what do I do ???? that s the point that I do not understand !!! I can t do QPainter painter(this)
son.cpp(106): error C2664: 'QPainter::QPainter(QPaintDevice *)'*: impossible de convertir le paramètre 1 de Son*const ' en 'QPaintDevice *'

That s why I was doing all the thing with passing the Widget to the Son so he knows where to draw !!!!!

jacek
5th July 2006, 14:31
Ok, so here what I don t understand :
In my Current class, where I do all the drawing in the Current::paintEvent.
I create a Son(which is not a Widget), and I call Son->draw().
So in this case you should have something like this:
class Son
{
public:
Son() { ... }
void draw( QWidget *widget ) const
{
QPainter painter( widget ); // <--
painter.drawEllipse( ... );
...
}
...
};

void Current::paintEvent( QPaintEvent * )
{
...
Son s;
s.draw( this );
...
}

djoul
5th July 2006, 14:56
Jacek, A statue of you should be built for the help you gave me, it WORKS.
THANK YOU,
YYYYYYYYYYYHHHHHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA