【问题标题】:How to make a non-modal Dialog window be always on top?如何使非模态对话框窗口始终位于顶部?
【发布时间】:2017-07-06 13:57:51
【问题描述】:

我在我的应用程序中使用Dialog {} 的实例来显示一个小的控制器窗口,用户可以与之交互以影响主窗口中的功能(类似于遥控器)。我可以将此对话框设为模态(modality: Qt.WindowModalmodality: Qt.ApplicationModal),也可以使用modality: Qt.NonModal 将其设为非模态。

我的问题是我需要将其设为非模态但始终位于主窗口的顶部。如果我使用Qt.NonModal,我仍然可以单击主窗体,但我的对话框会在它后面。 Dialog 类似乎没有 flags: 属性,所以我不能只将其设置为 Qt.WindowsStaysOnTopHint

有没有什么方法可以像这样纯粹从 QML 方面设置对话框的标志?或者是否可以在 C++ 中编写一个简单的实用程序方法,我可以从对话框的Component.onCompleted: 调用并传入对话框以在那里设置其窗口标志?

更新:为了说明我在说什么,这是我的主窗口顶部的对话框:

这是我的主窗口下方的对话框:

我希望我的对话框不会像这样进入我的主窗口下方,但我仍然希望能够单击并与我的主窗口进行交互。换句话说,我希望我的对话框是非模态的,但总是在顶部。

【问题讨论】:

  • 也许你可以用鼠标区域过滤掉对话框外的点击事件?
  • @sk2212:我认为这行不通。我希望用户能够单击主窗口或此浮动遥控器并与之交互。基本上只是标准的工具窗口行为。
  • 嗯...您能从您的窗口和对话框中创建一个简单的屏幕截图吗?我还是不明白你的意思。
  • 主窗口是Dialog的父窗口吗?这应该足以让Dialog保持领先——我认为。
  • @G.M.:主窗口是 Dialog 的父窗口(我认为,它目前是内联定义的),但它仍然位于主窗口下方。

标签: qt qml


【解决方案1】:

尝试使用Window 而不是Dialog 这样您就可以访问flags 属性。

您可以将flags 设置为Qt.WindowStaysOnTopHint 以使您的窗口始终位于其他窗口之上。您可以找到标志列表here。 (不要忘记在 QML 中将 :: 替换为 .

Main.qml:

import QtQuick 2.5
import QtQuick.Controls 2.0
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")


    Button {
        id: btn
        width: 100 ; height : 40
        text: "click me"
    }

    Text {
        anchors.top : btn.bottom
        text: "Button currently pressed"
        visible: btn.pressed
    }

    DialogOnTop {

    }
}

DialogOnTop.qml:

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.4

Window {
    id: myWindow

    width: 200
    height: 200

    flags:  Qt.Window | Qt.WindowSystemMenuHint
            | Qt.WindowTitleHint | Qt.WindowMinimizeButtonHint
            | Qt.WindowMaximizeButtonHint | Qt.WindowStaysOnTopHint


    visible: true
    modality: Qt.NonModal // no need for this as it is the default value


    Rectangle {
        color: "lightskyblue"
        anchors.fill: parent
        Text {
            text: "Hello !"
            color: "navy"
            anchors.centerIn: parent
        }
    }
}

结果:

【讨论】:

  • 所以我之前使用 Window 的尝试在 createComponent 上莫名其妙地失败了(这是关于不存在的标志和模态属性的错误)但是当我根据你的示例创建一个新类时 Window完美地工作。我正在开发的应用程序是从其他开发人员继承的代码库,他们似乎在 c++ 中添加了一些神奇的底层代码,用他们自己的版本替换了 QML 中真正的 Window 类(不公开暴露标志和模式,因此错误)。一旦我在课堂上注释掉了他们的导入语句,Window 就起作用了……
  • ...完美,非模态并且始终位于我的主窗口顶部。有时我讨厌我的开发者伙伴,但我喜欢。我将为您将得到的这个问题添加一个赏金(无论如何,我正打算为此提供一个赏金以帮助我得到答案)。
【解决方案2】:

通常你想使用Dialog 不仅仅是为了创建一个新窗口,而是为了它实现的功能和界面......

Dialog不继承WindowApplicationWindow的原因很明显:没有窗口,只要不是open()。但是一旦打开,就会有一个ApplicationWindow(来自QtQuick.Controls 1.4)

现在,在文档中,我们发现了这个漂亮的附加属性:ApplicationWindow,每个Item 都可以使用它,并且方便我们访问窗口。然后我们只需要找到一种方法来设置正确的标志,只要ApplicationWindow 可用 - 例如当我们收到信号visibleChanged.
由于Dialog 也不是Item,我们需要使用它的contentItem 来访问这个附加属性。

当我们将所有这些放在一起时,结果可能如下所示:

NonModalDialogThatStaysOnTop.qml // 我不擅长命名

import QtQuick 2.3
import QtQuick.Controls 1.4 // You need this, to have access to the `ApplicationWindow`-attatched property
import QtQuick.Dialogs 1.2

Dialog {
    onVisibleChanged: {
        if (visible) contentItem.ApplicationWindow.window.flags |= Qt.WindowStaysOnTopHint
    }
    modality: "NonModal"
}

现在你有你最喜欢的Dialog,它保持在顶部但不是模态的。

【讨论】:

  • 有效!但是,它仅适用于 QtQuick.Controls 第一代导入(不是第二代)。我还必须添加一对其他标志才能显示标题和关闭按钮:Qt.WindowTitleHint 和 Qt.WindowCloseButtonHint
【解决方案3】:

好的,所以您只想创建一个对话框(或一个看起来像对话框的组件)并且只想与主窗口对话框窗口进行交互。

请尝试以下方法:

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    id: rootWindow
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    color: "green"

    Rectangle {
        id: behind
        anchors.fill: parent
        color: Qt.rgba(0, 0, 0,  0.7)
        visible: false
    }

    MouseArea {
        enabled: behind.visible
        anchors.fill: parent

        onClicked: {
            console.log("Root Window")
        }
    }

    Button {

        text: "Open Dialog"

        onClicked: {
            behind.visible = true;
            var comp = Qt.createComponent("qrc:/MyDialog.qml");
            // var comp = Qt.createComponent("qrc:/DialogQt.qml");
            var obj1 = comp.createObject(rootWindow, {});
            obj1.z = 2;
        }
    }
}

MyDialog.qml

import QtQuick 2.7

Rectangle {
    id: modalWindow
    width: 200
    height: 200
    color: "red"

    anchors.centerIn: parent

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log("Modal Window")
        }
    }
}

单击“打开对话框”按钮将在主窗口组件顶部创建并打开“模式”对话框。

当然,您必须自行调整“MyDialog.qml”文件以适应您的设计要求。

但是,将其用作“真实”对话框(对我而言)也确实有效,就像 G.M 在 cmets 部分中已经指出的那样:

DialogQt.qml

Dialog {
    visible: true
    title: "Blue sky dialog"

    modality : Qt.ApplicationModal

    contentItem: Rectangle {
        color: "lightskyblue"
        anchors.fill: parent
        Text {
            text: "Hello blue sky!"
            color: "navy"
            anchors.centerIn: parent
        }
    }

}

【讨论】:

  • 我想我还没有传达我正在尝试正确执行的操作。我可以在这里轻松地做你在回答中所做的事情 - 在我的主窗口中间弹出一个矩形并与它或下面的窗口进行交互。这只是标准 QML 布局的东西。我正在尝试通过一个单独的窗口来实现这一点 - 您的 DialogQt.qml 也无法实现这一点,因为它是模态的(我需要一个非模态但始终位于主窗口顶部的单独窗口)。跨度>
  • @MusiGenesis 你必须使用Dialog 吗?使用Window 会起作用吗?我在我的应用程序中使用Window 做了同样的事情(非模态但始终在顶部)。
  • @Blabdouze:我之前确实尝试过使用Window 而不是Dialog,但是createComponent 调用一直失败,说Window 上没有flags: 或@ 这样的属性987654331@,这两个我都必须设置才能让它工作(我假设)。我在 Qt 5.5 上,也许这是我的问题?您可以使用Window 发布答案吗?
  • @MusiGenesis 我认为版本不是问题,如果我没记错的话,我当时使用的是 5.3 并且我有一个带有标志的Window。我发布了一个适合我的解决方案(在 5.7 上,但我认为这不是版本问题)。
猜你喜欢
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-24
相关资源
最近更新 更多