【问题标题】:QML on Windows: make the window to stay on topWindows 上的 QML:使窗口保持在顶部
【发布时间】:2017-02-16 12:00:09
【问题描述】:

我确实需要让我的窗口在 Windows 上保持在顶部,但 Windows 本身似乎 willing to allow me 无法做到这一点。

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

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

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

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

window.raise()
window.requestActivate()

但也没有运气。

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

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

Qt.Popup
Qt.FramelessWindowHint
Qt.WindowStaysOnTopHint
Qt.CustomizeWindowHint
Qt.BypassWindowManagerHint
Qt.MSWindowsFixedSizeDialogHint

我正在 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
}

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

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

timeout 5 && debug\Test.exe

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

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

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

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

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

【问题讨论】:

  • 只是为了确保:您说的是 QML 而不是 QtWidgets,对吧?
  • @derM 没错,但我认为 QML 类型和 QWidgets 内部有一个共同的机制,这就是我关注与 QWidgets 相关的错误的原因。除了 Qt.WindowStaysOnTopHint 标志之外,我什么也没找到,它可以帮助解决纯 QML 方面的问题。
  • 好吧,好像确实有bug。我会发布一些为我规避它的黑客。

标签: windows qml


【解决方案1】:

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

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()
    }
}

【讨论】:

  • 我必须注意我使用了这个标志,但在 Windows 上它什么也没做。
  • 对我来说,它适用于 Win7 和 Qt5.7。您使用哪个版本?你能提供一个mcve吗?
  • 我在 Windows 10 上使用 Qt 5.8。将窗口置于前台的问题似乎已在 Windows 7 中得到解决:bugreports.qt.io/browse/QTBUG-37435
  • 我已经添加了 mcve,花了一些时间才知道如何重现我的问题。
  • 在测试过程中,我注意到 winInit 组件的 visible 属性不必为 true 以使解决方法起作用。将 visible 更改为 false 会在应用程序启动期间消除闪烁。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 2023-03-09
  • 1970-01-01
  • 2012-12-07
相关资源
最近更新 更多