Qt Quick在QML中的弹出层和弹窗

弹出层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import QtQuick.Controls 2.15

// 保存选择的学段
property string selectedSegment
// 创建一个 Popup 组件
Popup {
id: mPop
width: 300
height: 200
modal: true // 设置为模态弹窗
focus: true // 弹窗获得焦点
anchors.centerIn: parent

// 背景颜色
background: Rectangle {
color: "white"
radius: 4
}

Column {
anchors.fill: parent
spacing: 10

ListView {
width:parent.width
height:130
model: segmentModel
clip:true
ScrollBar.vertical: ScrollBar {
Component.onCompleted: {
active = true;
}
}
delegate: Item {
width: parent.width
height: 40
Text {
text: model.text
font.family: "微软雅黑"
anchors.centerIn: parent
color:model.text == selectedSegment?"#339DFF":"#333"
}
MouseArea {
anchors.fill: parent
onClicked: {
selectedSegment = model.text
popup.close()
}
}
}
}

Rectangle {
width:parent.width
height:1
color:"#f3f3f3"
}
// 选择结果
Text {
width:parent.width
height:40
color:"#333"
font.family: "微软雅黑"
text: "已选学段: " + selectedSegment
}
}
}

打开

1
mPop.open()

Toast实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
property string toastMsg   
Popup {
id: mPop

width: toastText.width + 32
height: 40
modal: true // 设置为模态弹窗
focus: true // 弹窗获得焦点
anchors.centerIn: parent

Text {
id: toastText

anchors.centerIn: parent
text: toastMsg
font.family: "微软雅黑"
font.pixelSize: 14
color: "#ffffff"
}

// 背景颜色
background: Rectangle {
color: Qt.rgba(0, 0, 0, 0.5)
radius: 8
}

}

显示Toast

1
2
3
4
5
6
7
8
function onShowToast(msg) {
console.log("onShowToast:" + msg);
toastMsg = msg;
mPop.open();
CommonMethods.delayExecute(2000, this, () => {
mPop.close();
});
}

延迟执行参考

https://www.psvmc.cn/article/2025-01-02-qt-quick-qml-js.html

Dialog

系统自带的弹窗非常丑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

//消息框
Window {
id: control
color: "transparent"

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

property alias showCancel: btn_cancel.visible
property alias showOk: btn_ok.visible
//默认的Text组件的文本值
property string text: "消息提示"
//标题
property alias title: title_text.text

//内容区域Loader加载的组件
property alias content: content_loader.sourceComponent

//标题栏高度
property alias headerHeight: head_area.height
//按钮栏高度
property alias footerHeight: foot_area.height

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 {
anchors.fill: parent
color: "white"
border.color: "lightGray"
clip: true
radius: 8

//用于拖拽对话框
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"
text: "提示"
}
}

Rectangle {
y: headerHeight - 1
color: "#f3f3f3"
width: parent.width
height: 1
}

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

sourceComponent: Text {
color: "#666666"
font.pixelSize: 14
font.family: "Microsoft YaHei"
wrapMode: Text.WrapAnywhere
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: true
text: "取消"
contentItem: Text {
text: parent.text
color: parent.hovered ? "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.hovered ? "#4A6FD3" : "white"
border.color: "#D9D9D9"
border.width: 1
radius: 4
}
onClicked: {
control.hide()
control.clickCancel()
}
}

Button {
id: btn_ok
text: "确认"
visible: true
//默认焦点为确认
focus: true
contentItem: Text {
text: parent.text
color: parent.hovered ? "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.hovered ? "#4A6FD3" : "white"
border.color: "#D9D9D9"
border.width: 1
radius: 4
}
onClicked: {
control.hide()
control.clickOk()
}
}
}
}
}
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 学段数据模型
ListModel {
id: segmentModel
ListElement {
text: "小学"
}
ListElement {
text: "初中"
}
ListElement {
text: "高中"
}
ListElement {
text: "大学"
}
}
// 保存选择的学段
property string selectedSegment

Components.ZDialog {
id: segmentDialog
title: "选择扫描仪"
content: ListView {
width: parent.width
height: 120
model: segmentModel
clip: true
ScrollBar.vertical: ScrollBar {
Component.onCompleted: {
active = true
}
}
delegate: Item {
width: parent.width
height: 40

Rectangle {
anchors.fill: parent
Text {
text: model.text
font.family: "微软雅黑"
anchors.centerIn: parent
color: model.text === selectedSegment ? "#339DFF" : "#333"
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: parent.color = "#f3f3f3"
onExited: parent.color = "transparent"
onClicked: {
selectedSegment = model.text
segmentDialog.close()
}
}
}
}
}
}