PDA

View Full Version : Painting: How to control what's in the foreground?



Mister_Crac
3rd May 2007, 13:24
I am writing a program that displays several QWidgets on the screen, within one parent QWidget. Then I have a QLabel that I draw with the drawText() method from QPainter. There are als Buttons to move around this Label on the screen (up, down, left, right).
Like so:



void MyClass::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.setBrush(Qt::red);
QPen myPen;
myPen.setWidth(1);
myPen.setColor(foreground);
painter.setPen(myPen);
painter.drawText(xpos, ypos, textDisplay->text());
}



Now, the QWidgets are always shown in the foreground, and the QLabel is shown in the background, behind the QWidgets. How can I change this order? I want the QLabel to be in the foreground.
Common sense tells you that whichever Object gets to be painted last should be in the foreground, since it is drawn "on top" of the other ones. How does one achieve this?

jpn
3rd May 2007, 13:29
One can change the stacking order of children with QWidget::raise() and QWidget::lower().

Mister_Crac
3rd May 2007, 14:14
Sounds good, but it does not seem to do the trick. I have added this method call to paintEvent():



textDisplay->raise();



But it still gets painted below the other widgets, not on top. See this Screenshot: http://img156.imageshack.us/img156/3302/qtpicturedf4.png

jpn
3rd May 2007, 14:20
Sounds good, but it does not seem to do the trick.
I have added this method call to paintEvent():



textDisplay->raise();


You don't want to do that during every single paint event. It would only cause unnecessary overhead.



But it still gets painted below the other widgets, not on top. See this Screenshot: http://img156.imageshack.us/img156/3302/qtpicturedf4.png
Children are always on top of their parent. From the attached screenshot it's impossible to see which widget is a children of which parent. So what are MyClass and textDisplay? You are raising textDisplay but MyClass actually draws the text?

Mister_Crac
3rd May 2007, 14:39
You don't want to do that during every single paint event. It would only cause unnecessary overhead.

Okay, but where do I call raise()? Within the constructor?



Children are always on top of their parent. From the attached screenshot it's impossible to see which widget is a children of which parent. So what are MyClass and textDisplay? You are raising textDisplay but MyClass actually draws the text?

The QLabel textDisplay is a member of MyClass. In the constructor of MyClass, I create the widgets that are shown as black in the screenshot (Bus, Prozessor etc.) and arrange them in a layout. So that makes them child widgets - right? The textDisplay is not integrated into the layout.
The one widget that is supposed to move around is textDisplay, so it is the only one that gets drawn in the paintEvent() method.

jpn
3rd May 2007, 15:08
Okay, but where do I call raise()? Within the constructor?
Yeah, it's enough change the stacking order once. Somewhere near creating the widgets is fine.



The QLabel textDisplay is a member of MyClass. In the constructor of MyClass, I create the widgets that are shown as black in the screenshot (Bus, Prozessor etc.) and arrange them in a layout. So that makes them child widgets - right? The textDisplay is not integrated into the layout.
The one widget that is supposed to move around is textDisplay, so it is the only one that gets drawn in the paintEvent() method.
So if MyClass is the parent, anything it draws (the red text) appears below it's children. Each widget is responsible for drawing itself when it receives a paint event. You don't paint other widgets, like children in the paintEvent() of the parent. Where is the textDisplay widget in the screenshot? Maybe you have to call QWidget::adjustSize() or something to make it adjust it's size to correspond it's contents (this would be done automatically if it was in a layout).

Mister_Crac
3rd May 2007, 16:58
Where is the textDisplay widget in the screenshot?

It's the big red letters :-)



Maybe you have to call QWidget::adjustSize() or something to make it adjust it's size to correspond it's contents (this would be done automatically if it was in a layout).

I somehow fear that moving around a widget that is part of a layout will break the layout, no? I will try it out now.

jpn
3rd May 2007, 17:05
It's the big red letters :-)
Are you sure? So where is the red text drawn in MyClass::paintEvent()?


I somehow fear that moving around a widget that is part of a layout will break the layout, no? I will try it out now.
No, you can't move a widget managed by a layout.

jpn
3rd May 2007, 17:10
Could you please do somewhere in MyClass after creating all the labels and other child widgets:


dumpObjectTree();

and paste the output?

Mister_Crac
3rd May 2007, 17:59
Okay I'm not sure if I came across clearly. I have made another screenshot and this time, I have changed all the German words to English for better understanding. Also, the first time around I did not show all of the windows that my application so far has. Here is the new and complete screenshot:

http://img502.imageshack.us/img502/4783/qtpicture2nf4.png

As you can see, the red text could really be anything. Anything you type in. It could also be another color if you want to. In any case, I definitely need it to be freely movable. Up, down, left, right, you name it. So it cannot be part of a layout, as it seems. All the other widgets - Memory, CPU, I/O Unit, Bus, Arrows - however can and in fact, are.

Now, the problem remains: How can I achieve it so that the QLabel gets drawn on top of the other widgets? Calling raise() did not lead to success so far.

Also,

Could you please do somewhere in MyClass after creating all the labels and other child widgets:


dumpObjectTree();

and paste the output?

Would the output of that command happen to be found in the directory which is named "debug"? Then I fear that my Qt library is maybe not compiled for debugging, because that directory is empty always.

jpn
3rd May 2007, 19:35
Would the output of that command happen to be found in the directory which is named "debug"? Then I fear that my Qt library is maybe not compiled for debugging, because that directory is empty always.
No, I was referring to the debug output. IDEs tend to show the debug output. If you're not using any IDE, on Windows you will have to add

CONFIG += console
in the .pro file, regenerate makefile and rebuild the application. An external console is launched together with the application from which you can see the debug output. Alternatively, you can use such utilities as DebugView (http://www.microsoft.com/technet/sysinternals/utilities/debugview.mspx) to monitor the debug output.

vermarajeev
4th May 2007, 07:04
I dont know whether I understood your problem correctly. When you move QLabel, do you want it to be seen at top of other widgets. i.e whenever QLabel has a mouse on it, QLabel should be seen at top of other widgets. If that is what you are looking for then have a look at Examples->QWidgets->ToolTips. Might help.

Thanks

Mister_Crac
4th May 2007, 17:46
in the .pro file, regenerate makefile and rebuild the application. An external console is launched together with the application from which you can see the debug output.

I have done this and indeed, I do get an additional black console window now, but no text ever appears inside of it. Even if I call dumpObjectTree(). Are you sure I do not need to re-compile Qt?

Mister_Crac
4th May 2007, 17:50
I dont know whether I understood your problem correctly. When you move QLabel, do you want it to be seen at top of other widgets.

I want this QLabel to be in front of the other QWidgets all of the time.


i.e whenever QLabel has a mouse on it, QLabel should be seen at top of other widgets. If that is what you are looking for then have a look at Examples->QWidgets->ToolTips. Might help.

I think my problem boils down to this: If you have two QWidgets that overlap, how do you control which one of the two is in the foreground? This seems to be complicated by the fact that the one QWidget (the QLabel which must be freely movable) is not part of a layout, while the other QWidgets (which are supposed to be visible, but "behind" the moving QLabel) are.

jpn
4th May 2007, 17:59
I have done this and indeed, I do get an additional black console window now, but no text ever appears inside of it. Even if I call dumpObjectTree(). Are you sure I do not need to re-compile Qt?
No, re-compiling Qt is not necessary. Sorry, I have no idea what's the problem with no text appearing, though. Did you clean and rebuild the whole project?


I think my problem boils down to this: If you have two QWidgets that overlap, how do you control which one of the two is in the foreground?
It's all about parenting widgets correctly. ;) The order of sibling child widgets can be changed with raise() and lower() as mentioned in the beginning of the thread.

Edit: This is why I asked for dumpObjectTree() output. It will show the actual hierarchy of the object tree.

Mister_Crac
4th May 2007, 18:50
No, re-compiling Qt is not necessary. Sorry, I have no idea what's the problem with no text appearing, though. Did you clean and rebuild the whole project?


Yes, I deleted the "release" directory and compiled it from scratch. I don't use a fancy IDE, just Vim 7.0 (gvim) as the editor and compiling at the console. Old school! :D
Maybe I could redirect the stderror output to a file?

EDIT:
I just realised that I made a mistake. For the QLabel, instead of doing this:

textDisplay = new QLabel("Enter Text here", this);
I had left out the "this", thus making the QLabel not a child Widget of the application window.
But still, even now that I have changed it, calling raise() seems to do nothing at all. Of course, there is always the possibility that I am making another stupid mistake... :(

Mister_Crac
8th May 2007, 14:00
Okay, so I finally managed to call dumpObjectTree() and get an output. Turns out that indeed my Qt was not compiled for debugging, but now it is. Here is what I get, I simplified it because the output was so long. Look at this screenshot to see how it looks now (http://img520.imageshack.us/img520/4341/qtpicture3yt0.png) - and still my QLabel is in the background. :-(



Rechner::
QWidget::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QGridLayout::
QLabel::
QTextDocument::
QTextDocumentLayout::
QTextImageHandler::
QTextFrame::
QTimer::
QTimer::
QTimer::
QTimer::
QTimer::