1 import QtQuick 2.15
2 import QtQuick.Controls 2.15
3 import QtQuick.Layouts 1.15
4
5 Item {
6 id: root
7 width: 200
8 height: 40
9
10 // 示例数据:支持多层级结构
11 property var subModel: {
12 "水果": {
13 "国产": {
14 "苹果": ["红富士", "蛇果"],
15 "香蕉": ["小米蕉", "皇帝蕉"],
16 "橙子": ["脐橙", "血橙"]
17 },
18 "进口": {
19 "苹果": ["富士", "嘎啦"],
20 "香蕉": ["小香蕉", "大蕉"],
21 "橙子": ["血橙", "普通橙"]
22 }
23 },
24 "蔬菜": {
25 "国产": {
26 "土豆": ["黄心土豆", "紫土豆"],
27 "胡萝卜": ["红胡萝卜", "黄胡萝卜"],
28 "黄瓜": ["旱黄瓜", "水黄瓜"]
29 },
30 "进口": {
31 "土豆": ["外国土豆1", "外国土豆2"],
32 "胡萝卜": ["外国胡萝卜1", "外国胡萝卜2"],
33 "黄瓜": ["外国黄瓜1", "外国黄瓜2"]
34 }
35 },
36 "1": {
37 "A组": {
38 "11": ["111", "112"],
39 "12": ["121", "122"],
40 "13": ["131", "132"]
41 },
42 "B组": {
43 "11": ["211", "212"],
44 "12": ["221", "222"],
45 "13": ["231", "232"]
46 }
47 },
48 "2": {
49 "C组": {
50 "21": ["311", "312"],
51 "22": ["321", "322"],
52 "23": ["331", "332"]
53 },
54 "D组": {
55 "21": ["411", "412"],
56 "22": ["421", "422"],
57 "23": ["431", "432"]
58 }
59 }
60 }
61
62 // 当前选中的菜单项
63 property string selectedSubItem: "设备责任人"
64
65 // 用于存储所有已打开的动态菜单 Popup(索引即层级)
66 property var openMenus: []
67
68 // 关闭从指定层级开始的所有已打开菜单
69 function closeDynamicMenus(level) {
70 for (var i = openMenus.length - 1; i >= level; i--) {
71 if (openMenus[i]) {
72 openMenus[i].close();
73 openMenus[i].destroy();
74 }
75 openMenus.splice(i, 1);
76 }
77 }
78
79 // 在指定层级打开菜单
80 // level:菜单层级(主菜单点击后,子菜单为 1 级,依此类推)
81 // data:当前层级菜单数据
82 // anchor:用于定位 Popup 的参照项
83 function openDynamicMenu(level, data, anchor) {
84 closeDynamicMenus(level);
85 var menu = dynamicMenuComponent.createObject(root, { "menuData": data, "level": level });
86 var pos = anchor.mapToItem(root, anchor.width, 0);
87 menu.x = pos.x;
88 menu.y = pos.y;
89 menu.open();
90 openMenus[level] = menu;
91 }
92
93 // 主按钮:显示当前选中项
94 Rectangle {
95 id: mainButton
96 width: root.width
97 height: root.height
98 color: "lightgray"
99 border.color: "gray"
100 radius: 5
101
102 Text {
103 id: mainText
104 anchors.centerIn: parent
105 text: root.selectedSubItem || "请选择"
106 }
107
108 MouseArea {
109 anchors.fill: parent
110 onClicked: {
111 // 显示主菜单时,关闭所有子菜单
112 mainListView.visible = true;
113 closeDynamicMenus(0);
114 }
115 }
116 }
117
118 // 主菜单 ListView,显示最外层(第一层)的菜单项
119 ListView {
120 id: mainListView
121 visible: false
122 width: root.width
123 x: mainButton.x
124 y: mainButton.y + mainButton.height
125 // 根据内容高度动态调整,但最多200像素
126 height: Math.min(contentHeight, 200)
127 model: Object.keys(root.subModel)
128 delegate: Item {
129 width: mainListView.width
130 height: root.height
131 RowLayout {
132 anchors.fill: parent
133 spacing: 0
134 // 左侧显示菜单文本
135 Rectangle {
136 id: mainTextRect
137 Layout.preferredWidth: parent.width * 0.75
138 height: parent.height
139 color: "lightgray"
140 Text {
141 anchors.centerIn: parent
142 text: modelData
143 verticalAlignment: Text.AlignVCenter
144 padding: 10
145 }
146 MouseArea {
147 anchors.fill: parent
148 onClicked: {
149 var childData = root.subModel[modelData];
150 if (childData !== undefined &&
151 ((Array.isArray(childData) && childData.length > 0) ||
152 (typeof childData === "object" && Object.keys(childData).length > 0))) {
153 // 存在子菜单,打开下一级菜单(level 1)
154 // openDynamicMenu(1, childData, mainTextRect);
155 root.selectedSubItem = modelData;
156 mainText.text = modelData;
157 mainListView.visible = false;
158 closeDynamicMenus(0);
159
160 } else {
161 // 叶子节点:更新选中并关闭所有菜单
162 root.selectedSubItem = modelData;
163 mainText.text = modelData;
164 mainListView.visible = false;
165 closeDynamicMenus(0);
166 }
167 }
168 }
169 }
170 // 右侧显示箭头:如果存在子菜单则显示 "▶",否则为空
171 Rectangle {
172 id: mainArrowRect
173 Layout.preferredWidth: parent.width * 0.25
174 height: parent.height
175 color: "lightgray"
176 Text {
177 anchors.centerIn: parent
178 color: "green"
179 text: {
180 var childData = root.subModel[modelData];
181 if (childData !== undefined &&
182 ((Array.isArray(childData) && childData.length > 0) ||
183 (typeof childData === "object" && Object.keys(childData).length > 0))) {
184 return "▶";
185 }
186 return "";
187 }
188 }
189 MouseArea {
190 anchors.fill: parent
191 onClicked: {
192 var childData = root.subModel[modelData];
193 if (childData !== undefined &&
194 ((Array.isArray(childData) && childData.length > 0) ||
195 (typeof childData === "object" && Object.keys(childData).length > 0))) {
196 openDynamicMenu(1, childData, mainArrowRect);
197 }
198 }
199 }
200 }
201 }
202 }
203 }
204
205 // 通用动态菜单 Popup 组件,用于构造任意层级的子菜单
206 Component {
207 id: dynamicMenuComponent
208 Popup {
209 id: dynPopup
210 // 当前层级菜单数据(可以是数组或对象)
211 property var menuData
212 // 当前菜单层级,主菜单点击后生成的菜单 level 为 1,依次递增
213 property int level: 0
214 width: root.width*0.75
215 padding: 1
216 height: Math.min(listView.contentHeight, 200)
217 background: Rectangle {
218 color: "#ffffff"
219 border.color: "#cccccc"
220 radius: 5
221 }
222 ListView {
223 id: listView
224 anchors.fill: parent
225 model: (typeof dynPopup.menuData === "object" && !Array.isArray(dynPopup.menuData))
226 ? Object.keys(dynPopup.menuData)
227 : dynPopup.menuData
228 delegate: Item {
229 width: listView.width
230 height: root.height
231 RowLayout {
232 anchors.fill: parent
233 spacing: 0
234 Layout.margins: 0
235 // 左侧显示菜单项文本
236 Rectangle {
237 id: dynTextRect
238 Layout.fillWidth: true
239 Layout.preferredWidth: parent.width * 0.75
240 height: parent.height
241 color: "lightgray"
242 Text {
243 anchors.centerIn: parent
244 text: modelData
245 verticalAlignment: Text.AlignVCenter
246 padding: 10
247 }
248 MouseArea {
249 anchors.fill: parent
250 onClicked: {
251 var childData;
252 if (typeof dynPopup.menuData === "object" && !Array.isArray(dynPopup.menuData)) {
253 childData = dynPopup.menuData[modelData];
254 }
255 if (childData !== undefined &&
256 ((Array.isArray(childData) && childData.length > 0) ||
257 (typeof childData === "object" && Object.keys(childData).length > 0))) {
258 // 存在下一级子菜单,打开下一层
259 // root.openDynamicMenu(dynPopup.level + 1, childData, dynTextRect);
260 root.selectedSubItem = modelData;
261 mainText.text = modelData;
262 mainListView.visible = false;
263 root.closeDynamicMenus(0);
264 } else {
265 // 叶子节点:更新选中并关闭所有菜单
266 root.selectedSubItem = modelData;
267 mainText.text = modelData;
268 mainListView.visible = false;
269 root.closeDynamicMenus(0);
270 }
271 }
272 }
273 }
274 // 右侧箭头,若存在子菜单则显示,否则为空
275 Rectangle {
276 id: dynArrowRect
277 Layout.fillWidth: true
278 Layout.preferredWidth: parent.width * 0.25
279 height: parent.height
280 color: "lightgray"
281 Text {
282 anchors.centerIn: parent
283 color: "green"
284 text: {
285 var childData;
286 if (typeof dynPopup.menuData === "object" && !Array.isArray(dynPopup.menuData)) {
287 childData = dynPopup.menuData[modelData];
288 }
289 if (childData !== undefined &&
290 ((Array.isArray(childData) && childData.length > 0) ||
291 (typeof childData === "object" && Object.keys(childData).length > 0))) {
292 return "▶";
293 }
294 return "";
295 }
296 }
297 MouseArea {
298 anchors.fill: parent
299 onClicked: {
300 var childData;
301 if (typeof dynPopup.menuData === "object" && !Array.isArray(dynPopup.menuData)) {
302 childData = dynPopup.menuData[modelData];
303 }
304 if (childData !== undefined &&
305 ((Array.isArray(childData) && childData.length > 0) ||
306 (typeof childData === "object" && Object.keys(childData).length > 0))) {
307 root.openDynamicMenu(dynPopup.level + 1, childData, dynArrowRect);
308 }
309 }
310 }
311 }
312 }
313 }
314 }
315 }
316 }
317 }