我有 QSystemTrayIcon 和 QAction,可以打开 QWebView 类型的新窗口。当窗口失去焦点并且我再次选择 QAction 时,窗口应该重新获得焦点。它在 Linux 上可以,但在 Mac OS X 上不行。
问题是,当我打开另一个窗口并处于活动状态时,比如说 Google Chrome,当我在尝试打开的窗口上调用
show()
时,它总是在 Google Chrome 下打开,所以我不这样做看到它。
聚焦也是如此,当我打开多个窗口时,我的 QWebView 可能是顺序中的最后一个,当我单击 QAction 来聚焦窗口时,它将始终位于 Google Chrome 窗口下方。
我的猜测是,当我单击 QAction(这是我的应用程序进程的一部分)时,它将尝试打开/聚焦窗口。但是,在操作过程中,Google Chrome 窗口会被调度并获得焦点,因为 QSystemTrayIcon 无法保持焦点。
因此,当窗口打开/获得焦点时,它不会从 Google Chrome 中窃取焦点,因为操作系统不允许这样做,因此它将被放置在当前获得焦点的窗口下。
我如何创建/聚焦窗口:
// ...
QPointer<QWebView> view;
// ...
void TrayIcon::webView() {
if (!this->view) {
this->view = new QWebView();
this->view->load("http://example.com");
this->view->show();
} else {
this->view->activateWindow();
this->view->raise();
}
}
我是否做错了什么,或者有任何已知的解决方法吗?
有点离题,但对某些用户可能有用:
我的建议是创建依赖于平台的代码来强制提升窗口。 Windows 平台上也有同样的问题,所以我正在使用下一个 hack:
void Utils::forceForegroundWindow( WId winId )
{
#ifdef Q_OS_WIN
HWND hWnd = winId;
if ( ::IsWindow( hWnd ) )
{
HWND hCurrWnd;
int iMyTID;
int iCurrTID;
hCurrWnd = ::GetForegroundWindow();
iMyTID = ::GetCurrentThreadId();
iCurrTID = ::GetWindowThreadProcessId( hCurrWnd, 0 );
::AttachThreadInput( iMyTID, iCurrTID, TRUE );
::ShowWindow( hWnd, SW_SHOWNORMAL );
::SetForegroundWindow( hWnd );
::AttachThreadInput( iMyTID, iCurrTID, FALSE );
}
#endif
}
我的项目中仍然没有提供 Mac OS 兼容性,因此此代码对于非 win 平台没有功能。
另一个想法:你应该始终保持焦点可见窗口。尝试使用 WA_TranslucentBackground | 来做一个WA_TransparentForMouseEvents 属性 + FramelessWindowHint 标志。所以你的应用程序永远不会失去焦点。
所以我设法用平台相关的代码解决了这个问题。我使用 .mm 文件中的代码创建了 Focuser 类,其中包含名为 Cocoa 的 Objective-C 代码。
焦点.h
#ifndef FOCUSER_H
#define FOCUSER_H
#include <QWidget>
class Focuser {
QWidget *widget;
public:
Focuser(QWidget *);
void show();
void focus();
};
#endif // FOCUSER_H
focuser_mac.mm
#include "focuser.h"
#import <Cocoa/Cocoa.h>
Focuser::Focuser(QWidget *w) {
this->widget = w;
}
void Focuser::show() {
this->widget->show();
this->focus();
}
void Focuser::focus() {
[NSApp activateIgnoringOtherApps:YES];
this->widget->activateWindow();
this->widget->raise();
}
焦点.cpp
#include "focuser.h"
Focuser::Focuser(QWidget *w) {
this->widget = w;
}
void Focuser::show() {
this->widget->show();
this->focus();
}
void Focuser::focus() {
this->widget->activateWindow();
this->widget->raise();
}
因此,我们有一个类,它在构造函数中采用 QWidget,并且有两个公共方法,一个是显示窗口小部件,另一个是聚焦窗口小部件的焦点。然后我们有该类的两个定义,一个在 focuser_mac.mm 中用于 Mac OS X,另一个在 focuser.cpp 中用于任何其他操作系统。 Mac 版的还可以调用
[NSApp activateIgnoringOtherApps:YES];
现在,为了编译它,应该将其添加到您的 .pro 文件中:
HEADERS += focuser.h
mac {
OBJECTIVE_SOURCES += focuser_mac.mm
}
linux|win32 {
SOURCES += focuser.cpp
}
完成后,只需在您需要应用程序关注的位置添加此代码即可:
QWidget *w = new QWidget();
// ...
Focuser f(w);
w.show(); // The widget will now be shown and focused by default.