问题描述
我有一个带有非模态 MainWindow
和 QDialog
的 QPushButton
,只是为了显示对话框。当应用程序最小化并再次最大化时,我希望对话框(如果可见)重新获得键盘焦点。
代码如下:
主窗口.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
QDialog *dialog;
public:
explicit MainWindow(QWidget *parent = nullptr);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPushButton>
#include <QDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),dialog(new QDialog(this))
{
QPushButton *button = new QPushButton("show dialog",this);
connect(button,&QPushButton::clicked,dialog,&QDialog::show);
setCentralWidget(button);
}
听起来很简单,但我尝试了各种方法都没有运气:
方法一: 侦听 QApplication::applicationStateChanged() 信号并在应用程序状态变为活动状态时将焦点设置为对话框。
方法二: 侦听对话框的显示和窗口激活事件并在触发时设置焦点。
方法 3: 侦听主窗口的显示和窗口激活事件并在触发时设置焦点。
主窗口.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
QDialog *dialog;
public:
explicit MainWindow(QWidget *parent = nullptr);
virtual bool event(QEvent *event) override;
virtual bool eventFilter(QObject *watched,QEvent *event) override;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPushButton>
#include <QDialog>
#include <QEvent>
#include <QApplication>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),&QDialog::show);
setCentralWidget(button);
dialog->installEventFilter(this);
//set focus on dialog when app becomes active
connect(qApp,&QApplication::applicationStateChanged,this,[this](Qt::ApplicationState state){
if (dialog->isVisible() && state == Qt::ApplicationActive) {
dialog->setFocus();
}
});
}
bool MainWindow::event(QEvent *event)
{
//set focus on dialog when main window is shown or activated
if (event->type() == QEvent::Show || event->type() == QEvent::WindowActivate) {
if (dialog->isVisible()) {
dialog->setFocus();
}
}
return QMainWindow::event(event);
}
bool MainWindow::eventFilter(QObject *watched,QEvent *event)
{
//set focus on dialog when dialog is shown or activated
if (watched == dialog) {
if (event->type() == QEvent::Show || event->type() == QEvent::WindowActivate) {
dialog->setFocus();
}
}
return QMainWindow::eventFilter(watched,event);
}
解决方法
一种有效的方法是侦听 QApplication::applicationStateChanged()
信号并在应用激活时调用 QWindow::requestActivate()
:
connect(qApp,&QApplication::applicationStateChanged,this,[this](Qt::ApplicationState state){
if (dialog->isVisible() && state == Qt::ApplicationActive) {
if (dialog->windowHandle()) dialog->windowHandle()->requestActivate();
}
});
根据文档,不确定为什么 QWindow::requestActivate()
有效,但 QWidget::setFocus()
在两个函数都应该提供键盘焦点时无效。如果有人知道,请在下面评论。