Why does Irrlicht window turn black when opening QMessageBox

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Donald Duck
Posts: 34
Joined: Sat Jan 21, 2017 6:51 pm
Location: Duckburg
Contact:

Why does Irrlicht window turn black when opening QMessageBox

Post by Donald Duck »

I'm using Irrlicht in a Qt context. To do this, I have an IrrlichtWidget class which shows an Irrlicht device in a QWidget. Here is the relevant part of that class:

Code: Select all

class IrrlichtWidget : public QWidget{
Q_OBJECT
public:
    IrrlichtWidget(){
        irr::SIrrlichtCreationParameters params;
        params.DriverType = irr::video::EDT_OPENGL;
        params.WindowId = (void*)winId();
        m_device = irr::createDeviceEx(params);
 
        setAttribute(Qt::WA_OpaquePaintEvent);
 
        m_timer = new QTimer;
        m_timer->setInterval(0);
        QObject::connect(m_timer, &QTimer::timeout, [this](){
            m_device->getVideoDriver()->beginScene(true, true, irr::video::SColor(255, 255, 255, 255));
            m_device->getSceneManager()->drawAll();
            m_device->getVideoDriver()->endScene();
            m_device->run();
        });
        m_timer->start();
    }
private:
    irr::IrrlichtDevice *m_device;
    QTimer *m_timer;
}
This works just fine until I use a QMessageBox. When I was programming with this class and wanted to use a QMessageBox, I noticed that whenever the message box opened, the Irrlicht widget turned black. To try to find out what was going on, I inserted a QMessageBox in the Irrlicht main loop so that it looked like this:

Code: Select all

QObject::connect(m_timer, &QTimer::timeout, [this](){
    m_device->getVideoDriver()->beginScene(true, true, irr::video::SColor(255, 255, 255, 255));
    m_device->getSceneManager()->drawAll();
    m_device->getVideoDriver()->endScene();
    m_device->run();
    QMessageBox::information(this, "Foo", "Bar");
});
When I did this, the background was black:

Image

To compare, here is exactly the same program with the only difference that it doesn't have a QMessageBox in it:

Image

I tried putting the QMessageBox everywhere in Irrlicht's main loop, at the beginning, at the end, in the middle, and it always does the same thing. It does this for every kind of Qt dialog boxes: QMessageBox, QFileDialog, etc.

I also tried removing the setAttribute(Qt::WA_OpaquePaintEvent) line in the constructor, and then the background was beige instead of black. Not the same color, but still the same problem.

It seems like the QMessageBox is somehow erasing the content of the Irrlicht widget. Why is it doing this? How can I fix it?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Why does Irrlicht window turn black when opening QMessag

Post by CuteAlien »

Just guessing. I suspect it might be related to the problem that modal dialogs have their own own message-loop. Which might clear the drawing but your wrapper to update it is no longer called.
You get similar problems when you move an Irrlicht window in "windowed" mode by draggin the title-bar or resizing it (that was once discussed here: http://irrlicht.sourceforge.net/forum// ... 123#226123). So you could try doing that to see if it behaves similar in those situations (then you know at least where it's coming from).
But might also have other reasons (not sure why it clears it really - should just be stuck to last render...).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
MartinVee
Posts: 139
Joined: Tue Aug 02, 2016 3:38 pm
Location: Québec, Canada

Re: Why does Irrlicht window turn black when opening QMessag

Post by MartinVee »

Just a quick thought...

I'm assuming that

Code: Select all

QMessageBox::information(this, "Foo", "Bar");
is a blocking call? So Irrlicht just stops being called when there's a message box, right?

So maybe it's just that Qt invalidates your control, and since you stop drawing, it's showing as a black window?
Donald Duck
Posts: 34
Joined: Sat Jan 21, 2017 6:51 pm
Location: Duckburg
Contact:

Re: Why does Irrlicht window turn black when opening QMessag

Post by Donald Duck »

I've written my own version of QMessageBox::information that works with Irrlicht:

Code: Select all

#include <QMessageBox>
#include <functional>
 
void showMessageBox(std::function<void(QMessageBox::StandardButton)> lambda, QWidget *parent, const QString &title, const QString &text, QMessageBox::Icon icon = QMessageBox::Information, QFlags<QMessageBox::StandardButton> buttons = QMessageBox::Ok){
    QMessageBox *messageBox = new QMessageBox(icon, title, text, buttons, parent);
    messageBox->open(NULL, NULL);
    QObject::connect(messageBox, &QMessageBox::finished, [messageBox, lambda](){
        if(messageBox->clickedButton() == messageBox->button(QMessageBox::Ok)){
            lambda(QMessageBox::Ok);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Open)){
            lambda(QMessageBox::Open);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Save)){
            lambda(QMessageBox::Save);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Cancel)){
            lambda(QMessageBox::Cancel);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Close)){
            lambda(QMessageBox::Close);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Discard)){
            lambda(QMessageBox::Discard);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Apply)){
            lambda(QMessageBox::Apply);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Reset)){
            lambda(QMessageBox::Reset);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::RestoreDefaults)){
            lambda(QMessageBox::RestoreDefaults);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Help)){
            lambda(QMessageBox::Help);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::SaveAll)){
            lambda(QMessageBox::SaveAll);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Yes)){
            lambda(QMessageBox::Yes);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::YesToAll)){
            lambda(QMessageBox::YesToAll);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::No)){
            lambda(QMessageBox::No);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::NoToAll)){
            lambda(QMessageBox::NoToAll);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Abort)){
            lambda(QMessageBox::Abort);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Retry)){
            lambda(QMessageBox::Retry);
        }
        else if(messageBox->clickedButton() == messageBox->button(QMessageBox::Ignore)){
            lambda(QMessageBox::Ignore);
        }
        else{
            lambda(QMessageBox::NoButton);
        }
    });
}
How to use it:
  • -The first parameter is a lambda which is executed when the dialog box gets closed. It takes one parameter, the button on which the user clicked.
    -The second parameter is the parent window, it works like the first parameter of QMessageBox::information.
    -The third parameter is the title of the window.
    -The fourth parameter is the message.
    -The fifth parameter is the icon of the message box. Possible values: QMessageBox::NoIcon, QMessageBox::Question, QMessageBox::Information, QMessageBox::Warning, QMessageBox::Critical.
    -The sixth parameter is the buttons of the dialog box, it works like the fourth parameter of QMessageBox::information.
Example:

Code: Select all

showMessageBox([](QMessageBox::StandardButton result){
    if(result == QMessageBox::Yes){
        showMessageBox([](QMessageBox::StandardButton){}, myWidget, "Hello", "Hello world!");
    }
}, myWidget, "Title", "Do you want to open a new dialog box?", QMessageBox::Question, QMessageBox::Yes | QMessageBox::No);
The above code asks the user if he wants to open a new dialog box. If the user clicks on Yes, it opens a dialog box saying "Hello World!", otherwise, nothing happens. myWidget is the program's main window.
Post Reply