PDA

View Full Version : Qt Parent <-> Child Relation When Painting



axed
19th April 2012, 23:33
Hello everybody!

I'm trying to use Qt together with Ogre. Everything worked so far under Linux, but as i recently had to change to my windows machine i encountered this strange Problem:
All children of my Ogre widget are just plain white.

7608

It makes sense as i had to kill the Ogre widget's PaintEngine with:


QPaintEngine *editor_engine:: paintEngine() const
{
return 0;
}

to enable Ogre beeing rendered as "the widget's background".

As i already said, the exactly same code works under Linux without any troubles.

Now my question is, how can i give all the child-widgets a own paintEngine - or is there a better way to bring them back to life on windows ? :3

wysota
19th April 2012, 23:48
We don't know what you did exactly so it's not possible to answer your question in any viable way.

axed
20th April 2012, 00:05
#include <QtGui/QApplication>
#include <QPaintEngine>
#include <QWidget>
#include <QPushButton>

class myclass : public QWidget
{
public:
myclass()
{
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_PaintOnScreen);
setWindowFlags( this->windowFlags() | Qt::MSWindowsOwnDC );
setFocusPolicy(Qt::StrongFocus);
}

QPaintEngine * paintEngine() const
{
return 0;
}
};


int main(int argc, char *argv[])
{


QApplication a(argc, argv);

myclass c;
QPushButton* b = new QPushButton( "hi" );
b->setParent( &c );
b->move( 10,10 );
c.show();
c.resize(100,100);

return a.exec();
}



that's what i did ..
if you want to have the full 2000 lines of the header and source files, well no problem, just tell me if the above isn't enough.
yet the question is how can i - in this example - reimplement the QPushButton to have it's own paint-routine so it becomes visible ?

wysota
20th April 2012, 00:49
Does it change anything if you set the Qt::AA_NativeWindows attribute on the application object?

axed
20th April 2012, 02:50
Nope,
i tried it on my application and on the example code above

i just discovered that it is working with an old testing project i created

it contains the following code:


#include <QApplication>
#include <QWidget>
#include <Ogre.h>
#include <QPushButton>

int main(int argc, char *argv[])
{
Ogre::Root* ogre_root;
Ogre::RenderWindow* ogre_render_window;
Ogre::SceneManager* ogre_scene_manager;

Ogre::Camera* ogre_haupt_kamera;
Ogre::Viewport* ogre_viewport;

QApplication app(argc,argv);

QWidget* widget = new QWidget();
widget->setAttribute(Qt::WA_NoSystemBackground);
widget->setAttribute(Qt::WA_PaintOnScreen);
widget->setWindowFlags( widget->windowFlags() | Qt::MSWindowsOwnDC );
widget->setFocusPolicy(Qt::StrongFocus);

ogre_root = new Ogre::Root();

ogre_root->addResourceLocation( "resources", "FileSystem", "General" );

Ogre::ResourceGroupManager::getSingleton().initial iseAllResourceGroups();

ogre_root->loadPlugin( "ogre_plugins/RenderSystem_GL" );
ogre_root->loadPlugin( "ogre_plugins/Plugin_OctreeSceneManager" );

Ogre::RenderSystem* rs = ogre_root->getRenderSystemByName("OpenGL Rendering Subsystem");
if(!(rs->getName() == "OpenGL Rendering Subsystem"))
{
return false; //No RenderSystem found
}
// configure our RenderSystem
rs->setConfigOption("Full Screen", "No");
rs->setConfigOption("VSync", "No");
rs->setConfigOption("Video Mode", "800 x 600 @ 32-bit");

ogre_root->setRenderSystem(rs);

ogre_render_window = ogre_root->initialise( false, "my 3D");

Ogre::NameValuePairList params;
params["useNVPerfHUD"] = "true";

//The external windows handle parameters are platform-specific
Ogre::String externalWindowHandleParams;

#if defined(Q_WS_WIN)
//positive integer for W32 (HWND handle) - According to Ogre Docs
externalWindowHandleParams = Ogre::StringConverter::toString((unsigned long)(widget->winId()));
#endif

#if defined(Q_WS_X11)
//poslong:posint:poslong:poslong (display*:screen:windowHandle:XVisualInfo*) for GLX - According to Ogre Docs
QX11Info info = x11Info();
externalWindowHandleParams = Ogre::StringConverter::toString((unsigned long)(info.display()));
externalWindowHandleParams += ":";
externalWindowHandleParams += Ogre::StringConverter::toString((unsigned int)(info.screen()));
externalWindowHandleParams += ":";
externalWindowHandleParams += Ogre::StringConverter::toString((unsigned long)(widget->winId()));
#endif

//Add the external window handle parameters to the existing params set.
#if defined(Q_WS_WIN)
params["externalWindowHandle"] = externalWindowHandleParams;
params["parentWindowHandle"] = externalWindowHandleParams;
#endif

#if defined(Q_WS_X11)
params["parentWindowHandle"] = externalWindowHandleParams;
#endif

ogre_render_window = ogre_root->createRenderWindow("OgreWindow", 600, 400, false, &params);
ogre_render_window->setActive(true);
ogre_render_window->setVisible(true);

ogre_scene_manager = ogre_root->createSceneManager( "OctreeSceneManager" );

ogre_haupt_kamera = ogre_scene_manager->createCamera( "haupt_kamera" );
ogre_haupt_kamera->setPosition( Ogre::Vector3(100,100,100) );
ogre_haupt_kamera->lookAt(Ogre::Vector3(0, 0, 0));

ogre_haupt_kamera->setNearClipDistance(0.1);

if (ogre_root->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_INFINITE_FAR_PLANE))
{
ogre_haupt_kamera->setFarClipDistance(0); // wird eingeschalten wenn die grafikkarte das unterstützt
}

ogre_viewport = ogre_render_window->addViewport( ogre_haupt_kamera );
ogre_viewport->setBackgroundColour( Ogre::ColourValue( 0.9, 0.9, 0.9 ) );

ogre_haupt_kamera->setAspectRatio( Ogre::Real( ogre_viewport->getActualWidth() ) /
Ogre::Real( ogre_viewport->getActualHeight() ) );

ogre_scene_manager->setAmbientLight( Ogre::ColourValue(0.9f, 0.9f, 0.9f) );
ogre_scene_manager->setShadowTechnique( Ogre::SHADOWTYPE_STENCIL_ADDITIVE );
ogre_scene_manager->setShadowColour(Ogre::ColourValue(0.5, 0.5, 0.5));

// ogre_scene_manager->setSkyBox( true, "Himmel", 5000 );


widget->show();
widget->resize(400,300);

QPushButton* b = new QPushButton( "hi" );
b->setParent( widget );
b->move( 10,10 );
b->show();

return app.exec();
}



am i blind that i can't find the difference?
or is it just that the test-project never redraws the ogre-stuff
*investigating*

Added after 54 minutes:

ok ok, now i tried to remove the termination of the paintengine



//QPaintEngine *editor_engine:: paintEngine() const
//{
// return 0;
//}


Now all the child-qwidgets are visible but the ogre content is not.
As far as i can remember this was the reason why i killed the paintengine of the widget.

What brings us back to the topic:
How can i paint children, if the parent qwidget doesn't have a paintEngine ?

Added after 50 minutes:

And of course the app's output gets spammed with


QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
QPainter::setBrush: Painter not active
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::drawRects: Painter not active
QPainter::setBrush: Painter not active
QPainter::drawRects: Painter not active

wysota
20th April 2012, 09:57
The point is that Qt::WA_PaintOnScreen only works on X11. Windows will ignore it thus you get a different behaviour on the two platforms. It would be easiest to overcome this problem if you made OGRE paint not on the widget but on an image (e.g. through a pixel buffer or something similar) and then render that image to the widget using regular Qt means.

axed
20th April 2012, 11:52
Thank you for still being patient with me! :)

Just to remind everybody at this point: I'm using atm Windows7.

When i comment out the setAttribute(Qt::WA_PaintOnScreen); line
All child-widgets become painted properly - But Ogre does not render at all.
If i uncomment the line again, all the children are messed up again, but ogre renders just fine.

Nice to see it only affects X11 ...

Actually the ogre documentations, examples and their wiki are very ... well .... "imprecise" or "incomplete" and far not as extensive as Qt's docu.
So it seems that people render ogre's content into the widget by mixing the winid, doing that instead with another buffer looks to me -correct me if i'm wrong, as i'm taking the ogre-doc's quality into account- , like a huge thing to do.
Also, i would have to restructure some huge parts of my project - which where supposed to be platform-independent.
It doesn't look much like an option to me, and it doesn't even smell like the "Qt's"-way.
Isn't there an equivalent of Qt::WA_PaintOnScreen for windows?
I just can't find one in the Qt-docs.

Added after 5 minutes:

just if you're not too familiar with integrating ogre into qt:
https://ogreaddons.svn.sourceforge.net/svnroot/ogreaddons/trunk/QtOgreFramework/QtOgre/source/OgreWidget.cpp

wysota
20th April 2012, 11:59
doing that instead with another buffer looks to me -correct me if i'm wrong, as i'm taking the ogre-doc's quality into account- , like a huge thing to do.
I don't know. I guess using an OpenGL backend would be much simpler than DirectX one, maybe you should look into that?


Also, i would have to restructure some huge parts of my project - which where supposed to be platform-independent.
I don't think so. You'd only have to change the paint event and add a dedicated method for rendering into the pixmap. The rest shouldn't need to be changed.


Isn't there an equivalent of Qt::WA_PaintOnScreen for windows?
If there was, PaintOnScreen would simply be made work on Windows :)

axed
20th April 2012, 16:30
As i switched from linux, I'm still using OpenGL // as the rendersystem for ogre - there is no directx involved at all.


Ogre::RenderSystem* rs = ogre_root->getRenderSystemByName("OpenGL Rendering Subsystem");

if(!(rs->getName() == "OpenGL Rendering Subsystem"))

{

return false; //No RenderSystem found

}

// configure our RenderSystem

rs->setConfigOption("Full Screen", "No");

rs->setConfigOption("VSync", "No");

rs->setConfigOption("Video Mode", "800 x 600 @ 32-bit");



ogre_root->setRenderSystem(rs);

So my problem is, that i have no idea about how i could fetch the ogre-content without embedding it into an widget. And all Ogre+Qt combinations i've seen so far are doing it exactly this way.



Isn't there an equivalent of Qt::WA_PaintOnScreen for windows?
If there was, PaintOnScreen would simply be made work on Windows
true :3

the only thing that i can imagine atm is to create a hidden widget, where the ogre content gets rendered and i call in my paint events the QWidget::render(...) on that seperate widget.
But somehow i fell silly as other guys - like in the link i posted above, can archive that stuff without bitchin' around in all those indirections.

wysota
20th April 2012, 17:08
You should look into something OGRE calls a "hardware buffer". You should be able to force OGRE to render into a pixel buffer (e.g. through QGLPixelBuffer) and then it should be easy to extract its contents and use it in Qt. Unfortunately I'm not an expert on neither OpenGL nor OGRE so I can't help you much with it.