treeviewmanager.cpp 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434
  1. #include "treeviewmanager.h"
  2. #include "OriginalWnd.h" // 包含 OriginalWnd 的定义
  3. // 构造函数
  4. TreeViewManager::TreeViewManager(OriginalWnd* originalWnd, QWidget *widget2, QWidget *parent)
  5. : QWidget(parent),
  6. widget2(widget2),
  7. treeViewDown(new QTreeView(widget2)),
  8. m_originalWnd(originalWnd),
  9. navigationWidget(nullptr),
  10. buttonOpenFile(nullptr),
  11. buttonUp(nullptr),
  12. buttonDown(nullptr),
  13. buttonLeft(nullptr),
  14. buttonRight(nullptr),
  15. restoring(false)
  16. {
  17. if (!widget2) {
  18. qWarning() << "TreeViewManager: widget2 未初始化";
  19. return;
  20. }
  21. // 初始化目录树模型
  22. downModel = new QStandardItemModel(this);
  23. treeViewDown->setModel(downModel);
  24. // 给 viewport() 安装事件过滤器,以便拦截其 Paint 事件
  25. treeViewDown->viewport()->installEventFilter(this);
  26. // 应用样式表
  27. applyCustomStyles();
  28. treeViewDown->setHeaderHidden(true); // 显示头部
  29. treeViewDown->setGeometry(16, 106, widget2->width()-16, widget2->height() - 106);
  30. treeViewDown->setEditTriggers(QAbstractItemView::NoEditTriggers);
  31. treeViewDown->show();
  32. // 使用统一的分隔线创建函数
  33. QFrame *lineFrame1 = createUnifiedSeparator(widget2, 2);
  34. lineFrame1->setGeometry(16, 89, 428, 2); // 位置和大小
  35. lineFrame1->show();
  36. qDebug() << "widget2 geometry:" << widget2->geometry();
  37. qDebug() << "treeViewDown geometry:" << treeViewDown->geometry();
  38. // 创建按钮并设置布局
  39. setupButton();
  40. // 创建导航栏
  41. navigationWidget = new QWidget(widget2);
  42. navigationWidget->setGeometry(15, 15, 300, 74);
  43. navigationLayout = new QVBoxLayout(navigationWidget);
  44. navigationLayout->setContentsMargins(0, 0, 0, 0);
  45. navigationLayout->setSpacing(0);
  46. navigationWidget->show();
  47. // 更新导航栏位置
  48. updateNavigationWidgetGeometry();
  49. // 连接信号与槽
  50. connect(downModel, &QStandardItemModel::itemChanged, this, &TreeViewManager::onItemChanged);
  51. // 目录树连接点击信号
  52. connect(treeViewDown, &QTreeView::clicked, this, [=](const QModelIndex &index) {
  53. QStandardItem *item = downModel->itemFromIndex(index);
  54. if (!item) return;
  55. // 仅在非恢复状态下记录选中路径
  56. if (!restoring) {
  57. QStringList path = buildItemPath(item);
  58. addVisitedPath(path);
  59. }
  60. QVariant data = item->data(Qt::UserRole);
  61. if (data.canConvert<QJsonObject>()) {
  62. QJsonObject fields = data.toJsonObject();
  63. if (fields.contains("isThirdLevel") && fields["isThirdLevel"].toBool()) {
  64. qDebug() << "加载三级目录字段内容:" << fields;
  65. // 更新导航栏
  66. updateNavigationBar(index);
  67. // 显示三级目录字段内容
  68. displayThirdLevelFields(fields);
  69. treeViewDown->hide(); // 隐藏 treeViewDown
  70. // 调用 updateSeparatorLine 以隐藏分割线
  71. updateSeparatorLine();
  72. return;
  73. }
  74. }
  75. // 即使是非三级目录,也更新导航栏
  76. updateNavigationBar(index);
  77. qDebug() << "更新导航栏,目录项:" << item->text();
  78. });
  79. // 连接 expanded 和 collapsed 信号
  80. connect(treeViewDown, &QTreeView::expanded, this, [=](const QModelIndex &index) {
  81. QStandardItem *item = downModel->itemFromIndex(index);
  82. if (!item) return;
  83. QStringList path = buildItemPath(item);
  84. addExpandedPath(path);
  85. updateSeparatorLine();
  86. });
  87. connect(treeViewDown, &QTreeView::collapsed, this, [=](const QModelIndex &index) {
  88. QStandardItem *item = downModel->itemFromIndex(index);
  89. if (!item) return;
  90. QStringList path = buildItemPath(item);
  91. removeExpandedPath(path);
  92. updateSeparatorLine();
  93. });
  94. // 加载并展开上次访问过的路径
  95. loadVisitedPaths();
  96. QTimer::singleShot(0, this, [=]() {
  97. QStandardItem *rootItem = downModel->invisibleRootItem();
  98. QStandardItem *thirdItem = findFirstThirdLevelItemDFS(rootItem);
  99. if (thirdItem) {
  100. QJsonObject thirdLevelObj = thirdItem->data(Qt::UserRole).toJsonObject();
  101. if (thirdLevelObj.contains("isThirdLevel") && thirdLevelObj["isThirdLevel"].toBool()) {
  102. loadButtonConfigForThirdLevel(thirdLevelObj);
  103. }
  104. }
  105. });
  106. connect(buttonOpenFile, &QPushButton::clicked, this, &TreeViewManager::onButtonOpenFileClicked);
  107. connect(buttonUp, &QPushButton::clicked, this, &TreeViewManager::onButtonUpClicked);
  108. connect(buttonDown, &QPushButton::clicked, this, &TreeViewManager::onButtonDownClicked);
  109. connect(buttonLeft, &QPushButton::clicked, this, &TreeViewManager::onButtonLeftClicked);
  110. connect(buttonRight, &QPushButton::clicked, this, &TreeViewManager::onButtonRightClicked);
  111. // 确保在加载完成后更新横线
  112. QTimer::singleShot(0, this, &TreeViewManager::updateSeparatorLine);
  113. }
  114. TreeViewManager::~TreeViewManager()
  115. {
  116. // 在析构时,保存当前状态(展开/选中)
  117. saveVisitedPaths();
  118. }
  119. void TreeViewManager::clearAllSeparators()
  120. {
  121. // 隐藏并删除所有分割线
  122. for (auto separator : firstLevelSeparators.values()) {
  123. if (separator) {
  124. separator->hide();
  125. separator->deleteLater(); // 如果想完全删除,可用 deleteLater
  126. }
  127. }
  128. firstLevelSeparators.clear(); // 清空map
  129. }
  130. QStandardItem* TreeViewManager::findFirstThirdLevelItemDFS(QStandardItem *parentItem)
  131. {
  132. if (!parentItem) {
  133. return nullptr;
  134. }
  135. // 遍历当前 parentItem 的所有子
  136. for (int i = 0; i < parentItem->rowCount(); ++i) {
  137. QStandardItem *child = parentItem->child(i);
  138. if (!child) continue;
  139. // 检查这个子节点是否是三级目录
  140. QVariant data = child->data(Qt::UserRole);
  141. if (data.canConvert<QJsonObject>()) {
  142. QJsonObject obj = data.toJsonObject();
  143. if (obj.contains("isThirdLevel") && obj["isThirdLevel"].toBool()) {
  144. // 找到第一个 isThirdLevel = true 的节点就返回
  145. return child;
  146. }
  147. }
  148. // 如果不是 isThirdLevel,继续往子节点里找
  149. QStandardItem* deeperFound = findFirstThirdLevelItemDFS(child);
  150. if (deeperFound) {
  151. return deeperFound;
  152. }
  153. }
  154. return nullptr;
  155. }
  156. // 递归更新子项状态
  157. void TreeViewManager::updateChildItems(QStandardItem *parentItem, Qt::CheckState state)
  158. {
  159. if (!parentItem)
  160. return;
  161. qDebug() << "Updating child items of:" << parentItem->text() << "to state:" << state;
  162. for (int i = 0; i < parentItem->rowCount(); ++i)
  163. {
  164. QStandardItem *child = parentItem->child(i);
  165. if (child)
  166. {
  167. child->setCheckState(state);
  168. // 递归更新子项
  169. updateChildItems(child, state);
  170. }
  171. }
  172. }
  173. // 收集所有被选中的复选框路径
  174. QStringList TreeViewManager::collectCheckedPathsRecursive(QStandardItem *item, QStringList path)
  175. {
  176. QStringList checkedList;
  177. if (!item) {
  178. item = downModel->invisibleRootItem();
  179. }
  180. for (int i = 0; i < item->rowCount(); ++i) {
  181. QStandardItem *child = item->child(i);
  182. if (child) {
  183. QStringList currentPath = path;
  184. currentPath << child->text();
  185. if (child->checkState() == Qt::Checked) {
  186. checkedList << currentPath.join("/");
  187. }
  188. // 递归收集子项
  189. checkedList << collectCheckedPathsRecursive(child, currentPath);
  190. }
  191. }
  192. return checkedList;
  193. }
  194. // 无参数版本的 collectCheckedPaths 函数定义
  195. QStringList TreeViewManager::collectCheckedPaths()
  196. {
  197. return collectCheckedPathsRecursive(downModel->invisibleRootItem(), QStringList());
  198. }
  199. // // 根据路径设置复选框状态
  200. // void TreeViewManager::setCheckedPaths(const QStringList &checkedPathsList)
  201. // {
  202. // for (const QString &pathStr : checkedPathsList) {
  203. // QStringList path = pathStr.split("/");
  204. // QModelIndex idx = findItemByPath(path);
  205. // if (idx.isValid()) {
  206. // QStandardItem *item = downModel->itemFromIndex(idx);
  207. // if (item) {
  208. // item->setCheckState(Qt::Checked);
  209. // visitedPaths.insert(pathStr);
  210. // qDebug() << "设置复选框为选中:" << pathStr;
  211. // }
  212. // } else {
  213. // qDebug() << "未找到路径部分:" << pathStr;
  214. // }
  215. // }
  216. // }
  217. void TreeViewManager::setCheckedPaths(const QStringList &checkedPathsList)
  218. {
  219. qDebug() << "Setting checked paths:" << checkedPathsList;
  220. m_blockItemChanged = true; // Block signals
  221. qDebug() << "setCheckedPaths: m_blockItemChanged set to true";
  222. for (const QString &pathStr : checkedPathsList) {
  223. QStringList path = pathStr.split("/");
  224. QModelIndex idx = findItemByPath(path);
  225. if (idx.isValid()) {
  226. QStandardItem *item = downModel->itemFromIndex(idx);
  227. if (item) {
  228. qDebug() << " - Setting item:" << item->text() << "to Checked";
  229. item->setCheckState(Qt::Checked);
  230. visitedPaths.insert(pathStr);
  231. qDebug() << "Added visited path:" << pathStr;
  232. }
  233. } else {
  234. qDebug() << "Path not found:" << pathStr;
  235. }
  236. }
  237. m_blockItemChanged = false; // Unblock signals
  238. qDebug() << "setCheckedPaths: m_blockItemChanged set to false";
  239. }
  240. // 保存复选框状态
  241. void TreeViewManager::saveCheckedPaths()
  242. {
  243. if (currentConfigFilePath.isEmpty()) {
  244. qWarning() << "当前配置文件路径为空,无法保存复选框状态。";
  245. return;
  246. }
  247. QSettings settings("RunCloudTech", "David");
  248. QString configKey = currentConfigKey(currentConfigFilePath);
  249. settings.beginGroup("TreeViewCheckedState");
  250. // 保存选中路径
  251. QString keyChecked = QString("checkedPaths/%1").arg(configKey);
  252. QStringList checkedList = collectCheckedPaths();
  253. settings.setValue(keyChecked, checkedList);
  254. settings.endGroup();
  255. qDebug() << "保存复选框状态路径:" << checkedList;
  256. }
  257. // 加载复选框状态
  258. void TreeViewManager::loadCheckedPaths()
  259. {
  260. if (currentConfigFilePath.isEmpty()) {
  261. qWarning() << "当前配置文件路径为空,无法加载复选框状态。";
  262. return;
  263. }
  264. QSettings settings("RunCloudTech", "David");
  265. QString configKey = currentConfigKey(currentConfigFilePath);
  266. settings.beginGroup("TreeViewCheckedState");
  267. // Read checked paths
  268. QString keyChecked = QString("checkedPaths/%1").arg(configKey);
  269. QStringList loadedChecked = settings.value(keyChecked).toStringList();
  270. settings.endGroup();
  271. qDebug() << "加载复选框状态路径:" << loadedChecked;
  272. m_blockItemChanged = true;
  273. qDebug() << "loadCheckedPaths: m_blockItemChanged set to true";
  274. setCheckedPaths(loadedChecked);
  275. m_blockItemChanged = false;
  276. qDebug() << "loadCheckedPaths: m_blockItemChanged set to false";
  277. }
  278. void TreeViewManager::onItemChanged(QStandardItem *item)
  279. {
  280. qDebug() << "onItemChanged called for item:" << item->text();
  281. qDebug() << "Flags - m_blockItemChanged:" << m_blockItemChanged << ", restoring:" << restoring;
  282. if (m_blockItemChanged || restoring) {
  283. qDebug() << "Exiting onItemChanged due to flags.";
  284. return; // 防止递归和恢复期间触发
  285. }
  286. m_blockItemChanged = true;
  287. qDebug() << "Processing item:" << item->text();
  288. Qt::CheckState state = item->checkState();
  289. // 更新所有子项的复选框状态
  290. updateChildItems(item, state);
  291. // 更新所有父项的复选框状态
  292. updateParentItems(item->parent());
  293. m_blockItemChanged = false;
  294. // 如果不在恢复模式下,记录被选中的路径
  295. if (!restoring) {
  296. QStringList path = buildItemPath(item);
  297. if (state == Qt::Checked) {
  298. addVisitedPath(path);
  299. } else {
  300. // 如果需要在取消选中时执行某些操作,例如从 visitedPaths 中移除
  301. QString joinedPath = path.join("/");
  302. if (visitedPaths.contains(joinedPath)) {
  303. visitedPaths.remove(joinedPath);
  304. qDebug() << "移除选中路径:" << joinedPath;
  305. }
  306. }
  307. // 记录复选框状态
  308. saveCheckedPaths();
  309. }
  310. }
  311. //更新所有父项的复选框状态
  312. void TreeViewManager::updateParentItems(QStandardItem *parentItem)
  313. {
  314. if (!parentItem)
  315. return;
  316. int checkedCount = 0;
  317. int totalCount = parentItem->rowCount();
  318. qDebug() << "Updating child items of:" ;
  319. for (int i = 0; i < totalCount; ++i)
  320. {
  321. QStandardItem *child = parentItem->child(i);
  322. if (child && child->checkState() == Qt::Checked)
  323. {
  324. checkedCount++;
  325. }
  326. }
  327. if (checkedCount == totalCount)
  328. {
  329. parentItem->setCheckState(Qt::Checked);
  330. }
  331. else
  332. {
  333. parentItem->setCheckState(Qt::Unchecked);
  334. }
  335. // 递归更新上层父项
  336. updateParentItems(parentItem->parent());
  337. }
  338. //创建横线样式
  339. QFrame* TreeViewManager::createUnifiedSeparator(QWidget *parent, int height)
  340. {
  341. QFrame *separator = new QFrame(parent);
  342. separator->setFrameShape(QFrame::NoFrame); // 移除默认框架
  343. separator->setFixedHeight(height); // 设置固定高度
  344. separator->setStyleSheet("background-color: #C7CAEB;"); // 设置背景颜色
  345. separator->hide(); // 根据需要初始化为隐藏
  346. qDebug() << "创建统一分隔符 QFrame,父级:" << parent;
  347. return separator;
  348. }
  349. // 目录树的横线
  350. void TreeViewManager::updateSeparatorLine() {
  351. // 检查 treeViewDown 是否可见
  352. if (!treeViewDown->isVisible()) {
  353. // 隐藏所有横线
  354. for (auto separator : firstLevelSeparators) {
  355. if (separator)
  356. separator->hide();
  357. }
  358. return;
  359. }
  360. // 遍历记录的一级目录
  361. for (auto it = firstLevelSeparators.begin(); it != firstLevelSeparators.end(); ++it) {
  362. QStandardItem *firstLevelItem = it.key();
  363. QFrame *separator = it.value();
  364. if (!firstLevelItem || !separator) continue;
  365. QModelIndex firstLevelIndex = downModel->indexFromItem(firstLevelItem);
  366. QRect firstLevelRect = treeViewDown->visualRect(firstLevelIndex);
  367. if (!firstLevelRect.isValid()) {
  368. separator->hide();
  369. continue;
  370. }
  371. if (treeViewDown->isExpanded(firstLevelIndex) && firstLevelItem->hasChildren()) {
  372. // 找到最后一个可见子目录
  373. QModelIndex lastVisibleChild = findLastVisibleChild(firstLevelIndex);
  374. if (lastVisibleChild.isValid()) {
  375. QRect lastChildRect = treeViewDown->visualRect(lastVisibleChild);
  376. if (lastChildRect.isValid()) {
  377. // 将横线放置在最后一个子目录下方
  378. separator->setGeometry(16, lastChildRect.bottom() + 105, widget2->width() - 32, 2);
  379. separator->show();
  380. } else {
  381. // 如果子目录不可见,则将横线放在一级目录下方
  382. separator->setGeometry(16, firstLevelRect.bottom() + 105, widget2->width() - 32, 2);
  383. separator->show();
  384. }
  385. } else {
  386. // 没有可见子目录,则放在一级目录下方
  387. separator->setGeometry(16, firstLevelRect.bottom() + 105, widget2->width() - 32, 2);
  388. separator->show();
  389. }
  390. } else {
  391. // 一级目录收起,横线直接在下方
  392. separator->setGeometry(16, firstLevelRect.bottom() + 105, widget2->width() - 32, 2);
  393. separator->show();
  394. }
  395. }
  396. }
  397. // 分割线 找到最后一个可见子项
  398. QModelIndex TreeViewManager::findLastVisibleChild(const QModelIndex &parentIndex) {
  399. if (!parentIndex.isValid()) return QModelIndex();
  400. int childCount = downModel->rowCount(parentIndex);
  401. QModelIndex lastVisibleChild;
  402. for (int i = childCount - 1; i >= 0; --i) {
  403. QModelIndex childIndex = downModel->index(i, 0, parentIndex);
  404. if (!treeViewDown->isRowHidden(i, parentIndex)) { // 确保子项未被隐藏
  405. if (treeViewDown->isExpanded(childIndex) && downModel->rowCount(childIndex) > 0) {
  406. QModelIndex deeperChild = findLastVisibleChild(childIndex);
  407. if (deeperChild.isValid()) {
  408. return deeperChild;
  409. }
  410. }
  411. lastVisibleChild = childIndex;
  412. break; // 找到最后一个可见子项后退出循环
  413. }
  414. }
  415. return lastVisibleChild;
  416. }
  417. QString TreeViewManager::currentConfigKey(const QString &configFilePath)
  418. {
  419. // 使用文件名作为唯一标识符
  420. QFileInfo fileInfo(configFilePath);
  421. QString key = fileInfo.fileName();
  422. qDebug() << "Generated config key:" << key;
  423. return key;
  424. }
  425. void TreeViewManager::saveVisitedPaths()
  426. {
  427. if (currentConfigFilePath.isEmpty()) {
  428. qWarning() << "当前配置文件路径为空,无法保存复选框状态。";
  429. return;
  430. }
  431. QSettings settings("RunCloudTech", "David");
  432. QString configKey = currentConfigKey(currentConfigFilePath);
  433. settings.beginGroup("TreeViewState");
  434. // 保存选中路径
  435. QString keyVisited = QString("visitedPaths/%1").arg(configKey);
  436. QStringList visitedList(visitedPaths.begin(), visitedPaths.end());
  437. settings.setValue(keyVisited, visitedList);
  438. // 保存展开路径
  439. QString keyExpanded = QString("expandedPaths/%1").arg(configKey);
  440. QStringList expandedList(expandedPaths.begin(), expandedPaths.end());
  441. settings.setValue(keyExpanded, expandedList);
  442. settings.endGroup();
  443. qDebug() << "保存选中路径:" << visitedList;
  444. qDebug() << "保存展开路径:" << expandedList;
  445. // 调用保存复选框状态
  446. saveCheckedPaths();
  447. }
  448. void TreeViewManager::loadVisitedPaths()
  449. {
  450. if (currentConfigFilePath.isEmpty()) {
  451. qWarning() << "当前配置文件路径为空,无法加载访问路径。";
  452. return;
  453. }
  454. QSettings settings("RunCloudTech", "David");
  455. QString configKey = currentConfigKey(currentConfigFilePath);
  456. settings.beginGroup("TreeViewState");
  457. // 读取选中路径
  458. QString keyVisited = QString("visitedPaths/%1").arg(configKey);
  459. QStringList loadedVisited = settings.value(keyVisited).toStringList();
  460. // 读取展开路径
  461. QString keyExpanded = QString("expandedPaths/%1").arg(configKey);
  462. QStringList loadedExpanded = settings.value(keyExpanded).toStringList();
  463. settings.endGroup();
  464. qDebug() << "加载选中路径:" << loadedVisited;
  465. qDebug() << "加载展开路径:" << loadedExpanded;
  466. restoring = true; // 进入恢复模式
  467. // 恢复展开路径
  468. for (const QString &p : loadedExpanded) {
  469. QStringList path = p.split("/");
  470. QModelIndex idx = findItemByPath(path);
  471. if (idx.isValid()) {
  472. treeViewDown->expand(idx);
  473. expandedPaths.insert(p); // 重新插入
  474. qDebug() << "成功恢复展开路径:" << p;
  475. } else {
  476. qDebug() << "未找到展开路径部分: " << p;
  477. }
  478. }
  479. // 恢复选中路径
  480. for (const QString &p : loadedVisited) {
  481. QStringList path = p.split("/");
  482. QModelIndex idx = findItemByPath(path);
  483. if (idx.isValid()) {
  484. QStandardItem *item = downModel->itemFromIndex(idx);
  485. if (item) {
  486. item->setCheckState(Qt::Checked);
  487. visitedPaths.insert(p);
  488. qDebug() << "成功恢复选中路径:" << p;
  489. }
  490. } else {
  491. qDebug() << "未找到选中路径部分: " << p;
  492. }
  493. }
  494. // 恢复复选框状态
  495. loadCheckedPaths();
  496. restoring = false; // 退出恢复模式
  497. // 更新导航栏
  498. if (!loadedVisited.isEmpty()) {
  499. QString lastPathStr = loadedVisited.last();
  500. QStringList lastPath = lastPathStr.split("/");
  501. QModelIndex lastIdx = findItemByPath(lastPath);
  502. if (lastIdx.isValid()) {
  503. treeViewDown->setCurrentIndex(lastIdx);
  504. updateNavigationBar(lastIdx);
  505. }
  506. } else {
  507. // 如果没有加载到任何路径,自动选择第一个目录
  508. QStandardItem *rootItem = downModel->invisibleRootItem();
  509. if (rootItem->rowCount() > 0) {
  510. QModelIndex firstIndex = downModel->index(0, 0, QModelIndex());
  511. if (firstIndex.isValid()) {
  512. treeViewDown->setCurrentIndex(firstIndex);
  513. updateNavigationBar(firstIndex);
  514. treeViewDown->expand(firstIndex); // 展开第一个目录
  515. QStandardItem *firstItem = downModel->itemFromIndex(firstIndex);
  516. QVariant data = firstItem->data(Qt::UserRole);
  517. if (data.canConvert<QJsonObject>()) {
  518. QJsonObject thirdLevelObj = data.toJsonObject();
  519. if (thirdLevelObj.contains("isThirdLevel") && thirdLevelObj["isThirdLevel"].toBool()) {
  520. loadButtonConfigForThirdLevel(thirdLevelObj);
  521. }
  522. }
  523. }
  524. }
  525. }
  526. // 使用 singleShot 确保在所有展开操作完成后更新分隔线
  527. QTimer::singleShot(0, this, &TreeViewManager::updateSeparatorLine);
  528. }
  529. /**
  530. * @brief 记录选中的路径
  531. * @param path 节点路径列表
  532. */
  533. void TreeViewManager::addVisitedPath(const QStringList &path)
  534. {
  535. QString joined = path.join("/");
  536. if (!visitedPaths.contains(joined)) {
  537. visitedPaths.insert(joined);
  538. qDebug() << "记录[选中]路径:" << joined;
  539. }
  540. }
  541. /**
  542. * @brief 记录展开的路径
  543. * @param path 节点路径列表
  544. */
  545. void TreeViewManager::addExpandedPath(const QStringList &path)
  546. {
  547. QString joined = path.join("/");
  548. if (!expandedPaths.contains(joined)) {
  549. expandedPaths.insert(joined);
  550. qDebug() << "记录[展开]路径:" << joined;
  551. }
  552. }
  553. /**
  554. * @brief 移除展开的路径
  555. * @param path 节点路径列表
  556. */
  557. void TreeViewManager::removeExpandedPath(const QStringList &path)
  558. {
  559. QString joinedPath = path.join("/");
  560. if (expandedPaths.contains(joinedPath)) {
  561. expandedPaths.remove(joinedPath);
  562. qDebug() << "移除展开路径:" << joinedPath;
  563. }
  564. }
  565. /**
  566. * @brief 构建节点的完整路径
  567. * @param item 当前节点
  568. * @return 节点路径列表
  569. */
  570. QStringList TreeViewManager::buildItemPath(QStandardItem *item)
  571. {
  572. QStringList path;
  573. QStandardItem *currentItem = item;
  574. while (currentItem) {
  575. path.prepend(currentItem->text());
  576. currentItem = currentItem->parent();
  577. }
  578. return path;
  579. }
  580. /**
  581. * @brief 根据路径查找对应的节点
  582. * @param path 节点路径列表
  583. * @return 节点的 QModelIndex
  584. */
  585. QModelIndex TreeViewManager::findItemByPath(const QStringList &path)
  586. {
  587. if (path.isEmpty()) return QModelIndex();
  588. QStandardItem *currentItem = downModel->invisibleRootItem();
  589. QModelIndex currentIndex;
  590. for (const QString &part : path) {
  591. bool found = false;
  592. for (int i = 0; i < currentItem->rowCount(); ++i) {
  593. QStandardItem *child = currentItem->child(i);
  594. if (child->text() == part) {
  595. currentIndex = downModel->indexFromItem(child);
  596. currentItem = child;
  597. found = true;
  598. break;
  599. }
  600. }
  601. if (!found) {
  602. qWarning() << "未找到路径部分:" << part;
  603. return QModelIndex();
  604. }
  605. }
  606. return currentIndex;
  607. }
  608. bool TreeViewManager::eventFilter(QObject *watched, QEvent *event)
  609. {
  610. // 只拦截 treeViewDown->viewport() 的 Paint 事件
  611. if (watched == treeViewDown->viewport() && event->type() == QEvent::Paint)
  612. {
  613. // 第1步:让 QTreeView 先进行默认绘制 (文字、图标等)
  614. // 这样可以把“树节点”都画出来
  615. bool handled = QWidget::eventFilter(watched, event);
  616. // 第2步:在同一个绘制周期里,使用 QPainter 叠加画“拐角线”
  617. QPainter painter(treeViewDown->viewport());
  618. if (!painter.isActive()) {
  619. qWarning() << "Painter not active";
  620. return handled;
  621. }
  622. painter.save();
  623. painter.setPen(QPen(Qt::gray, 1, Qt::DashLine)); // 灰色、1px 宽、虚线
  624. // 调用一个递归或遍历函数,把所有节点的父->子线、兄弟延续竖线都画上
  625. paintAllBranches(QModelIndex(), painter);
  626. painter.restore();
  627. // 返回 handled 或 true 均可,通常返回 handled 即可
  628. return handled;
  629. }
  630. // 其余事件交给父类默认处理
  631. return QWidget::eventFilter(watched, event);
  632. }
  633. void TreeViewManager::paintAllBranches(const QModelIndex &parentIndex, QPainter &painter)
  634. {
  635. int rowCount = downModel->rowCount(parentIndex);
  636. for(int i = 0; i < rowCount; ++i)
  637. {
  638. // 当前子节点
  639. QModelIndex childIndex = downModel->index(i, 0, parentIndex);
  640. if (!childIndex.isValid()) continue;
  641. // 1) 父->子拐角线
  642. drawParentChildLine(childIndex, painter);
  643. // 2) 兄弟延续竖线(如果本节点不是最后一个兄弟,就在拐点列画条向下的线)
  644. if (i < rowCount - 1) {
  645. drawSiblingLine(childIndex, painter);
  646. }
  647. // 3) 递归处理子节点
  648. paintAllBranches(childIndex, painter);
  649. }
  650. }
  651. /**
  652. * @brief 在“父节点 -> 子节点”间画一条“L”型拐角线,仅调整横向线段的长度
  653. */
  654. void TreeViewManager::drawParentChildLine(const QModelIndex &childIndex, QPainter &painter)
  655. {
  656. QModelIndex parentIndex = childIndex.parent();
  657. if (!parentIndex.isValid()) {
  658. // 说明是“顶层节点”
  659. // 定义一个固定的起点 (rootX, rootY)
  660. int indent = treeViewDown->indentation();
  661. int depth = 0; // 顶层节点深度为0
  662. int branchX = (depth + 1) * indent - indent / 2; // 计算 branchX 基于缩进和深度
  663. // 定义 rootY 为节点中心 Y
  664. QRect childRect = treeViewDown->visualRect(childIndex);
  665. if (!childRect.isValid())
  666. return;
  667. int rootY = childRect.center().y();
  668. // 定义横向偏移量
  669. const int hOffset = -20; // 根据需求调整
  670. // 绘制竖线: 从 (branchX, rootY) 到 (branchX, childRect.center().y())
  671. painter.drawLine(QPoint(branchX, rootY),
  672. QPoint(branchX, childRect.center().y()));
  673. // 计算新的横线终点
  674. int newX = childRect.left() + hOffset;
  675. // 绘制横线: 从 (branchX, childRect.center().y()) 到 (newX, childRect.center().y())
  676. painter.drawLine(QPoint(branchX, childRect.center().y()),
  677. QPoint(newX, childRect.center().y()));
  678. return;
  679. }
  680. QRect parentRect = treeViewDown->visualRect(parentIndex);
  681. QRect childRect = treeViewDown->visualRect(childIndex);
  682. if (!parentRect.isValid() || !childRect.isValid()) {
  683. // 父或子可能超出可视区域
  684. return;
  685. }
  686. int pMidY = parentRect.center().y();
  687. int cMidY = childRect.center().y();
  688. // 计算节点深度
  689. int depth = 0;
  690. QModelIndex p = parentIndex;
  691. while (p.isValid()) {
  692. depth++;
  693. p = p.parent();
  694. }
  695. int indent = treeViewDown->indentation();
  696. int branchX = depth * indent - indent / 2;
  697. // 确保 branchX 不超出视图范围
  698. branchX = std::max(branchX, 0);
  699. // 定义横向偏移量
  700. const int hOffset = -15; // 根据需求调整
  701. // 绘制竖线: 从 (branchX, pMidY) 到 (branchX, cMidY)
  702. painter.drawLine(QPoint(branchX, pMidY), QPoint(branchX, cMidY));
  703. // 计算新的横线终点
  704. int newX = childRect.left() + hOffset;
  705. // 绘制横线: 从 (branchX, cMidY) 到 (newX, cMidY)
  706. painter.drawLine(QPoint(branchX, cMidY), QPoint(newX, cMidY));
  707. }
  708. /**
  709. * @brief 若本节点下面还有兄弟,则在拐点列那里继续往下画竖线
  710. */
  711. void TreeViewManager::drawSiblingLine(const QModelIndex &childIndex, QPainter &painter)
  712. {
  713. QModelIndex parentIndex = childIndex.parent();
  714. if (!parentIndex.isValid()) {
  715. return; // 没有父节点
  716. }
  717. // 下一个兄弟
  718. int row = childIndex.row();
  719. int lastRow = downModel->rowCount(parentIndex) - 1;
  720. if (row >= lastRow) {
  721. return; // 说明是最后一个兄弟,不用画延伸线
  722. }
  723. QModelIndex nextSibling = downModel->index(row + 1, 0, parentIndex);
  724. QRect currRect = treeViewDown->visualRect(childIndex);
  725. QRect nextRect = treeViewDown->visualRect(nextSibling);
  726. if (!currRect.isValid() || !nextRect.isValid()) {
  727. return;
  728. }
  729. // 计算节点深度
  730. int depth = 0;
  731. QModelIndex p = parentIndex;
  732. while (p.isValid()) {
  733. depth++;
  734. p = p.parent();
  735. }
  736. int indent = treeViewDown->indentation();
  737. int branchX = depth * indent - indent / 2;
  738. // 确保 branchX 不超出视图范围
  739. branchX = std::max(branchX, 0);
  740. // 从当前节点底部向下延伸到下一个兄弟节点顶部
  741. int startY = currRect.bottom();
  742. int endY = nextRect.top();
  743. painter.drawLine(QPoint(branchX, startY), QPoint(branchX, endY));
  744. }
  745. // 一次性读取 configPaths 里的所有 JSON 文件并解析好,存到 m_configCache
  746. void TreeViewManager::preloadAllConfigs(const QStringList &configPaths)
  747. {
  748. m_configCache.clear(); // 先清空
  749. for (const QString &path : configPaths) {
  750. QFile file(path);
  751. if (!file.exists()) {
  752. qWarning() << "preloadAllConfigs: JSON 文件不存在:" << path;
  753. continue;
  754. }
  755. if (!file.open(QIODevice::ReadOnly)) {
  756. qWarning() << "preloadAllConfigs: 无法打开 JSON 文件:" << path;
  757. continue;
  758. }
  759. QByteArray data = file.readAll();
  760. file.close();
  761. QJsonDocument doc = QJsonDocument::fromJson(data);
  762. if (doc.isNull() || !doc.isObject()) {
  763. qWarning() << "preloadAllConfigs: JSON 文件格式错误:" << path;
  764. continue;
  765. }
  766. // 以 fileName 作为 key,比如 "home_config.json"
  767. QString key = QFileInfo(path).fileName();
  768. m_configCache.insert(key, doc);
  769. qDebug() << "preloadAllConfigs: 已缓存配置文件" << key;
  770. }
  771. }
  772. // void TreeViewManager::switchConfig(const QString &configKey)
  773. // {
  774. // // 先保存当前配置的状态
  775. // saveVisitedPaths();
  776. // // 检查 configKey 是否存在于缓存中
  777. // if (!m_configCache.contains(configKey)) {
  778. // qWarning() << "switchConfig: 未找到 configKey =" << configKey << ",无法切换";
  779. // return;
  780. // }
  781. // // 获取对应的 QJsonDocument
  782. // QJsonDocument doc = m_configCache.value(configKey);
  783. // // 1) 清理上一个配置产生的横线
  784. // clearAllSeparators();
  785. // // 加载新的 JSON 配置
  786. // loadJsonDoc(doc, configKey);
  787. // }
  788. void TreeViewManager::switchConfig(const QString &configKey)
  789. {
  790. qDebug() << "切换配置文件到:" << configKey;
  791. // 先保存当前配置的状态
  792. saveVisitedPaths();
  793. // 检查 configKey 是否存在于缓存中
  794. if (!m_configCache.contains(configKey)) {
  795. qWarning() << "switchConfig: 未找到 configKey =" << configKey << ",无法切换";
  796. return;
  797. }
  798. // 获取对应的 QJsonDocument
  799. QJsonDocument doc = m_configCache.value(configKey);
  800. // 1) 清理上一个配置产生的横线
  801. clearAllSeparators();
  802. // 2) 隐藏三级目录菜单内容
  803. clearThirdLevelMenu();
  804. // 3) 加载新的 JSON 配置
  805. loadJsonDoc(doc, configKey);
  806. }
  807. void TreeViewManager::clearThirdLevelMenu()
  808. {
  809. qDebug() << "清理并隐藏三级目录菜单内容";
  810. // 遍历所有子控件,找到标题为 "字段展示" 的窗口并关闭
  811. foreach (QObject *child, widget2->children()) {
  812. QWidget *childWidget = qobject_cast<QWidget*>(child);
  813. if (childWidget && childWidget->windowTitle() == "字段展示") {
  814. qDebug() << "关闭现有的字段展示窗口";
  815. childWidget->close();
  816. }
  817. }
  818. // 显示主目录树和分隔线
  819. treeViewDown->show();
  820. for (auto separator : firstLevelSeparators) {
  821. separator->show();
  822. }
  823. }
  824. void TreeViewManager::loadJsonDoc(const QJsonDocument &doc, const QString &configFilePath)
  825. {
  826. // 1) 更新 currentConfigFilePath
  827. currentConfigFilePath = configFilePath;
  828. m_blockItemChanged = true;
  829. qDebug() << "Loading JSON config, m_blockItemChanged set to true";
  830. // 清空
  831. downModel->clear();
  832. firstLevelSeparators.clear();
  833. visitedPaths.clear();
  834. expandedPaths.clear();
  835. // 3) 构建树
  836. if (!doc.isObject()) {
  837. qWarning() << "loadJsonDoc: doc 不是对象结构";
  838. return;
  839. }
  840. QJsonObject rootObj = doc.object();
  841. buildTree(rootObj, downModel->invisibleRootItem());
  842. // 强制刷新
  843. //treeViewDown->reset();
  844. // 5) 恢复 记忆路径 + 复选框状态
  845. loadVisitedPaths();
  846. m_blockItemChanged = false;
  847. qDebug() << "Finished loading JSON config, m_blockItemChanged set to false";
  848. // // 6) 自动选择第一个目录并更新导航栏
  849. // QStandardItem *rootItem = downModel->invisibleRootItem();
  850. // if (rootItem->rowCount() > 0) {
  851. // QModelIndex firstIndex = downModel->index(0, 0, QModelIndex());
  852. // if (firstIndex.isValid()) {
  853. // treeViewDown->setCurrentIndex(firstIndex);
  854. // updateNavigationBar(firstIndex);
  855. // treeViewDown->expand(firstIndex); // 展开第一个目录
  856. // QStandardItem *firstItem = downModel->itemFromIndex(firstIndex);
  857. // QVariant data = firstItem->data(Qt::UserRole);
  858. // if (data.canConvert<QJsonObject>()) {
  859. // QJsonObject thirdLevelObj = data.toJsonObject();
  860. // if (thirdLevelObj.contains("isThirdLevel") && thirdLevelObj["isThirdLevel"].toBool()) {
  861. // loadButtonConfigForThirdLevel(thirdLevelObj);
  862. // }
  863. // }
  864. // }
  865. // }
  866. qDebug() << "[DEBUG] loadJsonDoc 完成,对应 configKey =" << configFilePath;
  867. }
  868. //目录树样式
  869. void TreeViewManager::applyCustomStyles() {
  870. treeViewDown->setStyleSheet(R"(
  871. /* 设置分支图标大小 */
  872. QTreeView::branch:closed:has-children {
  873. border-image: none;
  874. image: url(:/images/home_add.png);
  875. }
  876. QTreeView::branch:open:has-children {
  877. border-image: none;
  878. image: url(:/images/home_minus.png);
  879. }
  880. /* 设置多选框大小 */
  881. QTreeView::indicator:unchecked {
  882. image: url(:/images/home_NotSelecte.png);
  883. }
  884. QTreeView::indicator:checked {
  885. image: url(:/images/home_selected.png);
  886. }
  887. /* 背景透明,行间距 */
  888. QTreeView {
  889. background: transparent;
  890. border: none;
  891. }
  892. /* 设置项目选中的背景色 */
  893. QTreeView::item:selected {
  894. background-color: #A9B4FF;
  895. }
  896. /* 设置项目的行间距 */
  897. QTreeView::item {
  898. padding-top: 5px; /* 上边距 */
  899. padding-bottom: 5px; /* 下边距 */
  900. }
  901. )");
  902. }
  903. //加载的 JSON 数据
  904. void TreeViewManager::loadTreeData(const QJsonDocument &doc)
  905. {
  906. if (!doc.isObject()) {
  907. qWarning() << "无效的 JSON 结构";
  908. return;
  909. }
  910. qDebug() << "加载的 JSON 数据:" << doc.toJson();
  911. buildTree(doc.object(), downModel->invisibleRootItem());
  912. }
  913. //构建目录树
  914. void TreeViewManager::buildTree(const QJsonObject &jsonObj, QStandardItem *parent)
  915. {
  916. for (auto it = jsonObj.begin(); it != jsonObj.end(); ++it) {
  917. // 跳过不需要的字段
  918. if (it.key() == "isThirdLevel" || it.key() == "separator" || it.key() == "buttons") {
  919. continue;
  920. }
  921. QStandardItem *item = new QStandardItem(it.key());
  922. item->setCheckable(true); // 添加多选框
  923. item->setCheckState(Qt::Unchecked); // 默认状态为未选中
  924. parent->appendRow(item);
  925. qDebug() << "创建目录项:" << it.key();
  926. if (it.value().isObject()) {
  927. QJsonObject childObj = it.value().toObject();
  928. if (childObj.contains("isThirdLevel") && childObj["isThirdLevel"].toBool()) {
  929. // 是三级目录,存储整个对象到 UserRole
  930. item->setData(childObj, Qt::UserRole);
  931. qDebug() << "目录项为三级目录:" << it.key();
  932. }
  933. else {
  934. // 递归处理二级目录
  935. buildTree(childObj, item);
  936. }
  937. }
  938. // 如果是一级目录,检查是否需要创建分隔线
  939. if (parent == downModel->invisibleRootItem()) {
  940. QJsonObject currentObj = it.value().toObject();
  941. bool hasSeparator = currentObj.contains("separator") && currentObj["separator"].toBool();
  942. if (hasSeparator) {
  943. QFrame *separator = createUnifiedSeparator(widget2, 2);
  944. separator->hide(); // 初始隐藏
  945. firstLevelSeparators.insert(item, separator);
  946. qDebug() << "为一级目录创建统一分隔线:" << it.key();
  947. }
  948. }
  949. }
  950. // 在所有子项添加完成后,更新父项的复选框状态
  951. if (parent != downModel->invisibleRootItem()) {
  952. updateParentItems(parent);
  953. }
  954. }
  955. // 更新导航栏位置和大小
  956. void TreeViewManager::updateNavigationWidgetGeometry()
  957. {
  958. // 设置导航栏的宽度和高度
  959. int navWidth = 300; // 固定宽度为 300 像素
  960. int navHeight = 74; // 固定高度为 74 像素
  961. // 设置导航栏的左上角位置
  962. int navLeft = 15; // 距离 widget2 左边 15 像素
  963. int navTop = 15; // 距离 widget2 顶部 15 像素
  964. // 设置导航栏的几何位置
  965. navigationWidget->setGeometry(navLeft, navTop, navWidth, navHeight);
  966. // 如果需要,刷新组件
  967. navigationWidget->update();
  968. qDebug() << "Updated navigationWidget geometry:"
  969. << navigationWidget->geometry();
  970. }
  971. //导航栏动态更新
  972. void TreeViewManager::updateNavigationBar(const QModelIndex &index)
  973. {
  974. // 0) 如果当前 index 无效,尝试从 QSettings 读取“上次导航路径”并恢复
  975. if (!index.isValid()) {
  976. qWarning() << "updateNavigationBar(): 当前 index 无效,尝试从 QSettings 恢复上次导航";
  977. QSettings settings("RunCloudTech", "David");
  978. settings.beginGroup("TreeViewNav");
  979. QStringList lastNavPath = settings.value("lastNavPath").toStringList();
  980. settings.endGroup();
  981. if (!lastNavPath.isEmpty()) {
  982. // 找到对应的节点索引
  983. QModelIndex savedIndex = findItemByPath(lastNavPath);
  984. if (savedIndex.isValid()) {
  985. qDebug() << "成功从 QSettings 恢复导航路径:" << lastNavPath
  986. << ",对应项:" << downModel->itemFromIndex(savedIndex)->text();
  987. // 再次调用本函数,更新导航栏
  988. updateNavigationBar(savedIndex);
  989. } else {
  990. qWarning() << "QSettings 里存的路径无法找到对应节点,无法恢复。";
  991. }
  992. } else {
  993. qWarning() << "QSettings 里没有存任何导航路径,或为空。";
  994. }
  995. return;
  996. }
  997. QStandardItem *item = downModel->itemFromIndex(index);
  998. if (!item) {
  999. qWarning() << "导航栏更新失败:未找到对应项";
  1000. return;
  1001. }
  1002. qDebug() << "导航栏更新,目录项:" << item->text();
  1003. // 如果导航栏已有布局,先清理
  1004. if (navigationWidget->layout()) {
  1005. QLayoutItem *child;
  1006. while ((child = navigationWidget->layout()->takeAt(0)) != nullptr) {
  1007. if (child->widget()) {
  1008. child->widget()->deleteLater();
  1009. }
  1010. delete child;
  1011. }
  1012. delete navigationWidget->layout();
  1013. }
  1014. // 构建路径列表,从当前项回溯到根节点
  1015. QList<QStandardItem *> path;
  1016. QStandardItem *temp = item;
  1017. while (temp) {
  1018. if (temp->text() != "isThirdLevel") { // 排除 "isThirdLevel" 标识
  1019. path.prepend(temp); // 从根节点开始
  1020. }
  1021. temp = temp->parent();
  1022. }
  1023. qDebug() << "导航路径:" << [path]() {
  1024. QStringList pathNames;
  1025. for (QStandardItem *p : path) {
  1026. pathNames.append(p->text());
  1027. }
  1028. return pathNames.join(" -> ");
  1029. }();
  1030. // 创建新的导航栏布局
  1031. QVBoxLayout *newLayout = new QVBoxLayout;
  1032. newLayout->setContentsMargins(0, 0, 0, 0);
  1033. newLayout->setSpacing(0);
  1034. // 确保始终显示三行
  1035. for (int i = 0; i < 3; ++i) {
  1036. QLabel *label = new QLabel;
  1037. if (i < path.size()) {
  1038. QString text = path[i]->text();
  1039. if (i == 1) text = " " + text; // 一级目录缩进
  1040. if (i == 2) text = " " + text; // 二级/三级目录缩进
  1041. label->setText(text);
  1042. } else {
  1043. label->setText(""); // 填充空白行
  1044. }
  1045. // 设置字体和样式
  1046. QFont font = label->font();
  1047. font.setPointSize(12);
  1048. label->setFont(font);
  1049. label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
  1050. label->setFixedHeight(navigationWidget->height() / 3);
  1051. newLayout->addWidget(label);
  1052. }
  1053. // 设置布局并更新导航栏
  1054. navigationWidget->setLayout(newLayout);
  1055. navigationWidget->update();
  1056. qDebug() << "导航栏更新完成:" << path.size() << "项";
  1057. //当前路径存到 QSettings,供下次启动恢复
  1058. QStringList pathStrings;
  1059. for (QStandardItem *p : path) {
  1060. pathStrings << p->text();
  1061. }
  1062. QSettings settings("RunCloudTech", "David");
  1063. settings.beginGroup("TreeViewNav");
  1064. settings.setValue("lastNavPath", pathStrings);
  1065. settings.endGroup();
  1066. qDebug() << "已将当前导航路径写入 QSettings:" << pathStrings;
  1067. }
  1068. /**
  1069. * @brief 加载并显示三级目录的按钮配置信息
  1070. * @param thirdLevelObj 三级目录的 JSON 对象
  1071. */
  1072. void TreeViewManager::loadButtonConfigForThirdLevel(const QJsonObject &thirdLevelObj)
  1073. {
  1074. if (!m_originalWnd) {
  1075. qWarning() << "OriginalWnd 指针为空,无法加载按钮配置";
  1076. return;
  1077. }
  1078. if (!thirdLevelObj.contains("buttons")) {
  1079. qWarning() << "三级目录配置中不包含 'buttons' 字段";
  1080. return;
  1081. }
  1082. QJsonArray buttonsArray = thirdLevelObj.value("buttons").toArray();
  1083. if (buttonsArray.size() != 12) {
  1084. qWarning() << "按钮数量不是12个,实际数量:" << buttonsArray.size();
  1085. // 根据需求选择是否继续处理
  1086. }
  1087. // 获取 widget_left
  1088. QWidget* widgetLeft = m_originalWnd->getWidgetLeft();
  1089. if (!widgetLeft) {
  1090. qWarning() << "无法访问 widget_left";
  1091. return;
  1092. }
  1093. // 清空 widget_left 中由 loadButtonConfigForThirdLevel 创建的按钮
  1094. QList<QPushButton*> existingButtons = widgetLeft->findChildren<QPushButton*>();
  1095. for (QPushButton* button : existingButtons) {
  1096. if (button->objectName().startsWith("thirdLevelBtn_")) { // 仅删除特定按钮
  1097. button->deleteLater();
  1098. }
  1099. }
  1100. // 使用绝对定位创建按钮
  1101. for (int i = 0; i < buttonsArray.size() && i < 12; ++i) {
  1102. QJsonObject buttonObj = buttonsArray[i].toObject();
  1103. QString buttonId = buttonObj.value("id").toString();
  1104. QString buttonIcon = buttonObj.value("icon").toString();
  1105. QString buttonText = buttonObj.value("text").toString();
  1106. bool isEnabled = buttonObj.value("enabled").toBool();
  1107. // 创建按钮
  1108. QPushButton *button = new QPushButton(widgetLeft);
  1109. button->setObjectName("thirdLevelBtn_" + buttonId); // 设置带前缀的对象名称
  1110. //设置按钮的样式,调整图标和文本的位置
  1111. button->setStyleSheet(R"(
  1112. QPushButton {
  1113. position: absolute;
  1114. border-radius: 6px;
  1115. opacity: 1;
  1116. background: #CBD0FF;
  1117. border: none;
  1118. }
  1119. QPushButton:hover {
  1120. background-color: #A9B4FF; /* 鼠标悬停效果 */
  1121. }
  1122. )");
  1123. // 设置按钮的位置和大小
  1124. int x = 16;
  1125. int y = 245 + i * (48 + 13); // 第一个按钮 y=245,后续每个按钮间隔13px
  1126. button->setGeometry(x, y, 158, 48);
  1127. // 设置按钮的可见性,根据 "enabled" 字段显示或隐藏按钮
  1128. button->setVisible(isEnabled); // 如果 isEnabled 为 false,则隐藏按钮
  1129. // 创建图标标签
  1130. QLabel *iconLabel = new QLabel(button);
  1131. iconLabel->setPixmap(QIcon(buttonIcon).pixmap(16, 16));
  1132. iconLabel->setGeometry(10, 16, 16, 16); // 图标距离左边10px,顶部16px
  1133. iconLabel->setFixedSize(16, 16);
  1134. iconLabel->setStyleSheet("background-color: transparent;");
  1135. iconLabel->setVisible(isEnabled); // 根据按钮的可见性设置图标的可见性
  1136. // 创建文本标签
  1137. QLabel *textLabel = new QLabel(buttonText, button);
  1138. textLabel->setGeometry(34, 0, 90, 48); // 文本距离左边34px,占用剩余空间
  1139. textLabel->setWordWrap(true); // 允许换行
  1140. textLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
  1141. //textLabel->setStyleSheet("background-color: transparent;");
  1142. textLabel->setStyleSheet(R"(
  1143. QLabel {
  1144. background: transparent;
  1145. font-family: "思源黑体";
  1146. font-size: 14px;
  1147. font-weight: 500;
  1148. color: #4E51CE;
  1149. }
  1150. )");
  1151. textLabel->setVisible(isEnabled); // 根据按钮的可见性设置文本的可见性
  1152. // 创建 F1-F12 标签
  1153. QString fLabelText = QString("F%1").arg(i + 1); // F1, F2, ..., F12
  1154. QLabel *fLabel = new QLabel(fLabelText, button);
  1155. fLabel->setFixedSize(21, 16); // 设置大小为21x16
  1156. fLabel->setAlignment(Qt::AlignCenter);
  1157. fLabel->setStyleSheet(R"(
  1158. QLabel {
  1159. background-color: transparent;
  1160. color: #2A7ED8;
  1161. font-size: 12px;
  1162. font-weight: bold;
  1163. }
  1164. )");
  1165. // 设置标签的位置
  1166. int fX = 134;
  1167. int fY = 2;
  1168. fLabel->setGeometry(fX, fY, 14, 16);
  1169. fLabel->setVisible(isEnabled); // 根据按钮的可见性设置标签的可见性
  1170. qDebug() << "创建按钮:" << buttonId << ", 文本:" << buttonText << ", 图标:" << buttonIcon << ", 启用:" << isEnabled;
  1171. }
  1172. }
  1173. //三级目录字段窗口
  1174. void TreeViewManager::displayThirdLevelFields(const QJsonObject &fields)
  1175. {
  1176. if (fields.isEmpty()) {
  1177. qWarning() << "字段数据为空,无法显示";
  1178. return;
  1179. }
  1180. qDebug() << "显示的字段数据:" << fields;
  1181. // 检查是否为三级目录
  1182. if (!fields.contains("isThirdLevel") || !fields["isThirdLevel"].toBool()) {
  1183. qWarning() << "不是三级目录,跳过按钮加载";
  1184. return;
  1185. }
  1186. // 隐藏目录树
  1187. treeViewDown->hide();
  1188. // 隐藏所有横线
  1189. for (auto separator : firstLevelSeparators) {
  1190. separator->hide();
  1191. }
  1192. // 加载按钮配置
  1193. loadButtonConfigForThirdLevel(fields);
  1194. // 1. 检查是否已存在字段窗口,防止重复创建
  1195. foreach (QObject *child, widget2->children()) {
  1196. QWidget *childWidget = qobject_cast<QWidget*>(child);
  1197. if (childWidget && childWidget->windowTitle() == "字段展示") {
  1198. qDebug() << "字段窗口已存在,关闭旧窗口";
  1199. childWidget->close();
  1200. }
  1201. }
  1202. // 2. 创建一个新的 “字段展示” 窗口
  1203. QWidget *fieldWindow = new QWidget(widget2);
  1204. fieldWindow->setWindowTitle("字段展示");
  1205. fieldWindow->setGeometry(treeViewDown->geometry());
  1206. // -- 2.1 创建一个滚动区域 QScrollArea
  1207. QScrollArea *scrollArea = new QScrollArea(fieldWindow);
  1208. scrollArea->setWidgetResizable(true); // 内容自适应大小
  1209. scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 保留水平滚动条
  1210. qDebug() << "QScrollArea 已创建,水平滚动条策略设置为 ScrollBarAsNeeded";
  1211. // -- 2.2 创建滚动容器 scrollWidget,并设置垂直布局
  1212. QWidget *scrollWidget = new QWidget;
  1213. scrollWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); // 宽度跟随父窗口
  1214. QVBoxLayout *scrollLayout = new QVBoxLayout(scrollWidget);
  1215. scrollLayout->setSpacing(10); // 字段的垂直间距
  1216. scrollLayout->setContentsMargins(10, 10, 10, 10); // 减少边距
  1217. // 3. 遍历 JSON 中的字段,生成控件
  1218. for (auto it = fields.begin(); it != fields.end(); ++it) {
  1219. QString fieldName = it.key();
  1220. if (fieldName == "isThirdLevel") {
  1221. continue; // 跳过 isThirdLevel 字段
  1222. }
  1223. if (fieldName == "buttons") {
  1224. continue; // 跳过 buttons 字段
  1225. }
  1226. QJsonObject fieldConfig = it.value().toObject();
  1227. QString fieldType = fieldConfig["type"].toString();
  1228. qDebug() << "处理字段:" << fieldName << "类型:" << fieldType;
  1229. // 每个字段一行:Label在左,控件在右
  1230. QHBoxLayout *fieldLayout = new QHBoxLayout;
  1231. fieldLayout->setSpacing(5); // 减少每行的水平间距
  1232. // (1)左侧:字段名 (最小宽度,固定高度24px,左对齐)
  1233. QLabel *label = new QLabel(fieldName);
  1234. label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
  1235. label->setFixedHeight(24); // 高度为24px
  1236. label->setMinimumWidth(120); // 减少最小宽度,允许根据内容自动调整
  1237. fieldLayout->addWidget(label);
  1238. // 在中间插入弹性伸缩,使后面的控件靠右
  1239. fieldLayout->addStretch(1);
  1240. // (2)右侧:根据 fieldType 创建相应控件
  1241. QWidget *rightWidget = new QWidget;
  1242. QHBoxLayout *rightLayout = new QHBoxLayout(rightWidget);
  1243. rightLayout->setContentsMargins(0, 0, 0, 0); // 移除右侧边距
  1244. rightLayout->setSpacing(5); // 减少控件之间的间距
  1245. if (fieldType == "input") {
  1246. // 创建 QLineEdit 输入框
  1247. QLineEdit *lineEdit = new QLineEdit(fieldConfig["value"].toString());
  1248. lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 水平方向扩展
  1249. lineEdit->setFixedHeight(28); // 减少高度
  1250. lineEdit->setAlignment(Qt::AlignLeft); // 输入框左对齐
  1251. lineEdit->setStyleSheet(R"(
  1252. QLineEdit {
  1253. background: #FFFFFF;
  1254. border: 1px solid #BABBDC;
  1255. border-radius: 6px;
  1256. padding: 2px 5px;
  1257. }
  1258. )");
  1259. rightLayout->addWidget(lineEdit);
  1260. qDebug() << "添加输入框:" << fieldName;
  1261. } else if (fieldType == "radio") {
  1262. // 创建一组 QRadioButton 单选框
  1263. QHBoxLayout *radioLayout = new QHBoxLayout;
  1264. radioLayout->setSpacing(5); // 减少单选按钮之间的间距
  1265. QButtonGroup *radioGroup = new QButtonGroup(rightWidget);
  1266. QString currentValue = fieldConfig["value"].toString();
  1267. QJsonArray options = fieldConfig["options"].toArray();
  1268. for (const QJsonValue &option : options) {
  1269. QRadioButton *radioButton = new QRadioButton(option.toString());
  1270. // 使用默认样式,无需自定义样式表
  1271. if (option.toString() == currentValue) {
  1272. radioButton->setChecked(true);
  1273. }
  1274. radioGroup->addButton(radioButton);
  1275. radioLayout->addWidget(radioButton);
  1276. qDebug() << "添加单选按钮:" << option.toString();
  1277. }
  1278. rightLayout->addLayout(radioLayout);
  1279. } else if (fieldType == "checkbox") {
  1280. // 创建 QCheckBox 复选框(仅显示复选框,不显示文字)
  1281. QCheckBox *checkBox = new QCheckBox;
  1282. checkBox->setChecked(fieldConfig["value"].toBool());
  1283. // 应用指定的样式,使用默认的勾标记
  1284. checkBox->setStyleSheet(R"(
  1285. QCheckBox::indicator {
  1286. width: 20px;
  1287. height: 20px;
  1288. }
  1289. QCheckBox::indicator:unchecked {
  1290. background-color: #FFFFFF;
  1291. border: 1px solid #4E51CE;
  1292. border-radius: 4px;
  1293. }
  1294. QCheckBox::indicator:checked {
  1295. image: url(:/images/check_selected.png);
  1296. border: 1px solid #FFFFFF;
  1297. border-radius: 4px;
  1298. }
  1299. QCheckBox {
  1300. /* 取消显示文本 */
  1301. spacing: 0px;
  1302. }
  1303. )");
  1304. // 直接将 QCheckBox 添加到 rightLayout,不添加任何标签
  1305. rightLayout->addWidget(checkBox);
  1306. qDebug() << "添加复选框:" << fieldName;
  1307. } else if (fieldType == "dropdown") {
  1308. // 创建 QComboBox 下拉框
  1309. QComboBox *comboBox = new QComboBox;
  1310. comboBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // 固定宽度
  1311. comboBox->setFixedSize(120, 28); // 减少宽度和高度
  1312. comboBox->setStyleSheet(R"(
  1313. QComboBox {
  1314. background: #FFFFFF;
  1315. border: 1px solid #BABBDC;
  1316. border-radius: 6px;
  1317. padding: 2px 5px;
  1318. }
  1319. QComboBox::drop-down {
  1320. width: 20px;
  1321. }
  1322. )");
  1323. QJsonArray options = fieldConfig["options"].toArray();
  1324. for (const QJsonValue &option : options) {
  1325. comboBox->addItem(option.toString());
  1326. }
  1327. comboBox->setCurrentText(fieldConfig["value"].toString());
  1328. rightLayout->addWidget(comboBox);
  1329. qDebug() << "添加下拉框:" << fieldName;
  1330. } else if (fieldType == "time") {
  1331. // 创建 QTimeEdit 时间选择框
  1332. QTimeEdit *timeEdit = new QTimeEdit;
  1333. timeEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // 固定宽度
  1334. timeEdit->setFixedSize(120, 28); // 减少宽度和高度
  1335. timeEdit->setStyleSheet(R"(
  1336. QTimeEdit {
  1337. background: #FFFFFF;
  1338. border: 1px solid #BABBDC;
  1339. border-radius: 6px;
  1340. padding: 2px 5px;
  1341. }
  1342. )");
  1343. timeEdit->setDisplayFormat("HH:mm:ss");
  1344. timeEdit->setTime(QTime::fromString(fieldConfig["value"].toString(), "HH:mm:ss"));
  1345. rightLayout->addWidget(timeEdit);
  1346. qDebug() << "添加时间选择框:" << fieldName;
  1347. } else if (fieldType == "switch") {
  1348. // 创建 QCheckBox 开关控件,并添加文字标签“开”和“关”
  1349. QWidget *switchContainer = new QWidget;
  1350. QHBoxLayout *switchLayout = new QHBoxLayout(switchContainer);
  1351. switchLayout->setSpacing(5); // 减少开关和标签之间的间距
  1352. switchLayout->setContentsMargins(0, 0, 0, 0);
  1353. QCheckBox *switchBox = new QCheckBox;
  1354. switchBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1355. switchBox->setFixedSize(30, 30); // 调整开关大小
  1356. switchBox->setStyleSheet(R"(
  1357. QCheckBox::indicator {
  1358. width: 30px;
  1359. height: 30px;
  1360. }
  1361. QCheckBox::indicator:unchecked {
  1362. background-color: #BABBDC;
  1363. border-radius: 6px;
  1364. }
  1365. QCheckBox::indicator:checked {
  1366. background-color: #4CAF50;
  1367. border-radius: 6px;
  1368. }
  1369. )");
  1370. // 设置初始状态
  1371. QString switchValue = fieldConfig["value"].toString();
  1372. if (switchValue == "on") {
  1373. switchBox->setChecked(true);
  1374. } else {
  1375. switchBox->setChecked(false);
  1376. }
  1377. // 添加文字标签
  1378. QLabel *switchLabel = new QLabel(switchBox->isChecked() ? "开" : "关");
  1379. switchLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
  1380. switchLabel->setStyleSheet("font-size: 14px;"); // 可选:调整字体大小
  1381. // 连接开关状态改变信号以更新标签文字
  1382. connect(switchBox, &QCheckBox::stateChanged, [switchLabel](int state){
  1383. if (state == Qt::Checked) {
  1384. switchLabel->setText("开");
  1385. } else {
  1386. switchLabel->setText("关");
  1387. }
  1388. });
  1389. switchLayout->addWidget(switchBox);
  1390. switchLayout->addWidget(switchLabel);
  1391. rightLayout->addWidget(switchContainer);
  1392. qDebug() << "添加开关控件和标签:" << fieldName;
  1393. } else if (fieldType == "combined") {
  1394. // 组合控件(包含 QLineEdit 和两个 QToolButton)
  1395. QJsonObject combinedValue = fieldConfig["value"].toObject();
  1396. // 确保必要的字段存在
  1397. if (!combinedValue.contains("inputValue") ||
  1398. !combinedValue.contains("moduleButton") ||
  1399. !combinedValue.contains("axisButton")) {
  1400. qWarning() << "组合控件的 value 字段不完整:" << fieldName;
  1401. continue;
  1402. }
  1403. QLineEdit *comboInput = new QLineEdit(combinedValue["inputValue"].toString());
  1404. comboInput->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 水平方向扩展
  1405. comboInput->setFixedHeight(28); // 减少高度
  1406. comboInput->setStyleSheet(R"(
  1407. QLineEdit {
  1408. background: #FFFFFF;
  1409. border: 1px solid #BABBDC;
  1410. border-radius: 5px;
  1411. padding: 2px 5px;
  1412. }
  1413. )");
  1414. qDebug() << "添加组合控件的输入框:" << fieldName;
  1415. // 创建一个容器 widget 来包含组合控件
  1416. QWidget *combinedWidget = new QWidget;
  1417. QHBoxLayout *combinedLayout = new QHBoxLayout(combinedWidget);
  1418. combinedLayout->setSpacing(5); // 减少控件之间的间距
  1419. combinedLayout->setContentsMargins(0, 0, 0, 0);
  1420. // “模组” QToolButton
  1421. QToolButton *moduleButton = new QToolButton(combinedWidget); // 设置父级
  1422. moduleButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1423. moduleButton->setFixedSize(80, 28); // 调整按钮大小
  1424. moduleButton->setStyleSheet(R"(
  1425. QToolButton {
  1426. background: #FFFFFF;
  1427. border: 1px solid #BABBDC;
  1428. border-radius: 5px;
  1429. padding: 0px; /* 移除默认内边距 */
  1430. text-align: center; /* 使文本居中 */
  1431. }
  1432. QToolButton::menu-indicator {
  1433. image: none;
  1434. }
  1435. QToolButton::checked {
  1436. background: #4CAF50; /* 高亮颜色 */
  1437. }
  1438. /* 强制文本居中 */
  1439. QToolButton::hover {
  1440. qproperty-textAlignment: 'AlignCenter';
  1441. }
  1442. )");
  1443. moduleButton->setText("模组");
  1444. moduleButton->setCheckable(true);
  1445. moduleButton->setPopupMode(QToolButton::InstantPopup);
  1446. // “轴向” QToolButton
  1447. QToolButton *axisButton = new QToolButton(combinedWidget); // 设置父级
  1448. axisButton->setObjectName("axisButton"); // 为轴向按钮设置对象名以便查找
  1449. axisButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1450. axisButton->setFixedSize(80, 28); // 调整按钮大小
  1451. axisButton->setStyleSheet(R"(
  1452. QToolButton {
  1453. background: #FFFFFF;
  1454. border: 1px solid #BABBDC;
  1455. border-radius: 5px;
  1456. padding: 0px; /* 移除默认内边距 */
  1457. text-align: center; /* 使文本居中 */
  1458. }
  1459. QToolButton::menu-indicator {
  1460. image: none;
  1461. }
  1462. QToolButton::checked {
  1463. background: #4CAF50; /* 高亮颜色 */
  1464. }
  1465. /* 强制文本居中 */
  1466. QToolButton::hover {
  1467. qproperty-textAlignment: 'AlignCenter';
  1468. }
  1469. )");
  1470. axisButton->setText("轴向");
  1471. axisButton->setCheckable(true);
  1472. axisButton->setPopupMode(QToolButton::InstantPopup);
  1473. axisButton->setEnabled(false); // 初始时禁用轴向按钮
  1474. // 创建 QMenu 用于“轴向”按钮,并设置样式表
  1475. QMenu *axisMenu = new QMenu(axisButton);
  1476. axisMenu->setStyleSheet(R"(
  1477. QMenu {
  1478. background-color: white;
  1479. color: black;
  1480. border: 1px solid #BABBDC;
  1481. }
  1482. QMenu::item:selected {
  1483. background-color: #4CAF50; /* 选中时背景颜色 */
  1484. color: white; /* 选中时字体颜色 */
  1485. }
  1486. )");
  1487. QJsonObject axisMap = fieldConfig["axisMap"].toObject();
  1488. // 初始化轴向菜单内容为空,等待选择模组后填充
  1489. axisButton->setMenu(axisMenu);
  1490. qDebug() << "初始化轴向菜单为空:" << fieldName;
  1491. // 连接“轴向”按钮的菜单触发事件来更新“轴向”菜单
  1492. connect(axisMenu, &QMenu::triggered, this, [axisButton](QAction *action){
  1493. axisButton->setText(action->text());
  1494. axisButton->setChecked(true);
  1495. qDebug() << "轴向选择:" << action->text();
  1496. });
  1497. // “模组” QMenu
  1498. QMenu *moduleMenu = new QMenu(moduleButton);
  1499. moduleMenu->setStyleSheet(R"(
  1500. QMenu {
  1501. background-color: white;
  1502. color: black;
  1503. border: 1px solid #BABBDC;
  1504. }
  1505. QMenu::item:selected {
  1506. background-color: #4CAF50; /* 选中时背景颜色 */
  1507. color: white; /* 选中时字体颜色 */
  1508. }
  1509. )");
  1510. QJsonArray moduleOptions = fieldConfig["moduleOptions"].toArray();
  1511. for (const QJsonValue &mod : moduleOptions) {
  1512. QAction *action = moduleMenu->addAction(mod.toString());
  1513. // 使用按值捕获,避免悬空指针
  1514. connect(action, &QAction::triggered, this, [moduleButton, action, fieldConfig,
  1515. combinedWidget, fieldName,
  1516. axisButton, axisMenu, axisMap]() {
  1517. moduleButton->setText(action->text());
  1518. moduleButton->setChecked(true);
  1519. qDebug() << "模组选择:" << action->text();
  1520. // 更改背景颜色为高亮色
  1521. moduleButton->setStyleSheet("background: #4CAF50;");
  1522. axisButton->setStyleSheet("background: #4CAF50;");
  1523. qDebug() << "组合控件颜色已切换为高亮颜色";
  1524. // 启用轴向按钮
  1525. axisButton->setEnabled(true);
  1526. // 动态填充轴向菜单
  1527. axisMenu->clear(); // 清空现有菜单项
  1528. if (axisMap.contains(action->text())) {
  1529. QJsonArray axes = axisMap[action->text()].toArray();
  1530. for (const QJsonValue &axis : axes) {
  1531. axisMenu->addAction(axis.toString());
  1532. }
  1533. qDebug() << "轴向菜单已根据模组选择动态填充";
  1534. } else {
  1535. qDebug() << "没有找到对应模组的轴向选项";
  1536. }
  1537. // 启动定时器
  1538. int timeoutSec = fieldConfig["timeout"].toInt(180); // 默认180秒(3分钟)
  1539. QTimer *timer = new QTimer(combinedWidget);
  1540. timer->setSingleShot(true);
  1541. connect(timer, &QTimer::timeout, combinedWidget, [moduleButton, axisButton]() {
  1542. // 恢复背景颜色为默认
  1543. moduleButton->setStyleSheet("background: #FFFFFF;");
  1544. axisButton->setStyleSheet("background: #FFFFFF;");
  1545. qDebug() << "组合控件颜色已切换为默认(超时)";
  1546. });
  1547. timer->start(timeoutSec * 1000); // 修正为 timeoutSec * 1000 毫秒 (3分钟)
  1548. qDebug() << "启动定时器," << timeoutSec << "秒后更改组合控件颜色";
  1549. });
  1550. }
  1551. moduleButton->setMenu(moduleMenu);
  1552. qDebug() << "添加组合控件的模组按钮:" << fieldName;
  1553. // 创建一个容器 widget 来包含组合控件
  1554. combinedLayout->addWidget(comboInput);
  1555. combinedLayout->addWidget(moduleButton);
  1556. combinedLayout->addWidget(axisButton);
  1557. combinedLayout->addStretch(); // 保证组合控件紧凑排列
  1558. rightLayout->addWidget(combinedWidget);
  1559. qDebug() << "组合控件已添加到布局:" << fieldName;
  1560. } else {
  1561. qWarning() << "未知字段类型:" << fieldType;
  1562. }
  1563. // 将 rightWidget 加到 fieldLayout 的右侧
  1564. fieldLayout->addWidget(rightWidget);
  1565. qDebug() << "将 rightWidget 添加到 fieldLayout";
  1566. // 将 fieldLayout 添加到 scrollLayout
  1567. scrollLayout->addLayout(fieldLayout);
  1568. qDebug() << "添加字段布局:" << fieldName;
  1569. if (fieldConfig.contains("separator") && fieldConfig["separator"].toBool()) {
  1570. QFrame *separator = createUnifiedSeparator(scrollWidget, 2);
  1571. QHBoxLayout *separatorLayout = new QHBoxLayout;
  1572. separatorLayout->setContentsMargins(0, 5, 0, 5); // 5px 上下边距
  1573. separatorLayout->addWidget(separator);
  1574. scrollLayout->addLayout(separatorLayout);
  1575. separator->show(); // 显示分隔线
  1576. qDebug() << "添加统一的动态分割线,并已显示";
  1577. }
  1578. }
  1579. // 4. 补一个弹性伸缩,让底部也有一定空隙
  1580. scrollLayout->addStretch();
  1581. qDebug() << "添加弹性伸缩以填充底部空隙";
  1582. // 5. 将 scrollWidget 设置给 scrollArea
  1583. scrollArea->setWidget(scrollWidget);
  1584. qDebug() << "滚动容器已设置到 QScrollArea";
  1585. // 6. 最后将 scrollArea 放到 fieldWindow 的主布局中
  1586. QVBoxLayout *mainLayout = new QVBoxLayout(fieldWindow);
  1587. mainLayout->setContentsMargins(0, 0, 0, 0);
  1588. mainLayout->addWidget(scrollArea);
  1589. qDebug() << "主布局已设置到 fieldWindow";
  1590. // 7. 显示窗口
  1591. fieldWindow->show();
  1592. qDebug() << "三级目录字段窗口已打开";
  1593. }
  1594. void TreeViewManager::setupButton()
  1595. {
  1596. buttonOpenFile = new QPushButton(widget2);
  1597. buttonUp = new QPushButton(widget2);
  1598. buttonDown = new QPushButton(widget2);
  1599. buttonLeft = new QPushButton(widget2);
  1600. buttonRight = new QPushButton(widget2);
  1601. // 设置 buttonOpenFile 的位置
  1602. buttonOpenFile->setParent(widget2); // 明确设置 widget2 为父级
  1603. buttonOpenFile->setMaximumSize(76, 30);
  1604. buttonOpenFile->setIcon(QIcon(":/images/home_openFile.png"));
  1605. buttonOpenFile->setText("");
  1606. buttonOpenFile->setGeometry(328, 16, 76, 30);
  1607. // 设置按钮位置大小
  1608. buttonUp->setParent(widget2);
  1609. buttonUp->setMaximumSize(36, 30);
  1610. buttonUp->setIcon(QIcon(":/images/home_up.png"));
  1611. buttonUp->setText("");
  1612. buttonUp->setGeometry(408, 16, 36, 30); // 位置示例
  1613. buttonDown->setParent(widget2);
  1614. buttonDown->setMaximumSize(36, 30);
  1615. buttonDown->setIcon(QIcon(":/images/home_down.png"));
  1616. buttonDown->setText("");
  1617. buttonDown->setGeometry(408, 50, 36, 30); // 位置示例
  1618. buttonLeft->setParent(widget2);
  1619. buttonLeft->setMaximumSize(36, 30);
  1620. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  1621. buttonLeft->setText("");
  1622. buttonLeft->setGeometry(328, 50, 36, 30); // 位置示例
  1623. buttonRight->setParent(widget2);
  1624. buttonRight->setMaximumSize(36, 30);
  1625. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  1626. buttonRight->setText("");
  1627. buttonRight->setGeometry(368, 50, 36, 30); // 位置示例
  1628. // 显示所有按钮
  1629. buttonOpenFile->show();
  1630. buttonUp->show();
  1631. buttonDown->show();
  1632. buttonLeft->show();
  1633. buttonRight->show();
  1634. }
  1635. void TreeViewManager::onButtonOpenFileClicked()
  1636. {
  1637. foreach (QObject *child, widget2->children()) {
  1638. QWidget *childWidget = qobject_cast<QWidget *>(child);
  1639. if (childWidget && childWidget->windowTitle() == "字段展示") {
  1640. qDebug() << "关闭字段窗口:" << childWidget;
  1641. childWidget->close();
  1642. }
  1643. }
  1644. treeViewDown->show(); // 显示 treeViewDown
  1645. treeViewDown->collapseAll(); // 收起所有节点
  1646. treeViewDown->clearSelection();
  1647. // 展开一级目录
  1648. QStandardItem *rootItem = downModel->invisibleRootItem();
  1649. if (rootItem) {
  1650. for (int i = 0; i < rootItem->rowCount(); ++i) {
  1651. QStandardItem *childItem = rootItem->child(i);
  1652. if (childItem) {
  1653. treeViewDown->expand(downModel->indexFromItem(childItem));
  1654. qDebug() << "展开一级目录:" << childItem->text();
  1655. }
  1656. }
  1657. }
  1658. // 重置导航栏
  1659. updateNavigationBar(QModelIndex());
  1660. // 更新横线的位置和可见性
  1661. QTimer::singleShot(0, this, &TreeViewManager::updateSeparatorLine);
  1662. qDebug() << "成功返回到一级菜单";
  1663. }
  1664. void TreeViewManager::onButtonUpClicked()
  1665. {
  1666. qDebug() << "TreeViewManager: 向上遍历所有目录";
  1667. // 获取当前选中项索引
  1668. QModelIndex currentIndex = treeViewDown->currentIndex();
  1669. if (!currentIndex.isValid()) {
  1670. qDebug() << "当前无有效索引,从最后一个根节点开始遍历";
  1671. // 从最后一个根节点开始
  1672. int lastRootRow = downModel->rowCount() - 1;
  1673. if (lastRootRow >= 0) {
  1674. currentIndex = downModel->index(lastRootRow, 0);
  1675. treeViewDown->setCurrentIndex(currentIndex);
  1676. updateNavigationBar(currentIndex);
  1677. qDebug() << "当前目录:" << downModel->itemFromIndex(currentIndex)->text();
  1678. }
  1679. return;
  1680. }
  1681. QStandardItem *currentItem = downModel->itemFromIndex(currentIndex);
  1682. if (!currentItem) {
  1683. qWarning() << "无法获取当前目录项";
  1684. return;
  1685. }
  1686. // 检查当前节点是否有上一个同级节点
  1687. QModelIndex previousSiblingIndex = currentIndex.siblingAtRow(currentIndex.row() - 1);
  1688. if (previousSiblingIndex.isValid()) {
  1689. // 如果有上一个同级节点,则进入该节点的最后一个子节点
  1690. qDebug() << "当前目录有上一个同级节点:" << downModel->itemFromIndex(previousSiblingIndex)->text();
  1691. QModelIndex lastChildIndex = getLastChildIndex(previousSiblingIndex);
  1692. if (lastChildIndex.isValid()) {
  1693. treeViewDown->setCurrentIndex(lastChildIndex);
  1694. updateNavigationBar(lastChildIndex);
  1695. qDebug() << "进入上一个同级节点的最后一个子节点:" << downModel->itemFromIndex(lastChildIndex)->text();
  1696. } else {
  1697. treeViewDown->setCurrentIndex(previousSiblingIndex);
  1698. updateNavigationBar(previousSiblingIndex);
  1699. qDebug() << "进入上一个同级节点:" << downModel->itemFromIndex(previousSiblingIndex)->text();
  1700. }
  1701. return;
  1702. }
  1703. // 如果没有上一个同级节点,返回到父节点
  1704. QModelIndex parentIndex = currentIndex.parent();
  1705. if (parentIndex.isValid()) {
  1706. treeViewDown->setCurrentIndex(parentIndex);
  1707. updateNavigationBar(parentIndex);
  1708. qDebug() << "返回到父节点:" << downModel->itemFromIndex(parentIndex)->text();
  1709. return;
  1710. }
  1711. // 如果没有父节点,说明已经到达最顶部
  1712. qDebug() << "已经到达根目录顶部,无法继续向上遍历";
  1713. }
  1714. // 获取最后一个子节点的索引
  1715. QModelIndex TreeViewManager::getLastChildIndex(const QModelIndex &parentIndex)
  1716. {
  1717. if (!parentIndex.isValid() || downModel->rowCount(parentIndex) == 0) {
  1718. return QModelIndex(); // 无效索引
  1719. }
  1720. // 获取最后一个子节点的索引
  1721. int lastRow = downModel->rowCount(parentIndex) - 1;
  1722. QModelIndex lastChildIndex = downModel->index(lastRow, 0, parentIndex);
  1723. // 如果最后一个子节点还有子节点,递归查找其最后一个子节点
  1724. QModelIndex lastGrandChildIndex = getLastChildIndex(lastChildIndex);
  1725. return lastGrandChildIndex.isValid() ? lastGrandChildIndex : lastChildIndex;
  1726. }
  1727. void TreeViewManager::onButtonDownClicked()
  1728. {
  1729. qDebug() << "TreeViewManager: 向下遍历所有目录";
  1730. // 获取当前选中项索引
  1731. QModelIndex currentIndex = treeViewDown->currentIndex();
  1732. if (!currentIndex.isValid()) {
  1733. qDebug() << "当前无有效索引,从第一个根节点开始遍历";
  1734. currentIndex = downModel->index(0, 0); // 从第一个根节点开始
  1735. treeViewDown->setCurrentIndex(currentIndex);
  1736. updateNavigationBar(currentIndex); // 更新导航栏
  1737. qDebug() << "当前目录:" << downModel->itemFromIndex(currentIndex)->text();
  1738. return;
  1739. }
  1740. QStandardItem *currentItem = downModel->itemFromIndex(currentIndex);
  1741. if (!currentItem) {
  1742. qWarning() << "无法获取当前目录项";
  1743. return;
  1744. }
  1745. // 如果当前项有子节点,则进入子节点
  1746. if (currentItem->hasChildren()) {
  1747. qDebug() << "当前目录有子目录,进入第一个子目录:" << currentItem->text();
  1748. treeViewDown->expand(currentIndex); // 展开当前目录
  1749. QModelIndex childIndex = downModel->index(0, 0, currentIndex); // 获取第一个子节点
  1750. if (childIndex.isValid()) {
  1751. treeViewDown->setCurrentIndex(childIndex); // 进入第一个子节点
  1752. updateNavigationBar(childIndex); // 更新导航栏
  1753. qDebug() << "进入子目录:" << downModel->itemFromIndex(childIndex)->text();
  1754. return;
  1755. } else {
  1756. qWarning() << "当前目录有子节点但无法获取";
  1757. }
  1758. }
  1759. // 当前目录没有子节点,寻找同级的下一个节点
  1760. QModelIndex nextSiblingIndex = currentIndex.siblingAtRow(currentIndex.row() + 1);
  1761. while (!nextSiblingIndex.isValid()) {
  1762. // 如果没有下一个同级节点,向上查找父节点的下一个同级节点
  1763. QModelIndex parentIndex = currentIndex.parent();
  1764. if (!parentIndex.isValid()) {
  1765. qDebug() << "已到达最底层目录,从第一个根节点重新开始遍历";
  1766. nextSiblingIndex = downModel->index(0, 0); // 回到根目录的第一个节点
  1767. break;
  1768. }
  1769. nextSiblingIndex = parentIndex.siblingAtRow(parentIndex.row() + 1); // 获取父节点的下一个同级节点
  1770. currentIndex = parentIndex; // 更新当前索引为父节点
  1771. }
  1772. // 进入下一个节点(同级或回到根节点的第一个节点)
  1773. if (nextSiblingIndex.isValid()) {
  1774. treeViewDown->setCurrentIndex(nextSiblingIndex);
  1775. updateNavigationBar(nextSiblingIndex); // 更新导航栏
  1776. qDebug() << "进入同级或上层同级目录:" << downModel->itemFromIndex(nextSiblingIndex)->text();
  1777. } else {
  1778. qWarning() << "无法找到下一个目录节点";
  1779. }
  1780. }
  1781. // 获取下一个有效索引
  1782. QModelIndex TreeViewManager::getNextIndex(const QModelIndex &currentIndex)
  1783. {
  1784. // 尝试获取当前项的下一个兄弟项
  1785. QModelIndex nextIndex = currentIndex.sibling(currentIndex.row() + 1, 0);
  1786. if (nextIndex.isValid()) {
  1787. return nextIndex;
  1788. }
  1789. // 如果没有兄弟项,向上找到父节点的下一个兄弟项
  1790. QModelIndex parentIndex = currentIndex.parent();
  1791. while (parentIndex.isValid()) {
  1792. QModelIndex nextParentSibling = parentIndex.sibling(parentIndex.row() + 1, 0);
  1793. if (nextParentSibling.isValid()) {
  1794. return nextParentSibling;
  1795. }
  1796. parentIndex = parentIndex.parent(); // 再往上层找
  1797. }
  1798. // 如果没有兄弟项或父节点兄弟项,返回无效索引
  1799. return QModelIndex();
  1800. }
  1801. void TreeViewManager::onButtonLeftClicked()
  1802. {
  1803. qDebug() << "TreeViewManager: 返回上一级目录";
  1804. // 检查是否是三级目录字段展示窗口
  1805. bool isFieldWindowClosed = false;
  1806. // 更新横线的位置和可见性
  1807. QTimer::singleShot(0, this, &TreeViewManager::updateSeparatorLine);
  1808. foreach (QObject *child, widget2->children()) {
  1809. QWidget *childWidget = qobject_cast<QWidget *>(child);
  1810. if (childWidget && childWidget->windowTitle() == "字段展示") {
  1811. qDebug() << "关闭三级目录窗口并返回到三级目录";
  1812. childWidget->close(); // 关闭字段展示窗口
  1813. isFieldWindowClosed = true;
  1814. }
  1815. }
  1816. if (isFieldWindowClosed) {
  1817. // 重新显示 treeViewDown 并恢复到对应的三级目录索引
  1818. treeViewDown->show();
  1819. QModelIndex currentIndex = treeViewDown->currentIndex();
  1820. if (currentIndex.isValid()) {
  1821. updateNavigationBar(currentIndex); // 更新导航栏
  1822. qDebug() << "返回到三级目录索引:" << downModel->itemFromIndex(currentIndex)->text();
  1823. } else {
  1824. qWarning() << "当前索引无效,无法更新导航栏";
  1825. }
  1826. // **继续执行向上遍历的逻辑**
  1827. QModelIndex parentIndex = currentIndex.parent();
  1828. if (parentIndex.isValid()) {
  1829. treeViewDown->setCurrentIndex(parentIndex);
  1830. treeViewDown->expand(parentIndex); // 确保父节点展开
  1831. updateNavigationBar(parentIndex); // 更新导航栏
  1832. QStandardItem *parentItem = downModel->itemFromIndex(parentIndex);
  1833. if (parentItem) {
  1834. qDebug() << "返回上一级目录:" << parentItem->text();
  1835. } else {
  1836. qWarning() << "未找到父目录项";
  1837. }
  1838. } else {
  1839. qWarning() << "当前节点没有父节点";
  1840. }
  1841. return; // 确保退出此方法,避免执行以下逻辑
  1842. }
  1843. // 获取当前选中项的索引
  1844. QModelIndex currentIndex = treeViewDown->currentIndex();
  1845. if (!currentIndex.isValid()) {
  1846. qDebug() << "当前无有效索引,无法返回";
  1847. return;
  1848. }
  1849. // 获取父节点索引
  1850. QModelIndex parentIndex = currentIndex.parent();
  1851. if (parentIndex.isValid()) {
  1852. // 如果有父节点,返回到父节点
  1853. treeViewDown->setCurrentIndex(parentIndex);
  1854. treeViewDown->expand(parentIndex); // 展开父节点
  1855. updateNavigationBar(parentIndex); // 更新导航栏
  1856. QStandardItem *parentItem = downModel->itemFromIndex(parentIndex);
  1857. if (parentItem) {
  1858. qDebug() << "返回上一级目录:" << parentItem->text();
  1859. } else {
  1860. qWarning() << "未找到父目录项";
  1861. }
  1862. } else {
  1863. // 如果没有父节点,返回到一级目录的第一行
  1864. QModelIndex firstIndex = downModel->index(0, 0);
  1865. if (firstIndex.isValid()) {
  1866. treeViewDown->setCurrentIndex(firstIndex);
  1867. treeViewDown->expand(firstIndex); // 展开一级目录
  1868. updateNavigationBar(firstIndex); // 更新导航栏
  1869. QStandardItem *firstItem = downModel->itemFromIndex(firstIndex);
  1870. if (firstItem) {
  1871. qDebug() << "返回到一级目录的第一行:" << firstItem->text();
  1872. } else {
  1873. qWarning() << "未找到一级目录的第一行";
  1874. }
  1875. } else {
  1876. qWarning() << "无法找到任何一级目录";
  1877. }
  1878. }
  1879. }
  1880. void TreeViewManager::onButtonRightClicked()
  1881. {
  1882. qDebug() << "TreeViewManager: 进入下一级目录";
  1883. // 获取当前选中项索引
  1884. QModelIndex currentIndex = treeViewDown->currentIndex();
  1885. if (!currentIndex.isValid()) {
  1886. qDebug() << "当前无有效索引,自动从第一个根节点开始";
  1887. currentIndex = downModel->index(0, 0); // 从根节点第一个开始
  1888. }
  1889. QStandardItem *currentItem = downModel->itemFromIndex(currentIndex);
  1890. if (!currentItem) {
  1891. qWarning() << "无法获取当前目录项";
  1892. return;
  1893. }
  1894. // 检查当前项是否有子节点
  1895. if (currentItem->hasChildren()) {
  1896. qDebug() << "当前目录有子目录,展开并进入第一个子目录:" << currentItem->text();
  1897. // 展开当前项并进入第一个子项
  1898. treeViewDown->expand(currentIndex);
  1899. QModelIndex childIndex = downModel->index(0, 0, currentIndex); // 使用 QAbstractItemModel::index()
  1900. if (childIndex.isValid()) {
  1901. treeViewDown->setCurrentIndex(childIndex);
  1902. updateNavigationBar(childIndex); // 更新导航栏
  1903. qDebug() << "进入子目录:" << downModel->itemFromIndex(childIndex)->text();
  1904. return;
  1905. } else {
  1906. qWarning() << "展开失败:未找到子节点";
  1907. return;
  1908. }
  1909. }
  1910. // 当前目录没有子节点,寻找同级的下一个节点
  1911. QModelIndex nextSiblingIndex = currentIndex.siblingAtRow(currentIndex.row() + 1);
  1912. while (!nextSiblingIndex.isValid()) {
  1913. // 如果没有下一个同级节点,向上查找父节点的下一个同级节点
  1914. QModelIndex parentIndex = currentIndex.parent();
  1915. if (!parentIndex.isValid()) {
  1916. qDebug() << "已到达最底层目录,没有更多的下一级节点";
  1917. return; // 已经遍历完所有节点
  1918. }
  1919. nextSiblingIndex = parentIndex.siblingAtRow(parentIndex.row() + 1);
  1920. currentIndex = parentIndex;
  1921. }
  1922. // 进入下一个同级节点
  1923. treeViewDown->setCurrentIndex(nextSiblingIndex);
  1924. updateNavigationBar(nextSiblingIndex); // 更新导航栏
  1925. qDebug() << "进入同级目录:" << downModel->itemFromIndex(nextSiblingIndex)->text();
  1926. }