QMessageBox on Linux fails to gain focus when shown for a second+ time on closeEvent
-
There are several topics that are duplicates to this forum thread:
"qtforum":http://www.qtforum.org/article/27890/qmessagebox-not-obtaining-the-keyboard-focus.html?905e83b1, "qtcentre-0":http://www.qtcentre.org/threads/29796-QMessageBox-Key-focus, "qtcentre-1":http://www.qtcentre.org/threads/24326-QMessageBox-with-no-focus, "qtcentre-2":http://www.qtcentre.org/threads/17068-QMessageBox-and-Focus, "qtcentre-3":http://www.qtcentre.org/threads/41412-QMessageBox-on-Linux-fails-to-gain-focus?p=189659#post189659 but this one differs in one aspect. Here's the problem:- You have a simple widget containing a push button.
- Closing the widget and pushing the button causes a QMessageBox to appear having OK and Cancel buttons.
- Run the widget and immediately after that close it. The QMessageBox is displayed and it HAS focus. Click OK to close the application or Cancel to proceed running the application. Hit Cancel.
- Now try to close the widget again. The message box appears but this time it HAS NO focus.
When the user tries to quit the application the QMessageBox is shown and HAS focus only the first time it is shown. If the user hits the Cancel button and tries to close the application again, the QMessageBox HAS NO focus the next time it is shown.
And the difference:
Note that the QMessageBox that is displayed inactive is the one shown in an overriden closeEvent(QCloseEvent*) member function. The message box displayed this way is active only the first time the widget is closed. The message box that is shown when the button is clicked is always active e.g. always has focus. This problem is reproduced only on Linux environment. Since it is not reproduced on Windows is it a Qt framework's bug? What is so special about this closeEvent that when it is fired the shown QMessageBox is inactive and has no focus on Linux?
Probable solution:
Instead of using the static member functions for creating a warning, question or information message boxes, a good beginning to the solution is to create a QMessageBox object, make some adjustments to it, and then display it. Currently nothing has helped the QMessageBox to gain focus, none of the following: 1) Try not to set parent to the QMessageBox being displayed. 2) Use setFocus. 3) Use setWindowState( Qt::WindowActive ). Some form members say that setting the window state to Qt::WindowFullScreen solves the problem. Doing this way the message box neither becomes enabled nor it is displayed correctly. 4) Use grabKeyboard and releaseKeyboard. Fully reproduce the problem:
Create a simple Qt GUI project with QWidget base class without generating .ui file (remove the checkmark in the project creation wizard) and paste the code below in the .cpp and .h files of the QWidget inherited class.
Widget.cpp
@#include "Widget.h"
#include <QCloseEvent>
#include <QMessageBox>
#include <QPushButton>
#include <QGridLayout>Widget::Widget(QWidget parent)
: QWidget(parent)
{
QGridLayout const gl = new QGridLayout( this );QPushButton* const pb = new QPushButton("Show Message Box..."); gl->addWidget( pb ); connect( pb, SIGNAL(clicked()), this, SLOT(showMessageBox()) );
}
Widget::~Widget()
{
}void Widget::closeEvent(QCloseEvent* event)
{
const int buttonId = QMessageBox::warning( this, "Warning", "Close Event", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok );if ( QMessageBox::Cancel == buttonId ) { event->ignore(); }
}
void Widget::showMessageBox()
{
const int buttonId = QMessageBox::warning( this, "Warning", "Button click", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok );
Q_UNUSED( buttonId )
}@Widget.h
@#ifndef WIDGET_H
#define WIDGET_H#include <QtGui/QWidget>
class Widget : public QWidget
{
Q_OBJECTpublic:
Widget(QWidget *parent = 0);
~Widget();protected:
virtual void closeEvent(QCloseEvent* event);private slots:
void showMessageBox();
};#endif // WIDGET_H
@ -
Another version of the code above, this time using an instance of QMessageBox object:
Widget.cpp
@#include "Widget.h"
#include <QCloseEvent>
#include <QMessageBox>
#include <QPushButton>
#include <QGridLayout>Widget::Widget(QWidget parent)
: QWidget(parent)
, m_messageBox(0)
{
QGridLayout const gl = new QGridLayout( this );QPushButton* const pb = new QPushButton("Show Message Box..."); gl->addWidget( pb ); connect( pb, SIGNAL(clicked()), this, SLOT(showMessageBox()) ); m_messageBox = new QMessageBox( QMessageBox::Warning, "Warning", "Close event or button click!", QMessageBox::Ok | QMessageBox::Cancel, this );
}
Widget::~Widget()
{
}void Widget::closeEvent(QCloseEvent* event)
{
QWidget::closeEvent( event );const int buttonId = m_messageBox->exec(); if ( QMessageBox::Cancel == buttonId ) { event->ignore(); }
}
void Widget::showMessageBox()
{
const int buttonId = m_messageBox->exec();
Q_UNUSED( buttonId )
}
@Widget.h
@#ifndef WIDGET_H
#define WIDGET_H#include <QtGui/QWidget>
class QMessageBox;
class Widget : public QWidget
{
Q_OBJECTpublic:
Widget(QWidget *parent = 0);
~Widget();protected:
virtual void closeEvent(QCloseEvent* event);private slots:
void showMessageBox();private:
QMessageBox* m_messageBox;
};#endif // WIDGET_H
@