QML中可重复使用的确认提示

时间:2015-10-16 19:21:57

标签: qml qt5 qtquick2

当用户按下按钮时,我需要一个确认或警告对话框。根据他们是选择“是”还是“否”,会触发不同的操作。挑战在于我有两个按钮弹出这样的对话框,在QML中如何做到这一点并不是那么简单。这是代码(我的演示应用程序):

main.qml

import QtQuick 2.5
import QtQuick.Window 2.2

import QtQuick.Controls 1.4

Window {
    visible: true

    function areYouSure()
    {
        prompt.visible = true
    }

    MainForm {
        anchors.fill: parent

        Button {
            id: buttonA
            anchors.left: parent.left
            anchors.top: parent.top
            text: "Button A"

            onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
        }

        Button {
            id: buttonB
            anchors.right: parent.right
            anchors.top: parent.top
            text: "Button B"

            onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
        }
    }

    Prompt {
        anchors.fill: parent
        id: prompt
        visible: false

        onCancelled: {
            console.log("Cancel was pressed")
            // but how can I tell which button's cancel as pressed?
        }

        onAccepted: {
            console.log("Accept was pressed")
            // same for which button's Ok?
        }
    }
}

Prompt.qml

import QtQuick 2.5
import QtQuick.Window 2.2

import QtQuick.Controls 1.4

Rectangle
{
    id: root
    width: parent.width

    property string message: "Are you Sure?"

    signal cancelled;
    signal accepted;


    Text{
        id: messagetxt
        text:root.message
        horizontalAlignment: Text.AlignHCenter
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter

    }

    Rectangle {
        id: cancelButton
        anchors.bottom: parent.bottom
        anchors.left: parent.left
        width: 50
        height: 40

        Text {
            anchors.centerIn: parent
            text: "Cancel"
        }
        color: "red"

        MouseArea {
            anchors.fill: parent

            onClicked: {
                root.visible = false
                cancelled()
            }
        }
    }

    Rectangle {
        id: okButton
        anchors.bottom: parent.bottom
        anchors.right: parent.right
        width: 50
        height: 40

        Text {
            anchors.centerIn: parent
            text: "Ok"
        }
        color: "blue"

        MouseArea {
            anchors.fill: parent

            onClicked: {
                root.visible = false
                accepted()

            }
        }
    }
}

在传统编程中,弹出一个单独的对话框,该对话框完全响应该问题,而不是响应其cancelled()accepted()信号。在QML中我们不能真的这样做,对吗?知道按下哪个按钮的最佳方法是什么?具有讽刺意味的是,即使发出正确的信号,我们也似乎无法对它们采取行动。

1 个答案:

答案 0 :(得分:2)

嗯,首先,您应该真正了解Dialogs模块,因为它为您提供了现成的解决方案,即MessageDialog

也就是说,您可以通过不同方式实现自定义,包括重新定义处理程序或传递id。如果要执行的操作很简单(例如函数调用),您甚至可以动态创建对话框并使用所需的行为绑定信号。自定义显然可以更进一步,更改titletext

这是一个简单的示例,它遵循最后一种方法,并根据按下的按钮打印不同的文本。一旦对话框设置为不可见,它将通过destroy函数销毁。

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0

ApplicationWindow {
    id: win
    title: qsTr("MultiDialog")
    visible: true

    RowLayout {
        anchors.fill: parent

        Button {
            text: "Button 1"
            onClicked: {
                var d1 = compDialog.createObject(win)
                // change "title" & "text"?
                d1.accepted.connect(function(){
                    console.info("accepted: " + text)
                })
                d1.rejected.connect(function(){
                    console.info("rejected: " + text)
                })
                d1.visible = true
            }
        }

        Button {
            text: "Button 2"
            onClicked: {
                var d2 = compDialog.createObject(win)
                // change "title" & "text"?
                d2.accepted.connect(function(){
                    console.info("accepted: " + text)
                })
                d2.rejected.connect(function(){
                    console.info("rejected: " + text)
                })
                d2.visible = true
            }
        }
    }

    Component {
        id: compDialog

        MessageDialog {
            title: "May I have your attention please"
            text: "It's so cool that you are using Qt Quick."
            onVisibleChanged: if(!visible) destroy(1)
            standardButtons: StandardButton.Cancel | StandardButton.Ok
        }
    }
}

如果您想使用Rectangle或被迫使用它,那么您仍然可以使用此方法。动态创建对象与MessageDialog的使用无关,可以使用(并且应该使用)来减少在整个应用程序生命周期中保持实例化的对象数。有关详细信息,请查看here

以下示例使用您定义的完全相同的对话框组件(稍作修改。正如您所看到的,代码几乎相同。我刚刚在信号处理程序的末尾移动了对象的破坏。 case我还更改了组件中定义的唯一属性的值,即message,以显示完整的自定义。

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4

Window {
    id: win
    visible: true

    RowLayout {
        anchors.fill: parent

        Button {
            text: "Button 1"
            Layout.alignment: Qt.AlignCenter
            onClicked: {
                var d1 = prompt.createObject(win)
                d1.message = text + " - Are you Sure?"
                d1.accepted.connect(function(){
                    console.info("accepted: " + text)
                    d1.destroy()
                })
                d1.rejected.connect(function(){
                    console.info("rejected: " + text)
                    d1.destroy()
                })
            }
        }

        Button {
            text: "Button 2"
            Layout.alignment: Qt.AlignCenter
            onClicked: {
                var d2 = prompt.createObject(win)
                d2.message = text + " - Are you Sure?"
                d2.accepted.connect(function(){
                    console.info("accepted: " + text)
                    d2.destroy()
                })
                d2.rejected.connect(function(){
                    console.info("rejected: " + text)
                    d2.destroy()
                })
            }
        }
    }

    Component {
        id: prompt

        Rectangle {
            id: root
            anchors.fill: parent

            property string message: "Are you Sure?"

            signal rejected()
            signal accepted()

            Text{
                id: messagetxt
                text:root.message
                horizontalAlignment: Text.AlignHCenter
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter
            }

            Rectangle {
                id: cancelButton
                anchors.bottom: parent.bottom
                anchors.left: parent.left
                width: 50
                height: 40

                Text {
                    anchors.centerIn: parent
                    text: "Cancel"
                }
                color: "red"

                MouseArea {
                    anchors.fill: parent
                    onClicked: rejected()
                }
            }

            Rectangle {
                id: okButton
                anchors.bottom: parent.bottom
                anchors.right: parent.right
                width: 50
                height: 40

                Text {
                    anchors.centerIn: parent
                    text: "Ok"
                }
                color: "blue"

                MouseArea {
                    anchors.fill: parent
                    onClicked: accepted()
                }
            }
        }
    }
}

如果您的组件没有像Component那样内联,但它保存在另一个文件中,您可以使用createComponent,如上面提供的链接所示。主窗口的代码如下所示:

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4

Window {
    id: win
    visible: true
    property var prompt

    RowLayout {
        anchors.fill: parent

        Button {
            text: "Button 1"
            Layout.alignment: Qt.AlignCenter
            onClicked: {
                var d1 = prompt.createObject(win)
                d1.message = text + " - Are you Sure?"
                d1.accepted.connect(function(){
                    console.info("accepted: " + text)
                    d1.destroy()
                })
                d1.rejected.connect(function(){
                    console.info("rejected: " + text)
                    d1.destroy()
                })
            }
        }

        Button {
            text: "Button 2"
            Layout.alignment: Qt.AlignCenter
            onClicked: {
                var d2 = prompt.createObject(win)
                d2.message = text + " - Are you Sure?"
                d2.accepted.connect(function(){
                    console.info("accepted: " + text)
                    d2.destroy()
                })
                d2.rejected.connect(function(){
                    console.info("rejected: " + text)
                    d2.destroy()
                })
            }
        }
    }

    Component.onCompleted: prompt = Qt.createComponent("Prompt.qml");
}

您应该始终检查是否正确执行了组件创建(为简洁起见,我没有这样做)。也就是说,代码与前一代码相同。

最后但并非最不重要的是,我注意到代码中出现错误:即使没有发出参数,也必须用括号声明始终的信号。对于其他信号和任何其他信号声明,它应该是signal accepted(),而不是signal accepted