Qt: Как передать фокус немодальному QDialog, созданному из главного окна, когда главное окно заблокировано модальным QDialog

В моем приложении Qt я сталкиваюсь со следующим сценарием: когда возникает определенное событие, я показываю немодальный QDialog, который запрашивает у пользователя подтверждение. Диалог отображается с использованием функции show() из QMainWindow. Каждый раз, когда возникает событие и другие модальные QDialog не отображаются, пользователь может нажать кнопку подтверждения. К сожалению, если модальный QDialog виден при возникновении события, немодальный QDialog недоступен. Это означает, что пользователь не может нажать кнопку подтверждения. Следующий код представляет собой упрощенную версию, которая вызывает ту же проблему. В этом примере QMainWindow содержит кнопку, при нажатии кнопки отображается модальный QDialog с использованием функции exec(), в то время как QTimer был запущен. Каждый раз, когда я закрываю модальное окно QDialog до того, как истечет QTimer, становится доступным немодальное диалоговое окно. Если я подожду, пока не отобразится немодальное диалоговое окно, не закрывая модальное, немодальное диалоговое окно будет недоступно (сначала мне нужно закрыть модальное).

Код MainWindows:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_pModeless = new DialogModal(this);
    connect(&m_qTimer,SIGNAL(timeout()),this,SLOT(TimerElapsed()));

}

MainWindow::~MainWindow()
{
    delete m_pModeless;
    delete ui;
} 

void MainWindow::TimerElapsed()
{
    m_qTimer.stop();
    m_pModeless->show();
    m_pModeless->activateWindow();
    m_pModeless->raise();
    m_pModeless->setFocus();
}

void MainWindow::on_pbStartTest_clicked()
{
    m_qTimer.start(10000);
    DialogModal d(this);
    d.exec();
}

Заголовок MainWindow:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include "dialogmodal.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    QTimer m_qTimer;
    DialogModal *m_pModeless;
private:
    Ui::MainWindow *ui;
private slots:
    void TimerElapsed();
    void on_pbStartTest_clicked();
};

#endif // MAINWINDOW_H

Заголовок DialogModal:

#ifndef DIALOGMODAL_H
#define DIALOGMODAL_H

#include <QDialog>

namespace Ui {
class DialogModal;
}

class DialogModal : public QDialog
{
    Q_OBJECT

public:
    explicit DialogModal(QWidget *parent = 0);
    ~DialogModal();

private slots:
    void on_pbExit_clicked();

private:
    Ui::DialogModal *ui;
};

#endif // DIALOGMODAL_H

Источник DialogModal:

#include "dialogmodal.h"
#include "ui_dialogmodal.h"

DialogModal::DialogModal(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogModal)
{
    ui->setupUi(this);
}

DialogModal::~DialogModal()
{
    delete ui;
}

void DialogModal::on_pbExit_clicked()
{
    close();
}

Есть ли способ сосредоточить внимание на немодальном диалоге, даже если присутствует один или несколько модальных диалоговых окон?


person Rudy Barbieri    schedule 06.02.2014    source источник


Ответы (2)


Нашел рабочее решение:

void MainWindow::TimerElapsed()
{
    QWidget *pwidget=NULL;
    m_qTimer.stop();
    foreach(pwidget,QApplication::topLevelWidgets())
    {
        if ((pwidget->isWindow())&&(pwidget->isModal()))
        {
            m_pModeless->setParent(pwidget);
        }
    }
    if (pwidget==NULL)
    {
        m_pModeless->setParent(this);
    }
    m_pModeless->show();
    m_pModeless->activateWindow();
    m_pModeless->raise();
    m_pModeless->setFocus();
}
person Rudy Barbieri    schedule 07.02.2014

Когда модальный диалог будет активирован (вот-вот появится), вы можете попробовать изменить родительский элемент немодального диалога на этот модальный диалог. Поскольку немодальный диалог будет иметь модальное диалоговое окно в качестве родительского, то есть шанс разместить его наверху. Тем не менее, это также может зависеть от платформы.

Конечно в идеале, чтобы таких ситуаций не было

person yshurik    schedule 06.02.2014
comment
В MainWindow я могу это сделать, но что, если модальный диалог откроет другой модальный диалог? Есть ли способ получить указатель верхнего модального диалога? - person Rudy Barbieri; 07.02.2014
comment
topLevelWidget () или window () должен возвращать указатель этого виджета верхнего уровня - person yshurik; 07.02.2014
comment
Да, спасибо, я нашел это сегодня утром, теперь моя проблема в том, что коллекция QApplication::topLevelWidgets() возвращает более одного виджета, который отвечает true, когда я вызываю функцию isWindow. Я попробую объединить isWindow и isModal вместе и посмотреть, что получится. - person Rudy Barbieri; 07.02.2014