treeviewmanager.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. #include "treeviewmanager.h"
  2. TreeViewManager::TreeViewManager(QWidget *parent, QWidget *widget2)
  3. : QWidget(parent),
  4. widget2(widget2),
  5. treeViewDown(new QTreeView(widget2)), // 初始化 treeViewDown
  6. navigationWidget(nullptr),
  7. buttonOpenFile(nullptr),
  8. buttonUp(nullptr),
  9. buttonDown(nullptr),
  10. buttonLeft(nullptr),
  11. buttonRight(nullptr) {
  12. if (!widget2) {
  13. qWarning() << "TreeViewManager: widget2 未初始化";
  14. return;
  15. }
  16. // 初始化目录树模型
  17. downModel = new QStandardItemModel(this);
  18. treeViewDown->setModel(downModel);
  19. // 创建数据模型
  20. //setupTreeData();
  21. // 应用样式表
  22. applyCustomStyles();
  23. treeViewDown->setHeaderHidden(true); // 显示头部
  24. treeViewDown->setGeometry(16, 106, widget2->width()-16, widget2->height() - 106);
  25. treeViewDown->setEditTriggers(QAbstractItemView::NoEditTriggers);
  26. treeViewDown->show();
  27. qDebug() << "widget2 geometry:" << widget2->geometry();
  28. qDebug() << "treeViewDown geometry:" << treeViewDown->geometry();
  29. // 加载 JSON 数据
  30. loadJsonFromFile(":/config/menu_config.json");
  31. // 创建按钮并设置布局
  32. setupButton();
  33. // 创建导航栏
  34. navigationWidget = new QWidget(widget2);
  35. navigationWidget->setGeometry(15, 15, 300, 74);
  36. navigationLayout = new QVBoxLayout(navigationWidget);
  37. navigationLayout->setContentsMargins(0, 0, 0, 0);
  38. navigationLayout->setSpacing(0);
  39. navigationWidget->show();
  40. // 更新导航栏位置
  41. updateNavigationWidgetGeometry();
  42. connect(treeViewDown, &QTreeView::clicked, this, [=](const QModelIndex &index) {
  43. QStandardItem *item = downModel->itemFromIndex(index);
  44. if (!item) return;
  45. QVariant data = item->data(Qt::UserRole);
  46. if (data.canConvert<QJsonObject>()) {
  47. QJsonObject fields = data.toJsonObject();
  48. displayThirdLevelFields(fields); // 显示三级目录字段
  49. }
  50. });
  51. connect(treeViewDown, &QTreeView::clicked, this, [=](const QModelIndex &index) {
  52. if (!index.isValid()) {
  53. qWarning() << "点击事件:索引无效";
  54. return;
  55. }
  56. QStandardItem *item = downModel->itemFromIndex(index);
  57. if (!item) {
  58. qWarning() << "点击事件:未找到对应项";
  59. return;
  60. }
  61. QVariant data = item->data(Qt::UserRole);
  62. if (data.canConvert<QJsonObject>()) {
  63. QJsonObject fields = data.toJsonObject();
  64. if (fields.contains("isThirdLevel") && fields["isThirdLevel"].toBool()) {
  65. qDebug() << "加载三级目录字段内容:" << fields;
  66. // 更新导航栏
  67. updateNavigationBar(index);
  68. // 显示三级目录字段内容
  69. displayThirdLevelFields(fields); // 显示三级目录字段
  70. treeViewDown->hide(); // 隐藏 treeViewDown
  71. return;
  72. }
  73. }
  74. // 即使是非三级目录,也更新导航栏
  75. updateNavigationBar(index);
  76. qDebug() << "更新导航栏,目录项:" << item->text();
  77. });
  78. connect(buttonOpenFile, &QPushButton::clicked, this, &TreeViewManager::onButtonOpenFileClicked);
  79. connect(buttonUp, &QPushButton::clicked, this, &TreeViewManager::onButtonUpClicked);
  80. connect(buttonDown, &QPushButton::clicked, this, &TreeViewManager::onButtonDownClicked);
  81. connect(buttonLeft, &QPushButton::clicked, this, &TreeViewManager::onButtonLeftClicked);
  82. connect(buttonRight, &QPushButton::clicked, this, &TreeViewManager::onButtonRightClicked);
  83. }
  84. void TreeViewManager::loadJsonFromFile(const QString &filePath)
  85. {
  86. QFile jsonFile(filePath);
  87. if (!jsonFile.exists()) {
  88. qWarning() << "JSON 文件不存在:" << filePath;
  89. return;
  90. }
  91. if (!jsonFile.open(QIODevice::ReadOnly)) {
  92. qWarning() << "无法打开 JSON 文件:" << filePath;
  93. return;
  94. }
  95. QByteArray fileData = jsonFile.readAll();
  96. jsonFile.close();
  97. QJsonDocument jsonDoc = QJsonDocument::fromJson(fileData);
  98. if (jsonDoc.isNull() || !jsonDoc.isObject()) {
  99. qWarning() << "JSON 文件格式错误:" << filePath;
  100. return;
  101. }
  102. // 直接传递解析好的 JSON 文档
  103. loadTreeData(jsonDoc);
  104. qDebug() << "JSON 数据加载完成";
  105. }
  106. void TreeViewManager::applyCustomStyles() {
  107. treeViewDown->setStyleSheet(R"(
  108. /* 设置分支图标 */
  109. QTreeView::branch:closed:has-children {
  110. border-image: none;
  111. image: url(:/images/home_add.png);
  112. }
  113. QTreeView::branch:open:has-children {
  114. border-image: none;
  115. image: url(:/images/home_minus.png);
  116. }
  117. /* 设置多选框 */
  118. QTreeView::indicator:unchecked {
  119. image: url(:/images/home_up.png);
  120. }
  121. QTreeView::indicator:checked {
  122. image: url(:/images/home_down.png);
  123. }
  124. /* 背景透明 */
  125. QTreeView {
  126. background: transparent;
  127. border: none;
  128. }
  129. )");
  130. }
  131. void TreeViewManager::loadTreeData(const QJsonDocument &doc)
  132. {
  133. if (!doc.isObject()) {
  134. qWarning() << "无效的 JSON 结构";
  135. return;
  136. }
  137. // qDebug() << "加载的 JSON 数据:" << doc.toJson();
  138. buildTree(doc.object(), downModel->invisibleRootItem());
  139. }
  140. void TreeViewManager::buildTree(const QJsonObject &jsonObj, QStandardItem *parent)
  141. {
  142. for (auto it = jsonObj.begin(); it != jsonObj.end(); ++it) {
  143. if (it.key() == "isThirdLevel") {
  144. qDebug() << "跳过 'isThirdLevel' 字段:" << it.key();
  145. continue; // 跳过 "isThirdLevel" 字段
  146. }
  147. QStandardItem *item = new QStandardItem(it.key());
  148. item->setCheckable(true); // 添加多选框
  149. parent->appendRow(item);
  150. if (it.value().isObject()) {
  151. QJsonObject childObj = it.value().toObject();
  152. if (childObj.contains("isThirdLevel") && childObj["isThirdLevel"].toBool()) {
  153. // 是三级目录,存储整个对象到 UserRole
  154. item->setData(childObj, Qt::UserRole);
  155. qDebug() << "识别为三级目录:" << it.key();
  156. } else {
  157. // 递归处理子目录
  158. buildTree(childObj, item);
  159. }
  160. }
  161. }
  162. }
  163. // 更新导航栏位置和大小
  164. void TreeViewManager::updateNavigationWidgetGeometry()
  165. {
  166. // 设置导航栏的宽度和高度
  167. int navWidth = 300; // 固定宽度为 300 像素
  168. int navHeight = 74; // 固定高度为 74 像素
  169. // 设置导航栏的左上角位置
  170. int navLeft = 15; // 距离 widget2 左边 15 像素
  171. int navTop = 15; // 距离 widget2 顶部 15 像素
  172. // 设置导航栏的几何位置
  173. navigationWidget->setGeometry(navLeft, navTop, navWidth, navHeight);
  174. // 如果需要,刷新组件
  175. navigationWidget->update();
  176. qDebug() << "Updated navigationWidget geometry:"
  177. << navigationWidget->geometry();
  178. }
  179. void TreeViewManager::updateNavigationBar(const QModelIndex &index)
  180. {
  181. if (!index.isValid()) {
  182. qWarning() << "导航栏更新失败:索引无效";
  183. return;
  184. }
  185. QStandardItem *item = downModel->itemFromIndex(index);
  186. if (!item) {
  187. qWarning() << "导航栏更新失败:未找到对应项";
  188. return;
  189. }
  190. qDebug() << "导航栏更新,目录项:" << item->text();
  191. // 如果导航栏已有布局,先清理
  192. if (navigationWidget->layout()) {
  193. QLayoutItem *child;
  194. while ((child = navigationWidget->layout()->takeAt(0)) != nullptr) {
  195. if (child->widget()) {
  196. child->widget()->deleteLater();
  197. }
  198. delete child;
  199. }
  200. delete navigationWidget->layout();
  201. }
  202. // 构建路径列表,从当前项到根节点
  203. QList<QStandardItem *> path;
  204. while (item) {
  205. if (item->text() != "isThirdLevel") { // 排除 "isThirdLevel" 标识
  206. path.prepend(item); // 从根节点开始
  207. }
  208. item = item->parent();
  209. }
  210. qDebug() << "导航路径:" << [path]() {
  211. QStringList pathNames;
  212. for (QStandardItem *p : path) {
  213. pathNames.append(p->text());
  214. }
  215. return pathNames.join(" -> ");
  216. }();
  217. // 创建新的导航栏布局
  218. QVBoxLayout *newLayout = new QVBoxLayout;
  219. newLayout->setContentsMargins(0, 0, 0, 0); // 去除边距
  220. newLayout->setSpacing(0); // 行间无间隙
  221. // 确保始终显示三行
  222. for (int i = 0; i < 3; ++i) {
  223. QLabel *label = new QLabel;
  224. if (i < path.size()) {
  225. QString text = path[i]->text();
  226. if (i == 1) text = " " + text; // 一级目录缩进
  227. if (i == 2) text = " " + text; // 二级/三级目录缩进
  228. label->setText(text);
  229. } else {
  230. label->setText(""); // 填充空白行
  231. }
  232. // 设置字体和样式
  233. QFont font = label->font();
  234. font.setPointSize(12); // 设置字体大小
  235. label->setFont(font);
  236. label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); // 左对齐且垂直居中
  237. label->setFixedHeight(navigationWidget->height() / 3); // 每行高度均分导航栏高度
  238. newLayout->addWidget(label);
  239. }
  240. // 设置布局并更新导航栏
  241. navigationWidget->setLayout(newLayout);
  242. navigationWidget->update();
  243. qDebug() << "导航栏更新完成:" << path.size() << "项";
  244. }
  245. void TreeViewManager::displayThirdLevelFields(const QJsonObject &fields)
  246. {
  247. if (fields.isEmpty()) {
  248. qWarning() << "字段数据为空,无法显示";
  249. return;
  250. }
  251. qDebug() << "显示的字段数据:" << fields;
  252. // 检查是否已存在字段窗口,防止重复创建
  253. foreach (QObject *child, widget2->children()) {
  254. QWidget *childWidget = qobject_cast<QWidget *>(child);
  255. if (childWidget && childWidget->windowTitle() == "字段展示") {
  256. qDebug() << "字段窗口已存在,关闭旧窗口";
  257. childWidget->close();
  258. }
  259. }
  260. QWidget *fieldWindow = new QWidget(widget2); // 使用 widget2 作为父窗口
  261. fieldWindow->setWindowTitle("字段展示");
  262. fieldWindow->setGeometry(treeViewDown->geometry());
  263. QVBoxLayout *layout = new QVBoxLayout(fieldWindow);
  264. for (auto it = fields.begin(); it != fields.end(); ++it) {
  265. QString fieldName = it.key();
  266. if (fieldName == "isThirdLevel") {
  267. continue; // 跳过 isThirdLevel 字段
  268. }
  269. QJsonObject fieldConfig = it.value().toObject();
  270. QHBoxLayout *fieldLayout = new QHBoxLayout;
  271. QLabel *label = new QLabel(fieldName);
  272. label->setFixedWidth(150);
  273. fieldLayout->addWidget(label);
  274. if (fieldConfig["type"].toString() == "input") {
  275. QLineEdit *lineEdit = new QLineEdit(fieldConfig["value"].toString());
  276. fieldLayout->addWidget(lineEdit);
  277. qDebug() << "创建输入控件:" << fieldName << ", 默认值:" << fieldConfig["value"].toString();
  278. } else if (fieldConfig["type"].toString() == "dropdown") {
  279. QComboBox *comboBox = new QComboBox;
  280. QJsonArray options = fieldConfig["options"].toArray();
  281. for (const QJsonValue &option : options) {
  282. comboBox->addItem(option.toString());
  283. }
  284. comboBox->setCurrentText(fieldConfig["value"].toString());
  285. fieldLayout->addWidget(comboBox);
  286. qDebug() << "创建下拉框:" << fieldName << ", 选项:" << options << ", 默认值:" << fieldConfig["value"].toString();
  287. } else if (fieldConfig["type"].toString() == "checkbox") {
  288. QCheckBox *checkBox = new QCheckBox;
  289. checkBox->setChecked(fieldConfig["value"].toString() == "true");
  290. fieldLayout->addWidget(checkBox);
  291. qDebug() << "创建复选框:" << fieldName << ", 默认值:" << fieldConfig["value"].toString();
  292. } else {
  293. qWarning() << "未知字段类型:" << fieldConfig["type"].toString();
  294. }
  295. layout->addLayout(fieldLayout);
  296. }
  297. fieldWindow->setLayout(layout);
  298. fieldWindow->adjustSize();
  299. fieldWindow->show();
  300. qDebug() << "三级目录字段窗口已打开";
  301. }
  302. void TreeViewManager::setupButton()
  303. {
  304. buttonOpenFile = new QPushButton(widget2);
  305. buttonUp = new QPushButton(widget2);
  306. buttonDown = new QPushButton(widget2);
  307. buttonLeft = new QPushButton(widget2);
  308. buttonRight = new QPushButton(widget2);
  309. // 设置 buttonOpenFile 的位置
  310. buttonOpenFile->setParent(widget2); // 明确设置 widget2 为父级
  311. buttonOpenFile->setMaximumSize(76, 30);
  312. buttonOpenFile->setIcon(QIcon(":/images/home_openFile.png"));
  313. buttonOpenFile->setText("");
  314. buttonOpenFile->setGeometry(328, 16, 76, 30);
  315. // 设置按钮位置大小
  316. buttonUp->setParent(widget2);
  317. buttonUp->setMaximumSize(36, 30);
  318. buttonUp->setIcon(QIcon(":/images/home_up.png"));
  319. buttonUp->setText("");
  320. buttonUp->setGeometry(408, 16, 36, 30); // 位置示例
  321. buttonDown->setParent(widget2);
  322. buttonDown->setMaximumSize(36, 30);
  323. buttonDown->setIcon(QIcon(":/images/home_down.png"));
  324. buttonDown->setText("");
  325. buttonDown->setGeometry(408, 50, 36, 30); // 位置示例
  326. buttonLeft->setParent(widget2);
  327. buttonLeft->setMaximumSize(36, 30);
  328. buttonLeft->setIcon(QIcon(":/images/home_left.png"));
  329. buttonLeft->setText("");
  330. buttonLeft->setGeometry(328, 50, 36, 30); // 位置示例
  331. buttonRight->setParent(widget2);
  332. buttonRight->setMaximumSize(36, 30);
  333. buttonRight->setIcon(QIcon(":/images/home_right.png"));
  334. buttonRight->setText("");
  335. buttonRight->setGeometry(368, 50, 36, 30); // 位置示例
  336. // 显示所有按钮
  337. buttonOpenFile->show();
  338. buttonUp->show();
  339. buttonDown->show();
  340. buttonLeft->show();
  341. buttonRight->show();
  342. }
  343. void TreeViewManager::onButtonOpenFileClicked()
  344. {
  345. foreach (QObject *child, widget2->children()) {
  346. QWidget *childWidget = qobject_cast<QWidget *>(child);
  347. if (childWidget && childWidget->windowTitle() == "字段展示") {
  348. qDebug() << "关闭字段窗口:" << childWidget;
  349. childWidget->close();
  350. }
  351. }
  352. treeViewDown->show(); // 显示 treeViewDown
  353. treeViewDown->collapseAll(); // 收起所有节点
  354. treeViewDown->clearSelection();
  355. // 展开一级目录
  356. QStandardItem *rootItem = downModel->invisibleRootItem();
  357. if (rootItem) {
  358. for (int i = 0; i < rootItem->rowCount(); ++i) {
  359. QStandardItem *childItem = rootItem->child(i);
  360. if (childItem) {
  361. treeViewDown->expand(downModel->indexFromItem(childItem));
  362. qDebug() << "展开一级目录:" << childItem->text();
  363. }
  364. }
  365. }
  366. // 重置导航栏
  367. updateNavigationBar(QModelIndex());
  368. qDebug() << "成功返回到一级菜单";
  369. }
  370. void TreeViewManager::onButtonUpClicked()
  371. {
  372. qDebug() << "TreeViewManager: 遍历导航向上";
  373. // 检查当前是否有选中的索引
  374. QModelIndex currentIndex = treeViewDown->currentIndex();
  375. if (!currentIndex.isValid()) {
  376. qDebug() << "没有选中的索引,无法向上遍历";
  377. return;
  378. }
  379. // 获取父项索引
  380. QModelIndex parentIndex = currentIndex.parent();
  381. if (!parentIndex.isValid()) {
  382. qDebug() << "当前已在顶级目录,无法向上遍历";
  383. return;
  384. }
  385. // 将父项设置为当前选中项
  386. treeViewDown->setCurrentIndex(parentIndex);
  387. // 获取父级菜单的内容
  388. QStandardItem *parentItem = downModel->itemFromIndex(parentIndex);
  389. if (!parentItem) {
  390. qWarning() << "父项未找到,无法遍历";
  391. return;
  392. }
  393. // 获取父项的数据
  394. QVariant parentData = parentItem->data(Qt::UserRole);
  395. if (parentData.canConvert<QJsonObject>()) {
  396. QJsonObject fields = parentData.toJsonObject();
  397. // 检查是否是三级菜单
  398. if (fields.contains("type") && fields["type"].toString() == "三级菜单") {
  399. qDebug() << "跳过三级菜单的内容:" << parentItem->text();
  400. return;
  401. }
  402. }
  403. qDebug() << "成功遍历到上一级菜单:" << parentItem->text();
  404. }
  405. void TreeViewManager::onButtonDownClicked()
  406. {
  407. qDebug() << "TreeViewManager: 遍历导航向下";
  408. QModelIndex currentIndex = treeViewDown->currentIndex();
  409. if (!currentIndex.isValid()) {
  410. currentIndex = downModel->index(0, 0); // 从根节点第一个开始
  411. }
  412. QModelIndex nextIndex = getNextIndex(currentIndex);
  413. while (nextIndex.isValid()) {
  414. QStandardItem *item = downModel->itemFromIndex(nextIndex);
  415. if (item && !item->data(Qt::UserRole).isValid()) {
  416. // 不是字段节点,导航到此项
  417. treeViewDown->setCurrentIndex(nextIndex);
  418. updateNavigationBar(nextIndex);
  419. qDebug() << "成功导航到下一个目录:" << item->text();
  420. return;
  421. }
  422. // 如果是字段节点,跳过
  423. nextIndex = getNextIndex(nextIndex);
  424. }
  425. qDebug() << "已到达目录底部,无法继续向下遍历";
  426. }
  427. // 获取下一个有效索引
  428. QModelIndex TreeViewManager::getNextIndex(const QModelIndex &currentIndex)
  429. {
  430. // 尝试获取当前项的下一个兄弟项
  431. QModelIndex nextIndex = currentIndex.sibling(currentIndex.row() + 1, 0);
  432. if (nextIndex.isValid()) {
  433. return nextIndex;
  434. }
  435. // 如果没有兄弟项,向上找到父节点的下一个兄弟项
  436. QModelIndex parentIndex = currentIndex.parent();
  437. while (parentIndex.isValid()) {
  438. QModelIndex nextParentSibling = parentIndex.sibling(parentIndex.row() + 1, 0);
  439. if (nextParentSibling.isValid()) {
  440. return nextParentSibling;
  441. }
  442. parentIndex = parentIndex.parent(); // 再往上层找
  443. }
  444. // 如果没有兄弟项或父节点兄弟项,返回无效索引
  445. return QModelIndex();
  446. }
  447. void TreeViewManager::onButtonLeftClicked()
  448. {
  449. qDebug() << "TreeViewManager: 进入下一级目录";
  450. }
  451. void TreeViewManager::onButtonRightClicked()
  452. {
  453. qDebug() << "TreeViewManager: 返回上一级目录";
  454. }