QML 使用 Window 自定义简易对话框

1.需求

先看看UI效果图,嗯,反正就是一股浓浓的网页风:

  • 对话框大小适应内容区域文本,也不排除会放入其他组件; 
  • 按钮区域肯定需要一定的自定义,比如显示隐藏哪些按钮。

2.实现

因为QML的Dialog会被限定在窗口内,所以我用Window来作为对话框的容器。实现效果如下:

  • 大小的适应,我让根组件的高度绑定内容的高度来适应;
  • 内容区域的组件切换,我放了一个Loader{}进行动态加载,且初始为一个Text显示文本信息;
  • 按钮区域我只放了一个Row{}排列按钮组,通过枚举来控制显示隐藏,暂时没扩展按钮的接口,全都是预先定义好的;
  • 此外还做了按钮焦点切换,弹出居中到屏幕等小功能。

3.代码

代码链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/TestQml_20201106_MyDialog

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

//测试消息框
Window {
    id: root
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Column{
        x:10
        y:10
        spacing: 10
        Button{
            id: btn_1
            text: "Dialog 1"
            onClicked: {
                dialog1.text+=dialog1.text
                dialog1.open()
            }
        }

        Button{
            id: btn_2
            text: "Dialog 1"
            onClicked: {
                dialog2.open()
            }
        }
    }

    MessageWindow{
        id: dialog1
        title: "这里是标题"
        text: "每次open文本叠加一倍测试高度适应。"
        buttonFlags: MessageWindow.CancelButton
                     |MessageWindow.OkButton
    }

    MessageWindow{
        id: dialog2
        text: "测试 buttonFlags 枚举。"
        buttonFlags: MessageWindow.CancelButton
                     |MessageWindow.OkButton
                     |MessageWindow.CloseButton
    }

    Component.onCompleted: {
        console.log("enum ok=",MessageWindow.OkButton)
    }
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

//消息框
Window {
    id: control

    //宽度可以重新设置,宽度根据内容适应
    width: 360
    height: content_loader.height+headerHeight+footerHeight
    //无边框
    flags: Qt.FramelessWindowHint | Qt.Dialog
    //模态
    modality: Qt.ApplicationModal

    //默认的Text组件的文本值
    property string text: ""
    //标题
    property alias title: title_text.text
    //背景区域Rectangle
    property alias background: bg_area
    //内容区域Loader加载的组件
    property alias content: content_loader.sourceComponent
    //右上关闭按钮Image
    property alias closeImage: close_img
    //右上关闭按钮MouseArea
    property alias closeMouse: close_mouse
    //标题栏高度
    property alias headerHeight: head_area.height
    //按钮栏高度
    property alias footerHeight: foot_area.height

    //按钮枚举,enum貌似是Qt5.10引入的,可替换为int来定义
    enum ButtonFlag{
        CloseButton=1 //关闭按钮
        ,CancelButton=2 //取消按钮
        ,OkButton=4 //确认按钮
    }
    //按钮枚举控制显示/隐藏
    property int buttonFlags: MessageWindow.CloseButton

    signal clickCancel()
    signal clickOk()

    //适配Dialog的open()接口
    function open()
    {
        control.resetPosition();
        control.show();
        //这里还没有把按钮焦点重置
    }

    //恢复位置到屏幕中心
    function resetPosition()
    {
        control.setX((control.screen.width-control.width)/2);
        control.setY((control.screen.height-control.height)/2);
    }

    //背景
    Rectangle{
        id: bg_area
        anchors.fill: parent
        color: "white"
        border.color: "lightGray"

        //用于拖拽对话框
        MouseArea{
            id: bg_mouse
            anchors.fill: parent
            property point clickPos: Qt.point(0,0)
            property bool dragMoving: false
            onPressed: {
                dragMoving = true;
                clickPos  = Qt.point(mouseX,mouseY);
            }
            onReleased: {
                dragMoving=false;
            }
            onPositionChanged: {
                if(!dragMoving){
                    return;
                }
                control.setX(control.x+mouseX-clickPos.x);
                control.setY(control.y+mouseY-clickPos.y);
            }
        }
    }

    //标题栏 header
    Item{
        id: head_area
        width: parent.width
        //设置标题文本后更高点
        height: title_text.text?50:30
        //预留的标题栏文本
        Text {
            id: title_text
            anchors.centerIn: parent
            color: "#444444"
            font.pixelSize: 16
            font.family: "Microsoft YaHei"
        }

        //标题栏关闭按钮
        Image {
            id: close_img
            visible: control.buttonFlags&MessageWindow.CloseButton
            source: "qrc:/close_gray.png"
            anchors{
                right: parent.right
                rightMargin: 10
                verticalCenter: parent.verticalCenter
            }
            width: sourceSize.width
            height: sourceSize.height

            MouseArea{
                id: close_mouse
                anchors.fill: parent
                //用close自适应大小会有问题
                onClicked: control.hide()
            }
        }
    }

    //中间内容区域
    Loader{
        id: content_loader
        x: 30
        y: headerHeight
        width: parent.width-60
        height: sourceComponent.height

        sourceComponent: Text {
            //width: content_loader.width
            color: "#666666"
            font.pixelSize: 14
            font.family: "Microsoft YaHei"
            wrapMode: Text.WrapAnywhere
            padding: 10
            text: control.text
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
        }
    }

    //底部按钮区域 footer
    Item{
        id: foot_area
        width: parent.width
        //显示按钮后更高点
        height: button_row.height + 30
        anchors.bottom: parent.bottom

        FocusScope{
            anchors.fill: parent
            focus: true
            Keys.onEscapePressed: control.hide()

            //底部按钮行
            Row{
                id: button_row
                anchors.centerIn: parent
                spacing: 20

                //这里反正也没几个按钮,就不把Button单独定义了
                //因为可能对单个按钮设置文本或者其他样式,Repeater也不用了
                Button{
                    id: btn_cancel
                    visible: control.buttonFlags&MessageWindow.CancelButton
                    text: "取消"
                    contentItem: Text {
                        text: parent.text
                        color: parent.focus?"white":"#666666"
                        font.pixelSize: 14
                        font.family: "Microsoft YaHei"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        elide: Text.ElideRight
                    }
                    background: Rectangle{
                        implicitWidth: 65
                        implicitHeight: 32
                        color: parent.focus?"#4A6FD3":"white"
                        border.color: "#D9D9D9"
                        border.width: parent.focus?0:1
                    }
                    onClicked: {
                        control.hide();
                        control.clickCancel();
                    }
                }

                Button{
                    id: btn_ok
                    text: "确认"
                    visible: control.buttonFlags&MessageWindow.OkButton
                    //默认焦点为确认
                    focus: true
                    contentItem: Text {
                        text: parent.text
                        color: parent.focus?"white":"#666666"
                        font.pixelSize: 14
                        font.family: "Microsoft YaHei"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        elide: Text.ElideRight
                    }
                    background: Rectangle{
                        implicitWidth: 65
                        implicitHeight: 32
                        color: parent.focus?"#4A6FD3":"white"
                        border.color: "#D9D9D9"
                        border.width: parent.focus?0:1
                    }
                    onClicked: {
                        control.hide()
                        control.clickOk()
                    }
                }
            }
        }
    }
}

 

### 回答1: QML是一种用户界面语言,可以用于开发桌面和移动应用程序。在QML中,可以通过弹出自定义模态对话框来实现与用户的交互。下面是一些实现此功能的步骤: 首先,需要创建一个新的QML文件来定义自定义模态对话框的布局和样式。在该文件中,可以使用标准QML组件来创建一个对话框,如Rectangle,Text和Button等。 其次,需要定义弹出自定义模态对话框的触发器,通常是一个按钮或菜单项。触发器应该有一个onClick事件处理程序,用来显示或隐藏自定义模态对话框。 然后,在onClick事件处理程序中,需要使用Qt Quick Dialogs组件中的Dialog组件来创建自定义模态对话框的实例。该组件提供了许多属性和方法,可以用于设置对话框的标题,内容和按钮等。 最后,在自定义模态对话框QML文件中,可以定义与用户交互的信号和槽,例如用户单击按钮时触发的事件。通过使用这些信号和槽,可以实现与用户的高级交互。 通过以上步骤,可以在QML中实现弹出自定义模态对话框的功能。在开发过程中,还需要注意遵循QML编程最佳实践,例如尽可能使用绑定和模型-视图分离等技术,以提高代码质量和可维护性。 ### 回答2: QML可以通过弹出自定义模态对话框来交互式地与用户进行交互,这主要是通过QML中提供的Dialog组件完成的。要弹出自定义模态对话框,需要创建一个新的自定义组件,该组件将作为Dialog的contentItem。 首先,创建一个QML文件作为自定义组件的模板。该模板可以包含所需的所有控件和布局,以及与这些控件相关的可视化效果。例如,一个包含一个文本框和两个按钮的自定义组件可能如下所示: ``` import QtQuick 2.0 Item { id: customDialog width: 200 height: 100 Rectangle { width: parent.width height: parent.height color: "lightgray" border.color: "black" border.width: 1 radius: 6 Text { text: "Enter your name:" anchors.centerIn: parent } TextInput { id: nameInput width: parent.width - 20 height: 20 anchors.top: parent.top anchors.topMargin: 20 anchors.horizontalCenter: parent.horizontalCenter } Row { width: parent.width spacing: 10 anchors.bottom: parent.bottom anchors.bottomMargin: 10 anchors.horizontalCenter: parent.horizontalCenter Button { text: "OK" onClicked: parent.accepted() } Button { text: "Cancel" onClicked: parent.rejected() } } } } ``` 该自定义组件包括一个文本输入框,一个“OK”按钮和一个“Cancel”按钮。在应用程序逻辑中,将创建一个与Dialog组件关联的弹出窗口,并将自定义组件添加为该窗口的contentItem。下面是一种可能的方法: ``` import QtQuick 2.0 import QtQuick.Controls 2.3 ApplicationWindow { id: mainWindow width: 300 height: 200 visible: true Button { text: "Open dialog" onClicked: openCustomDialog() } Dialog { id: customDialog title: "Custom dialog" x: (mainWindow.width - width) / 2 y: (mainWindow.height - height) / 2 modal: true contentItem: Item { CustomDialog { id: content anchors.fill: parent } } accepted: { console.log("OK clicked") console.log("Name entered: " + content.nameInput.text) } rejected: { console.log("Cancel clicked") } } function openCustomDialog() { customDialog.open() } } ``` 在这个例子中,当用户单击“Open dialog”按钮时,将调用openCustomDialog()函数,该函数将弹出一个自定义的模态对话框。该函数将调用Dialog的open()函数,它将显示模态对话框,直到用户单击“OK”或“Cancel”按钮为止。一旦用户单击了其中一个按钮,Dialog的accepted或rejected信号将触发。在这些信号的处理程序中,可以执行自定义操作,如读取文本输入框中输入的数据。 ### 回答3: QML弹出自定义模态对话框通常需要以下步骤: 1. 创建一个自定义QML组件,例如MyDialog.qml,并将其放置在对话框中。 2. 在MyDialog.qml中定义一个模态属性,以确保对话框在打开时是模态的。例如: Rectangle { // ... 其他属性 property bool modal: true // ... 其他组件 } 3. 在MyDialog.qml中添加关闭对话框的行为。例如: Button { text: "Close" onClicked: myDialog.close(); } 4. 在主QML文件中,初始化自定义对话框的一个实例,例如: import QtQuick.Controls 2.0 ApplicationWindow { // ... 其他属性 MyDialog { id: myDialog // ... 其他属性 } // ... 其他组件 } 5. 要使对话框出现,你可以向触发它的组件添加一个onClickd行为,例如一个按钮: Button { text: "Open Dialog" onClicked: myDialog.open(); } 上述操作将创建一个自定义QML组件,MyDialog.qml,它是模态的,并允许通过对话框中添加关闭按钮来关闭。还要在主QML文件中,初始化这个自定义对话框的一个实例,并通过触发组件的onClickd行为,使其出现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值