Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: QtProger от Июнь 30, 2010, 14:21



Название: Вывести QMessageBox поверх всех окон
Отправлено: QtProger от Июнь 30, 2010, 14:21
Как это сделать ?


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: GreatSnake от Июнь 30, 2010, 14:34
Код
C++ (Qt)
#ifdef Q_WS_X11
#include <QX11Info>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#endif
 
static void activateWindow( QWidget* w )
{
if( !w->isShown() )
w->show();
w->raise();
 
#ifdef Q_WS_X11
 
Display* dpy = QX11Info::display();
 
XClientMessageEvent ev = { 0 };
 
ev.type = ClientMessage;
ev.window = w->winId();
ev.message_type = XInternAtom( dpy, "_NET_ACTIVE_WINDOW", False );
ev.format = 32;
ev.send_event = True;
ev.data.l[1] = QX11Info::appUserTime();
 
XSendEvent( dpy,
RootWindowOfScreen( DefaultScreenOfDisplay( dpy) ), False,
SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &ev );
XSync( dpy, False );
 
#elif defined(Q_OS_WIN)
 
SetWindowPos( w->winId(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
 
#endif
 
w->activateWindow();
}
 
class YourMessageBox : public QMessageBox
{
     ...
     ...
     virtual void setVisible ( bool visible )
     {
          QMessageBox::setVisible( visible );
          if( visible )
            activateWindow( this );
     }
};
 

Но если используете статические методы QMessageBox, то придётся вешать eventFilter:
Код
C++ (Qt)
class YourMainWindow : public QMainWindow
{
public:
      YourMainWindow( QWidget* parent = 0 ) : QMainWindow( parent )
      {
          qApp->installEventFilter( this );
      }
 
      bool eventFilter( QObject* o, QEvent* e )
      {
QWidget* w = o->isWidgetType() ? qobject_cast< QWidget* >( o ) : 0;
 
if( e->type() == QEvent::ShowToParent && w && w->window() == w &&
( w->windowType() == Qt::Window || w->windowType() == Qt::Dialog ) )
{
activateWindow( w );
}
return false;
      }
};
 

Последний вариант, имхо, предпочтительней, т.к. решает проблему для всех top-level и диалоговых окон.


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: tim474 от Июнь 30, 2010, 15:43
А флаг WindowStaysOnTopHint?


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: GreatSnake от Июнь 30, 2010, 16:02
Цитировать
А флаг WindowStaysOnTopHint?
Сей флаг просто "держит" окно поверх других не активируя его.


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: QtProger от Июнь 30, 2010, 16:12
Сей флаг просто "держит" окно поверх других не активируя его.

Мне как раз это нужно. QMessageBox должен быть поверх всех окон. Активировать его не обязательно.


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: GreatSnake от Июнь 30, 2010, 16:22
Цитировать
Активировать его не обязательно.
Это как это?
Какой толк от активного модального диалога наверху, если он не будет иметь клавиатурного фокуса?
Это ущербный gui получается.


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: QtProger от Июнь 30, 2010, 16:30
Какой толк от активного модального диалога наверху, если он не будет иметь клавиатурного фокуса?
Это ущербный gui получается.

Клавиатурный фокус не требуется. QMessageBox я использую лишь в качестве уведомления.


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: GreatSnake от Июнь 30, 2010, 16:34
Цитировать
Клавиатурный фокус не требуется. QMessageBox я использую лишь в качестве уведомления.
Т.е. когда всплывёт этот диалог, юзер не сможет нажать <Esc>, <Enter> или <Space>, чтобы его убрать?
Или я чего-то не понимаю, или ...


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: QtProger от Июнь 30, 2010, 16:57
Т.е. когда всплывёт этот диалог, юзер не сможет нажать <Esc>, <Enter> или <Space>, чтобы его убрать?
Или я чего-то не понимаю, или ...

Да, было бы неплохо сделать клавиатурный фокус. Но вот что написано в справке к void QWidget::activateWindow ():

Цитировать
On Windows, if you are calling this when the application is not currently the active one then it will not make it the active window. It will change the color of the taskbar entry to indicate that the window has changed in some way. This is because Microsoft does not allow an application to interrupt what the user is currently doing in another application.

Из этого текста я понял, что в Виндовсе нельзя активировать окно приложения.


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: GreatSnake от Июнь 30, 2010, 17:07
Хм, а для чего я выше привёл код альтернативного activateWindow()?


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: QtProger от Июнь 30, 2010, 17:29
GreatSnake, я вставил твой код в widget.h, компилятор выдал кучу ошибок. Ошибки я написал в комментариях:

Код
C++ (Qt)
class YourMainWindow : public QMainWindow
{ //error: expected class-name before '{' token
public:
      YourMainWindow( QWidget* parent = 0 ) : QMainWindow( parent ) //error: class 'YourMainWindow' does not have any field named 'QMainWindow'
      {
               qApp->installEventFilter( this ); //error: no matching function for call to 'QApplication::installEventFilter(YourMainWindow* const)'
      }
 
      bool eventFilter( QObject* o, QEvent* e )
      {
               QWidget* w = o->isWidgetType() ? qobject_cast< QWidget* >( o ) : 0;
 
               if( e->type() == QEvent::ShowToParent && w && w->window() == w &&
                       ( w->windowType() == Qt::Window || w->windowType() == Qt::Dialog ) )
               {
                       activateWindow( w ); //error: 'activateWindow' was not declared in this scope
               }
               return false;
      }
};


Название: Re: Вывести QMessageBox поверх всех окон
Отправлено: GreatSnake от Июнь 30, 2010, 17:34
Мде...