QML实现可定制模态对话框【核心部分详解】


不少朋友需要会用到模态对话框,那么如何使用QML创建模态对话框呢?


分析:

我所需要的模态对话框是这样的:

上到下一次包含了:

a.标题栏

b.内容框

c.按钮栏

为了方便接口使用,我们将这三个部分整合在一个Window中。


这里是代码示例:

import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0

Window {
    id: eo_askDialog

    width: 300
    height: 200
    
    ColumnLayout{
        anchors.fill: parent

        spacing:2

        //标题栏
        Rectangle{
            id: titleBar
            Layout.fillWidth: parent
            implicitHeight: 30
            color: "darkgray"
        }

        //内容框
        Rectangle{
            id: contentView
            Layout.fillWidth: parent
            Layout.fillHeight: parent
            color: "lightgray"
        }

        //按钮栏
        Rectangle{
            id: buttonBar
            Layout.fillWidth: parent
            implicitHeight: 30
            color: "darkgray"
        }
    }
}

功能确定:

1.返回确认信号

2.返回取消信号

3.返回checkBox被选中时候的确认信号

4.返回关闭信号

5.可定制标题栏背景

6.可定制内容框背景

7.可定制按钮栏背景

8.可定制文字信息


为了实现以下功能,我们需要往Window中添加一些属性:

    property string title: "ask dialog"          //对话框标题
    property string content: "ask content."      //对话框内容
    property string yesButtonString: "yes"       //yes按钮的文字
    property string noButtonString: "no"         //no按钮的文字
    property string checkBoxString: "check box"  //选择框的文字
    property string titleBackgroundImage: ""     //标题栏背景图片
    property string contentBackgroundImage: ""   //内容框的背景图片
    property string buttonBarBackgroundImage: "" //按钮框的背景图片
    property bool checked: false                 //选择框是否确认

因为我们需要实现自定义的标题栏,所以加上这个属性可以忽略系统自带的标题栏:

flags: Qt.FramelessWindowHint | Qt.Window | Qt.WindowStaysOnTopHint

当然,不能忘了这是个模态对话框,加上如下的属性:

modality: Qt.ApplicationModal

我们需要告知外界Window的情况,所以加上自定义的信号:

   /** 自定义信号
        1.accept, yes按钮被点击
        2.reject, no按钮被点击
        3.checkAndAccept, 选择框和yes按钮被点击
    **/
    signal accept();
    signal reject();
    signal checkAndAccept();

现在我们得到了一个基本的模态框,只是现在还没有加上具体的标题、按钮和内容,以及把信号发送出去的相关逻辑代码。

这是Window现在的样子:


(你可以试着把它运行,但它就躺在那里不会理你)

现在我们需要一些交互代码:


1.实现标题栏


往Window的标题栏中加入一个RowLayout,其中包含2个MouseArea,

一个用于标题栏的文字显示和交互控制,另一个则作为关闭按钮使用。

RowLayout{
    anchors.fill: parent
    spacing: 2
    
    MouseArea{
        id: mouseControler
        
        property point clickPos: "0,0"
        
        Layout.fillHeight: parent
        Layout.fillWidth: parent
        
        //title
        Text{
            text: title
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 5
            anchors.left: parent.left
            anchors.leftMargin: 10
        }
        
        onPressed: {
            clickPos = Qt.point(mouse.x,mouse.y)
        }
        
        onPositionChanged: {
            //鼠标偏移量motai
            var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
            //如果mainwindow继承自QWidget,用setPos
            eo_askDialog.setX(eo_askDialog.x+delta.x)
            eo_askDialog.setY(eo_askDialog.y+delta.y)
        }
    }
    
    //close button
    MouseArea{
        id: closeButton
        Layout.fillHeight: parent
        implicitWidth: 45
        
        Rectangle{
            anchors.fill: parent
            color:"red"
        }
        
        onClicked: {
            console.log("close button clicked.");
            
            eo_askDialog.visible = false;
            reject()
        }
    }
}


这下我们的窗口就能拖动和关闭了!现在该轮到内容框了,

直接添加一个Text到Window的内容框中:

Text{
    text: content
    anchors.centerIn: parent
}

最后则是按钮栏,它和标题栏类似:

RowLayout{
    anchors.fill: parent
    spacing: 2

    //checkBox
    MouseArea{
        id: checkBox
        Layout.fillHeight: parent
        width:100

        Rectangle{
            anchors.fill: parent
            color:"lightgray"
        }

        Text{
            text: checkBoxString
            anchors.centerIn: parent
        }

        onClicked: {
            checked = checked == false
            console.log("checked changed.", checked)
        }
    }

    //h spacer
    Rectangle{
        id: buttonBarSpacer
        color: Qt.rgba(0,0,0,0)
        Layout.fillWidth: parent
    }

    //yes button
    MouseArea{
        id: yesButton
        Layout.fillHeight: parent
        width:75

        Rectangle{
            anchors.fill: parent
            color:"lightgray"
        }

        Text{
            text: yesButtonString
            anchors.centerIn: parent
        }

        onClicked: {
            console.log("yes button clicked.")
            eo_askDialog.visible = false;

            if(checked){
                checkAndAccept()
            }
            else{
                accept()
            }
        }
    }

    //no button
    MouseArea{
        id: noButton
        Layout.fillHeight: parent
        width:75

        Rectangle{
            anchors.fill: parent
            color:"lightgray"
        }

        Text{
            text: noButtonString
            anchors.centerIn: parent
        }

        onClicked: {
            console.log("no button clicked.")
            eo_askDialog.visible = false;

            reject();
        }
    }


}
其中h space 只是一个占位置的框而已,用于把checkbox 和 yes、no 按钮分隔开。


现在我们的框就是这样的:

具有完整的模态框的功能。

要完成背景图片的定制只需要往需要的MouseArea中加入一个Image

并引用Window的中定义的图片路径,并在Image

中添加一下不同的事件切换不同状态的图片的代码就好了

当然你也可以根据自己的需要自行定制



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值