Windows 上的 QML:使窗口保持在顶部

Ole*_*hyn 3 windows qml

我确实需要让我的窗口在 Windows 上保持领先,但 Windows 本身似乎并不愿意让我这样做。

我无法使用设置注册表值的解决方法,因为我无法要求用户注销/登录。

此外,我使用 QML 和QWidget::raise() 和 QApplication::setActiveWindow()的解决方案似乎也不起作用,因为我还没有设法使用以下代码将 QML 根对象作为 QWidget 指针获取:

QWidget* mainWin = qobject_cast<QWidget*>(engine.rootObjects().at(0));
if (mainWin)
{
    mainWin->raise();
    QApplication::setActiveWindow(mainWin);
    mainWin->activateWindow();
}
Run Code Online (Sandbox Code Playgroud)

我还尝试直接从 QML 激活窗口:

window.raise()
window.requestActivate()
Run Code Online (Sandbox Code Playgroud)

但也没有运气。

是否有任何一种方法可以在不更改注册表的情况下将窗口置于 Windows 的顶部,最好是纯粹从 QML 中?

编辑:当前使用的窗口标志是:

Qt.Popup
Qt.FramelessWindowHint
Qt.WindowStaysOnTopHint
Qt.CustomizeWindowHint
Qt.BypassWindowManagerHint
Qt.MSWindowsFixedSizeDialogHint
Run Code Online (Sandbox Code Playgroud)

我正在Windows 10 x64机器部署Qt 5.7 应用程序。我发现了这两个错误修正:

从中我可以得出结论, QWidget::activateWindow() 和 QWindow::requestActive() 应该适用于 Windows XP 和 Windows 7。

这是我的mcve,正如@derM 所问:

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    flags: Qt.WindowStaysOnTopHint

    width: 100
    height: 100
    visible: true
}
Run Code Online (Sandbox Code Playgroud)

它是在 Windows 10 x64 下使用 MinGW x32 编译的。

更简单的重现方式:在命令提示符下运行

timeout 5 && debug\Test.exe
Run Code Online (Sandbox Code Playgroud)

其中 debug\Test.exe 是 mcve 二进制文件的路径,然后打开文件资源管理器并导航到某个地方。当窗口打开时,它不会在前台。

更难的方法:如果你只是运行它,窗口将保持在它应该的顶部。但是,如果您按下 Qt Creator 中的运行按钮并将焦点(我想应该更改鼠标焦点,只需按 Alt+Tab 将无济于事)切换到另一个进程(在我的情况下 - 文件资源管理器),将显示该窗口在当前活动的文件资源管理器窗口下,即使我通过单击将其调出,只要我选择任何其他应用程序,它就会进入后台。

真正的应用程序是从一个服务启动的,所以我的应用程序启动时经常会有一个应用程序保持鼠标焦点。我想 Qt 将窗口置于前台的能力是使用SetForegroundWindow API 调用实现的,它在其备注中指出了以下限制:

  • 该进程是前台进程。
  • 该进程由前台进程启动。
  • 进程接收到最后一个输入事件。
  • 没有前台进程。
  • 进程正在调试中。
  • 前台进程不是现代应用程序或开始屏幕。
  • 前景未锁定(请参阅 LockSetForegroundWindow)。
  • 前台锁超时已过期(请参阅 - SystemParametersInfo 中的 SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 没有菜单处于活动状态。

所以我想知道如果进程是由服务启动的,而不是用户(即进程在启动期间不是活动进程),是否有可能将窗口置于前台。

der*_*erM 6

正如您所发布的:如果窗口是从前台进程创建的,我们将在创建窗口之前确保我们的进程是前台进程。

import QtQuick 2.7
import QtQuick.Window 2.2

Item {
    id: root

    Component { // Like a splash screen: Claim to be foreground process,
                // then create main window.
        id: winInit
        Window {
            flags: Qt.WindowStaysOnTopHint
            width: 1
            height: 1
            Component.onCompleted: {
                requestActivate()
                mainWin.createObject(root)
            }
        }
    }

    Component {
        id: mainWin
        Window {
            flags: Qt.WindowStaysOnTopHint
            width: 100
            height: 100
            visible: true
        }
    }

    Component.onCompleted: {
        var w1 = winInit.createObject(null)
        w1.destroy()
    }
}
Run Code Online (Sandbox Code Playgroud)