环境:qt creator 5.7.0
之前我写过在
qt widgets中自定义messageBox
,感觉在qml文件中使用消息对话框不像qt widgets中那么方便和友好,虽然说qml中有基础组件
MessageDialog
可以调用,但好像不能自定义其样式而显得格格不入,感觉就很鸡肋。于是自己重写了个消息弹窗供大家参考和指正,从而进一步优化。
先看效果图:
至于样式呢就留给大家根据自己的界面风格去添加和优化了,我只提供基础的框架。
实现原理:
消息类型:
首先就是定义消息类型了,比如以下代码就定义了6种消息类型,0x01 << 2表示把1往左移2位,其实就是1变成了4,不懂的去补习语法
property var mb_OK : 0x01 << 2
property var mb_SAVE : 0x01 << 3
property var mb_YES : 0x01 << 4
property var mb_NO : 0x01 << 5
property var mb_CANCEL : 0x01 << 6
property var mb_RELOGIN : 0x01 << 7
动态创建按钮:
不同的消息弹窗可能有不同的按钮组合,当然不能写死了,这就需要在qml中动态创建了。使用
createObject
就可以实现,比如下面代码:
RowLayout{
id:id_layout
}
Component
{
id:id_comp
Button{
property var type: 0x01
onClicked: checkd(type)
}
}
function checkd(_type)
{
root.retValue = _type
root.close()
}
function add_one(type, text){
var obj = id_comp.createObject(id_layout,{"Layout.alignment" : Qt.AlignHCenter, "Layout.preferredWidth" : 60, "Layout.preferredHeight" : 30,"text" : text})
obj.type = type
}
调用add_one函数,传入消息类型type和文本text,然后创建Button控件,点击Button则调用checkd函数,check函数中将消息类型_type赋给弹窗的返回值变量retValue,关闭弹窗后我们会根据这个变量retValue判断用户点击了哪个按钮,是不是感觉有点麻烦?其实并没有,只是简单的逻辑处理罢了,不多说了,直接上代码,毕竟看代码才是我们程序员的喜欢的事情。
新建一个消息框文件CMsgBox.qml
//CMsgBox.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
Window {
id: root
property var mb_OK : 0x01 << 2//0x00000400
property var mb_SAVE : 0x01 << 3//0x00002000
property var mb_YES : 0x01 << 4//0x00004000
property var mb_NO : 0x01 << 5//0x00010000
property var mb_CANCEL : 0x01 << 6//0x0008000
property var mb_RELOGIN : 0x01 << 7
property var message: "" //消息框的消息文本
property var btnType: 0x01 //按钮组合类型
property var retValue: 0x01 //关闭对话框后点击的按钮类型
modality: Qt.ApplicationModal
flags: Qt.FramelessWindowHint | Qt.Window
width: 313
height: 150
color: "transparent"
Rectangle{
anchors.fill: parent
anchors.margins: 4
color: "#23518b"
radius: 5
Item{
id:id_item_header
anchors.left:parent.left
anchors.top:parent.top
anchors.right: parent.right
height: 40
Text {
id: id_img_icon
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 10
text: qsTr("提示")
color: "white"
}
Button {
id: img
text: "x"
anchors.right: parent.right
anchors.rightMargin: 5
anchors.verticalCenter: parent.verticalCenter
width: 30
height: 30
onClicked: checkd(mb_CANCEL)
}
//拖动窗口
MouseArea {
property point clickPos
property bool isPressed: false
anchors.left: parent.left
anchors.top:parent.top
anchors.bottom: parent.bottom
anchors.right: img.left
onPressed: {
isPressed = true
clickPos = Qt.point(mouse.x, mouse.y)
}
onReleased: isPressed = false
onPositionChanged: {
var delta = Qt.point(mouse.x - clickPos.x,
mouse.y - clickPos.y)
var tmpX = root.x + delta.x
var tmpY = root.y + delta.y
if(tmpX + root.width > 25 && Screen.desktopAvailableWidth - tmpX > 25)
root.x = tmpX
if(tmpY + root.height > 25 && Screen.desktopAvailableHeight - tmpY > 25)
root.y = tmpY
}
}
}
Rectangle {
id:id_item_body
anchors.left: parent.left
anchors.top: id_item_header.bottom
anchors.right: parent.right
anchors.bottom: parent.bottom
Keys.onPressed: root.close()
color: "#3568a7"
radius:parent.radius
Item{
id:id_rect_msg
anchors.fill: parent
anchors.bottomMargin: 55
Text {
anchors.fill: parent
anchors.leftMargin: 30
anchors.rightMargin: 30
horizontalAlignment:Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
color: "white"
text: qsTr(message)
}
}
RowLayout{
property var objs: []
id:id_layout
anchors.left: parent.left
anchors.right: parent.right
anchors.top: id_rect_msg.bottom
anchors.bottom: parent.bottom
}
}
}
onBtnTypeChanged: create(root.btnType)
Component
{
id:id_btn_comp
Button{
property var type: 0x01
onClicked: checkd(type)
}
}
function clear()
{
var len = id_layout.objs.length
for(var i=0;i<len;i++)
{
id_layout.objs[i].destroy()
}
id_layout.objs = []
root.btnType = 0x01
}
function checkd(_type)
{
root.retValue = _type
//clear()//可不要,因为对话框关闭后会被销毁释放,单例模式下对话框关闭不会被销毁释放
root.close()
}
function add_one(type,text)
{
var obj = id_btn_comp.createObject(id_layout, {"Layout.alignment" : Qt.AlignHCenter, "Layout.preferredWidth" : 60, "Layout.preferredHeight" : 30,"text" : text})
obj.type = type
//id_layout.objs.push(obj)//可不要,这句是在单例模式下使用的(对话框只创建一次,后面每次打开都更新按钮)
}
function create(type)
{
if((type & root.mb_OK) === root.mb_OK)
{
add_one(root.mb_OK,"ok")
}
if((type & root.mb_SAVE) === root.mb_SAVE)
{
add_one(root.mb_SAVE,"save")
}
if((type & root.mb_YES) === root.mb_YES)
{
add_one(root.mb_YES,"yes")
}
if((type & root.mb_NO) === root.mb_NO)
{
add_one(root.mb_NO,"no")
}
if((type & root.mb_CANCEL) === root.mb_CANCEL)
{
add_one(root.mb_CANCEL,"cancel")
}
if((type & root.mb_RELOGIN) === root.mb_RELOGIN)
{
add_one(root.mb_RELOGIN,"relogin")
}
}
}
/*##^##
Designer {
D{i:0;height:222;width:392}
}
##^##*/
调用方式:
对话框关闭后就
destroy
了,不会占用内存,在接收到消息框的
closing
关闭信号后,我们就在lambda函数
ret
中进行后续处理
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
id:window
visible: true
width: 16 * 50
height: 9 * 50
Button {
anchors.centerIn: parent
text: "show"
onClicked:{
var dia = Qt.createComponent("CMsgBox.qml")
var dlg = dia.createObject(window)
dlg.btnType = dlg.mb_OK | dlg.mb_NO | dlg.mb_CANCEL
dlg.message = "Are you sure?"
dlg.closing.connect(function ret(){
if(dlg.retValue === dlg.mb_YES)
{
//do something
}
else if(dlg.retValue === dlg.mb_NO)
{
//do something
}
else if(dlg.retValue === dlg.mb_CANCEL)
{
//do something
}
dlg.destroy()
})
dlg.show()
}
}
}