控制网复测平面基准归算程序(包含控制网复测平面基准计算,平面控制网稳定性计算,水准测段高差稳定计算三个程序功能)
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

main.py 60KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  1. # ///////////////////////////////////////////////////////////////
  2. #
  3. # BY: WANDERSON M.PIMENTA
  4. # PROJECT MADE WITH: Qt Designer and PySide6
  5. # V: 1.0.0
  6. #
  7. # This project can be used freely for all uses, as long as they maintain the
  8. # respective credits only in the Python scripts, any information in the visual
  9. # interface (GUI) can be modified without any implication.
  10. #
  11. # There are limitations on Qt licenses if you want to use your products
  12. # commercially, I recommend reading them on the official website:
  13. # https://doc.qt.io/qtforpython/licenses.html
  14. #
  15. # ///////////////////////////////////////////////////////////////
  16. import time
  17. from PySide6.QtTest import QTest
  18. from PySide6.QtWidgets import QFileDialog, QWidget, QVBoxLayout, QTreeWidget, QApplication, QTreeWidgetItem, \
  19. QMessageBox, QItemDelegate, QLineEdit
  20. from PySide6.QtCore import Signal, Qt, Slot, QObject
  21. from PySide6.QtSql import QSqlTableModel, QSqlDatabase
  22. from watchdog.observers import Observer
  23. from watchdog.events import FileSystemEventHandler
  24. import sqlite3
  25. from PySide6.QtGui import QIcon
  26. import sys
  27. import os
  28. import platform
  29. import Front.back as Back
  30. import Front.back.Program_Run.database_operations
  31. from Front.back.GC.GCExport import main_function_example
  32. from Front.back.GS.GSExport import main_function_example
  33. from Front.back.WD.WDExport import main_function_example
  34. from Front.modules import *
  35. from Front.modules import Settings
  36. from Front.widgets import *
  37. # main.py
  38. from Front.back.Program_Run.utils import resource_path # 从 utils.py 导入 resource_path
  39. import gc
  40. from pathlib import Path
  41. # IMPORT / GUI AND MODULES AND WIDGETS
  42. # ///////////////////////////////////////////////////////////////
  43. # 将项目根目录添加到 sys.path
  44. project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
  45. sys.path.append(project_root)
  46. os.environ["QT_FONT_DPI"] = "96" # FIX Problem for High DPI and Scale above 100%
  47. # SET AS GLOBAL WIDGETS
  48. # ///////////////////////////////////////////////////////////////
  49. widgets = None
  50. excelname = ''
  51. # 获取项目根目录
  52. project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
  53. # 将项目根目录添加到 sys.path
  54. sys.path.append(project_root)
  55. # 表格的模型
  56. class MyTableModel(QAbstractTableModel):
  57. def __init__(self, data):
  58. super().__init__()
  59. self._data = data
  60. # 重新定义行数
  61. def rowCount(self, parent=QModelIndex()):
  62. return len(self._data)
  63. # 重新定义列数
  64. def columnCount(self, parent=QModelIndex()):
  65. return len(self._data[0]) if self._data else 0
  66. # 重新定义数据
  67. def data(self, index, role=Qt.DisplayRole):
  68. if not index.isValid():
  69. return None
  70. if role == Qt.DisplayRole:
  71. return self._data[index.row()][index.column()]
  72. return None
  73. # 数据一览树状
  74. class TreeWidgetItem:
  75. def __init__(self, id: any, parent_id: any, name: str, icon: QIcon = None, extend: object = None):
  76. """
  77. 菜单数据接口
  78. :param id: ID
  79. :param parent_id: 父ID
  80. :param name: 菜单名称
  81. :param icon: 图标
  82. :param extend: 扩展数据
  83. """
  84. self.id: any = id
  85. self.parent_id: any = parent_id
  86. self.name: str = name
  87. self.extend: object = extend
  88. # 实例化
  89. self.treeWidgetItem = QTreeWidgetItem([self.name])
  90. # 存储相关数据
  91. self.treeWidgetItem.setData(0, Qt.UserRole + 1, extend)
  92. self.treeWidgetItem.setIcon(0, QIcon(':/icons/default.png'))
  93. if icon is not None:
  94. self.treeWidgetItem.setIcon(0, icon)
  95. class ElTreeData(QObject):
  96. """
  97. Data Model
  98. """
  99. items_changed: Signal = Signal(str)
  100. styleSheet_changed: Signal = Signal(str)
  101. def __init__(self, items: list[TreeWidgetItem] = None, styleSheet: str = None):
  102. super(ElTreeData, self).__init__()
  103. # 定义数据
  104. self._items: list[TreeWidgetItem]
  105. self._styleSheet: str
  106. # 初始化数据
  107. self.items = items
  108. self.styleSheet = styleSheet
  109. @property
  110. def items(self):
  111. return self._items
  112. @items.setter
  113. def items(self, value):
  114. self._items = value
  115. # 数据改变时发出信号
  116. self.items_changed.emit(self.items)
  117. @property
  118. def styleSheet(self):
  119. return self._styleSheet
  120. @styleSheet.setter
  121. def styleSheet(self, value):
  122. self._styleSheet = value
  123. # 数据改变时发出信号
  124. self.styleSheet_changed.emit(self.styleSheet)
  125. # 全数据库
  126. class ElTree(QWidget):
  127. """
  128. Control
  129. """
  130. itemClicked: Signal = Signal(object)
  131. itemDoubleClicked: Signal = Signal(object)
  132. def __init__(self, treeData: ElTreeData, parent=None):
  133. super(ElTree, self).__init__(parent=parent)
  134. self.data = treeData
  135. # 将按钮的点击信号绑定到当前类的点击信号
  136. widgets.allTreeWidget.itemClicked.connect(lambda item: self.itemClicked.emit(item.data(0, Qt.UserRole + 1)))
  137. widgets.allTreeWidget.itemDoubleClicked.connect(
  138. lambda item: self.itemDoubleClicked.emit(item.data(0, Qt.UserRole + 1)))
  139. self.__render_items(True)
  140. # 设置 QTreeWidget 的 contextMenuPolicy 为 Qt.CustomContextMenu
  141. widgets.allTreeWidget.setContextMenuPolicy(Qt.CustomContextMenu)
  142. # 连接 customContextMenuRequested 信号到 contextMenuEvent 方法
  143. widgets.allTreeWidget.customContextMenuRequested.connect(self.contextMenuEvent)
  144. def __render_items(self, is_clear: bool):
  145. if is_clear:
  146. widgets.allTreeWidget.clear()
  147. widgets.qureyTreeWidget.clear()
  148. widgets.allTreeWidget.setColumnCount(1)
  149. widgets.allTreeWidget.setHeaderHidden(True)
  150. widgets.qureyTreeWidget.setColumnCount(1)
  151. widgets.qureyTreeWidget.setHeaderHidden(True)
  152. if self.data.items is not None:
  153. # 转为字典
  154. mapping: dict[any, TreeWidgetItem] = dict(zip([i.id for i in self.data.items], self.data.items))
  155. # 树容器
  156. treeWidgetItems: list[QTreeWidgetItem] = []
  157. for d in self.data.items:
  158. # 如果找不到父级项,则是根节点
  159. parent: TreeWidgetItem = mapping.get(d.parent_id)
  160. if parent is None:
  161. treeWidgetItems.append(d.treeWidgetItem)
  162. else:
  163. parent.treeWidgetItem.addChild(d.treeWidgetItem)
  164. # 挂载到树上
  165. widgets.allTreeWidget.insertTopLevelItems(0, treeWidgetItems)
  166. def contextMenuEvent(self, pos):
  167. try:
  168. # 获取当前选中的项目
  169. items = widgets.allTreeWidget.selectedItems()
  170. item = items[0]
  171. if item:
  172. # 创建右键菜单
  173. context_menu = QMenu(self)
  174. if item.parent() is None:
  175. # 根节点菜单
  176. action = QAction("删除库", self)
  177. action.triggered.connect(self.delete_db)
  178. context_menu.addAction(action)
  179. elif item.parent().parent() is None:
  180. # 父节点菜单
  181. action1 = QAction("删除", self)
  182. action1.triggered.connect(self.delete_js)
  183. context_menu.addAction(action1)
  184. else:
  185. # 子节点菜单
  186. action = QAction("删除表", self)
  187. action.triggered.connect(self.delete_item)
  188. context_menu.addAction(action)
  189. action2 = QAction("导出", self)
  190. action2.triggered.connect(self.export_item)
  191. context_menu.addAction(action2)
  192. # # 创建右键菜单
  193. # context_menu = QMenu(self)
  194. #
  195. # # 添加删除选项
  196. # delete_action = QAction("删除", self)
  197. # delete_action.triggered.connect(self.delete_item)
  198. # context_menu.addAction(delete_action)
  199. #
  200. # # 添加导出选项
  201. # export_action = QAction("导出", self)
  202. # export_action.triggered.connect(self.export_item)
  203. # context_menu.addAction(export_action)
  204. context_menu.exec(widgets.allTreeWidget.mapToGlobal(pos))
  205. except:
  206. pass
  207. def delete_js(self):
  208. #选中当前计算
  209. selected_items = widgets.allTreeWidget.selectedItems()
  210. item = selected_items[0]
  211. parent_name = item.text(0)
  212. # 获取父节点
  213. db_item = item.parent()
  214. if not db_item:
  215. QMessageBox.warning(self, '警告', '所选项目没有父节点')
  216. return
  217. dbname = db_item.text(0)
  218. dbpath = os.path.join(os.path.abspath('./SQL'), f"{dbname}.db")
  219. # 确定要清空的表
  220. tables_to_delete = []
  221. if parent_name == '水准测段高差稳定计算':
  222. tables_to_delete = ['GC_Input_Param', 'GC_Input_Point', 'GC_Output_Point']
  223. elif parent_name == '控制网复测平面基准计算':
  224. tables_to_delete = ['GS_Input_Param', 'GS_Input_Point', 'GS_Result_Point', 'GS_Trans_Param',
  225. 'GS_Trans_Point']
  226. elif parent_name == '平面控制网稳定性计算':
  227. tables_to_delete = ['WD_Input_Param', 'WD_Input_Point', 'WD_Result_Param', 'WD_Result_Point']
  228. else:
  229. QMessageBox.warning(self, '警告', '未知的父节点')
  230. return
  231. # 确认删除操作
  232. reply = QMessageBox.question(self, '确认删除', f'确定要删除所有 {parent_name} 的计算数据吗?',
  233. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  234. if reply == QMessageBox.No:
  235. return
  236. # 清空表
  237. try:
  238. conn = sqlite3.connect(dbpath)
  239. cursor = conn.cursor()
  240. for table in tables_to_delete:
  241. cursor.execute(f"DELETE FROM {table}")
  242. conn.commit()
  243. conn.close()
  244. QMessageBox.information(self, '成功', f'计算 {parent_name} 中的数据已清空')
  245. # 刷新树状图
  246. self.refresh_tree()
  247. except Exception as e:
  248. QMessageBox.critical(self, '错误', f'删除数据时出错: {str(e)}')
  249. def delete_db(self):
  250. # 获取当前选中的项目
  251. selected_items = widgets.allTreeWidget.selectedItems()
  252. item = selected_items[0]
  253. dbname = item.text(0)
  254. dbpath = os.path.join(os.path.abspath('./SQL'), f"{dbname}.db")
  255. # 确认删除操作
  256. reply = QMessageBox.question(self, '确认删除', f'确定要删除项目 {dbname} 吗?',
  257. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  258. if reply == QMessageBox.No:
  259. return
  260. try:
  261. # 从 QTreeWidget 中移除节点
  262. widgets.allTreeWidget.takeTopLevelItem(widgets.allTreeWidget.indexOfTopLevelItem(item))
  263. try:
  264. widgets.qureyTreeWidget.takeTopLevelItem(widgets.allTreeWidget.indexOfTopLevelItem(item))
  265. except:
  266. pass
  267. # 强制垃圾回收
  268. gc.collect()
  269. os.remove(dbpath)
  270. QMessageBox.information(self, '成功', f'项目 {dbname} 中的数据已删除')
  271. # 刷新树状图
  272. self.refresh_tree()
  273. # # 模拟点击 Enter 键 实现程序自动刷新的效果
  274. # QTest.keyClick(widgets.allTreeWidget, Qt.Key_Return)
  275. except Exception as e:
  276. QMessageBox.critical(self, '错误', f'删除数据时出错: {str(e)}')
  277. def delete_item(self):
  278. # 获取当前选中的项目
  279. selected_items = widgets.allTreeWidget.selectedItems()
  280. if not selected_items:
  281. QMessageBox.warning(self, '警告', '请先选择一个项目')
  282. return
  283. item = selected_items[0]
  284. data = item.data(0, Qt.UserRole + 1)
  285. if not data:
  286. self.warning = QMessageBox.warning(self, '警告', '所选项目没有关联的数据')
  287. return
  288. # 获取数据库路径和表名
  289. dbname = data['listData'][0]
  290. tablename = data['listData'][2]
  291. dbpath = resource_path(os.path.join('SQL', f"{dbname}.db")) # 使用 resource_path 获取数据库路径
  292. # 确保 tablename 是 UTF-8 编码的字符串
  293. try:
  294. tablename_utf8 = tablename.encode('utf-8')
  295. except Exception as e:
  296. QMessageBox.critical(self, '错误', f'表名编码转换错误: {str(e)}')
  297. return
  298. # 获取父节点
  299. parent_item = item.parent()
  300. if not parent_item:
  301. QMessageBox.warning(self, '警告', '所选项目没有父节点')
  302. return
  303. parent_name = parent_item.text(0)
  304. # 确定要删除的表
  305. tables_to_delete = []
  306. if parent_name == '水准测段高差稳定计算':
  307. tables_to_delete = ['GC_Input_Param', 'GC_Input_Point', 'GC_Output_Point']
  308. elif parent_name == '控制网复测平面基准计算':
  309. tables_to_delete = ['GS_Input_Param', 'GS_Input_Point', 'GS_Result_Point', 'GS_Trans_Param',
  310. 'GS_Trans_Point']
  311. elif parent_name == '平面控制网稳定性计算':
  312. tables_to_delete = ['WD_Input_Param', 'WD_Input_Point', 'WD_Result_Param', 'WD_Result_Point']
  313. else:
  314. QMessageBox.warning(self, '警告', '未知的父节点')
  315. return
  316. # 确认删除操作
  317. reply = QMessageBox.question(self, '确认删除', f'确定要删除项目表 {tablename} 吗?',
  318. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  319. if reply == QMessageBox.No:
  320. return
  321. # 清空表
  322. try:
  323. conn = sqlite3.connect(dbpath)
  324. cursor = conn.cursor()
  325. for table in tables_to_delete:
  326. cursor.execute(f"DELETE FROM {table} WHERE TableName = ?", (tablename_utf8,))
  327. conn.commit()
  328. conn.close()
  329. QMessageBox.information(self, '成功', f'表 {tablename} 中的数据已从相关表中删除')
  330. # 刷新树状图
  331. self.refresh_tree()
  332. except Exception as e:
  333. QMessageBox.critical(self, '错误', f'删除数据时出错: {str(e)}')
  334. def export_item(self):
  335. file_path, ok = QFileDialog.getSaveFileName(
  336. self, # 父窗口
  337. "保存文件", # 对话框标题
  338. "", # 默认路径(刚才选择的文件夹)
  339. "表格xlsx文件 (*.xlsx);;表格xls文件 (*.xls)", # 文件过滤器
  340. )
  341. if ok and file_path:
  342. # 将路径转换为 Path 对象
  343. path = Path(file_path)
  344. # 提取文件夹名
  345. folder_name = path.parent
  346. # 提取文件名
  347. file_name = path.name
  348. # 获取当前选中的项目
  349. selected_items = widgets.allTreeWidget.selectedItems()
  350. if not selected_items:
  351. QMessageBox.warning(self, '警告', '请先选择一个项目')
  352. return
  353. item = selected_items[0]
  354. data = item.data(0, Qt.UserRole + 1)
  355. if not data:
  356. QMessageBox.warning(self, '警告', '所选项目没有关联的数据')
  357. return
  358. # 获取数据库路径和表名
  359. dbname = data['listData'][0]
  360. tablename = data['listData'][2]
  361. tablename_utf8 = tablename.encode('utf-8')
  362. dbpath = resource_path(os.path.join('SQL', f"{dbname}.db"))
  363. # 获取父节点
  364. parent_item = item.parent()
  365. if not parent_item:
  366. QMessageBox.warning(self, '警告', '所选项目没有父节点')
  367. return
  368. parent_name = parent_item.text(0)
  369. # 根据父节点名称确定导出操作
  370. if parent_name == '水准测段高差稳定计算':
  371. GCExport.main_function_initial(self, tablename_utf8, dbpath,folder_name,file_name)
  372. GCExport.main_function_result(self, tablename_utf8, dbpath,folder_name,file_name)
  373. elif parent_name == '控制网复测平面基准计算':
  374. GSExport.main_function(self, dbpath, tablename,folder_name,file_name)
  375. GSExport.main_function_initial(self, dbpath, tablename_utf8,folder_name,file_name)
  376. elif parent_name == '平面控制网稳定性计算':
  377. WDExport.main_function(self, dbpath, tablename,folder_name,file_name)
  378. WDExport.main_function_initial(self, dbpath, tablename_utf8,folder_name,file_name)
  379. else:
  380. QMessageBox.warning(self, '警告', '未知的父节点')
  381. return
  382. def refresh_tree(self):
  383. # 调用 MainWindow 的 refresh_tree 方法
  384. main_window = QApplication.instance().activeWindow()
  385. if isinstance(main_window, MainWindow):
  386. main_window.refresh_tree()
  387. # 查询
  388. # 查询
  389. class ElTree1(QWidget):
  390. """
  391. Control
  392. """
  393. itemClicked: Signal = Signal(object)
  394. itemDoubleClicked: Signal = Signal(object)
  395. def __init__(self, treeData: ElTreeData, parent=None):
  396. super(ElTree1, self).__init__(parent=parent)
  397. self.data = treeData
  398. # 将按钮的点击信号绑定到当前类的点击信号
  399. widgets.qureyTreeWidget.itemClicked.connect(lambda item: self.itemClicked.emit(item.data(0, Qt.UserRole + 1)))
  400. widgets.qureyTreeWidget.itemDoubleClicked.connect(
  401. lambda item: self.itemDoubleClicked.emit(item.data(0, Qt.UserRole + 1)))
  402. self.__render_items(True)
  403. # 设置 QTreeWidget 的 contextMenuPolicy 为 Qt.CustomContextMenu
  404. widgets.qureyTreeWidget.setContextMenuPolicy(Qt.CustomContextMenu)
  405. # 连接 customContextMenuRequested 信号到 contextMenuEvent 方法
  406. widgets.qureyTreeWidget.customContextMenuRequested.connect(self.contextMenuEvent)
  407. def __render_items(self, is_clear: bool):
  408. if is_clear:
  409. widgets.qureyTreeWidget.clear()
  410. widgets.qureyTreeWidget.setColumnCount(1)
  411. widgets.qureyTreeWidget.setHeaderHidden(True)
  412. if self.data.items is not None:
  413. # 转为字典
  414. mapping: dict[any, TreeWidgetItem] = dict(zip([i.id for i in self.data.items], self.data.items))
  415. # 树容器
  416. treeWidgetItems: list[QTreeWidgetItem] = []
  417. for d in self.data.items:
  418. # 如果找不到父级项,则是根节点
  419. parent: TreeWidgetItem = mapping.get(d.parent_id)
  420. if parent is None:
  421. treeWidgetItems.append(d.treeWidgetItem)
  422. else:
  423. parent.treeWidgetItem.addChild(d.treeWidgetItem)
  424. # 挂载到树上
  425. widgets.qureyTreeWidget.insertTopLevelItems(0, treeWidgetItems)
  426. def contextMenuEvent(self, pos):
  427. # 获取当前选中的项目
  428. try:
  429. items = widgets.qureyTreeWidget.selectedItems()
  430. item = items[0]
  431. if item:
  432. # 创建右键菜单
  433. context_menu = QMenu(self)
  434. if item.parent() is None:
  435. # 根节点菜单
  436. action = QAction("删除库", self)
  437. action.triggered.connect(self.delete_db)
  438. context_menu.addAction(action)
  439. elif item.parent().parent() is None:
  440. # 父节点菜单
  441. action1 = QAction("删除", self)
  442. action1.triggered.connect(self.delete_js)
  443. context_menu.addAction(action1)
  444. else:
  445. # 子节点菜单
  446. action = QAction("删除表", self)
  447. action.triggered.connect(self.delete_item)
  448. context_menu.addAction(action)
  449. action2 = QAction("导出", self)
  450. action2.triggered.connect(self.export_item)
  451. context_menu.addAction(action2)
  452. context_menu.exec(widgets.qureyTreeWidget.mapToGlobal(pos))
  453. except:
  454. pass
  455. def delete_js(self):
  456. #选中当前计算
  457. selected_items = widgets.qureyTreeWidget.selectedItems()
  458. item = selected_items[0]
  459. parent_name = item.text(0)
  460. # 获取父节点
  461. db_item = item.parent()
  462. if not db_item:
  463. QMessageBox.warning(self, '警告', '所选项目没有父节点')
  464. return
  465. dbname = db_item.text(0)
  466. dbpath = os.path.join(os.path.abspath('./SQL'), f"{dbname}.db")
  467. # 确定要清空的表
  468. tables_to_delete = []
  469. if parent_name == '水准测段高差稳定计算':
  470. tables_to_delete = ['GC_Input_Param', 'GC_Input_Point', 'GC_Output_Point']
  471. elif parent_name == '控制网复测平面基准计算':
  472. tables_to_delete = ['GS_Input_Param', 'GS_Input_Point', 'GS_Result_Point', 'GS_Trans_Param',
  473. 'GS_Trans_Point']
  474. elif parent_name == '平面控制网稳定性计算':
  475. tables_to_delete = ['WD_Input_Param', 'WD_Input_Point', 'WD_Result_Param', 'WD_Result_Point']
  476. else:
  477. QMessageBox.warning(self, '警告', '未知的父节点')
  478. return
  479. # 确认删除操作
  480. reply = QMessageBox.question(self, '确认删除', f'确定要删除所有 {parent_name} 的计算数据吗?',
  481. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  482. if reply == QMessageBox.No:
  483. return
  484. # 清空表
  485. try:
  486. conn = sqlite3.connect(dbpath)
  487. cursor = conn.cursor()
  488. for table in tables_to_delete:
  489. cursor.execute(f"DELETE FROM {table}")
  490. conn.commit()
  491. conn.close()
  492. QMessageBox.information(self, '成功', f'计算 {parent_name} 中的数据已清空')
  493. # 清空树状图
  494. widgets.qureyTreeWidget.clear()
  495. # 刷新树状图
  496. self.refresh_tree()
  497. # 模拟点击 Enter 键 实现程序自动刷新的效果
  498. QTest.keyClick(widgets.qureyTreeWidget, Qt.Key_Return)
  499. except Exception as e:
  500. QMessageBox.critical(self, '错误', f'删除数据时出错: {str(e)}')
  501. def delete_db(self):
  502. # 获取当前选中的项目
  503. selected_items = widgets.qureyTreeWidget.selectedItems()
  504. item = selected_items[0]
  505. dbname = item.text(0)
  506. dbpath = os.path.join(os.path.abspath('./SQL'), f"{dbname}.db")
  507. # 确认删除操作
  508. reply = QMessageBox.question(self, '确认删除', f'确定要删除项目 {dbname} 吗?',
  509. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  510. if reply == QMessageBox.No:
  511. return
  512. try:
  513. # 从 QTreeWidget 中移除节点
  514. widgets.allTreeWidget.takeTopLevelItem(widgets.allTreeWidget.indexOfTopLevelItem(item))
  515. try:
  516. widgets.qureyTreeWidget.takeTopLevelItem(widgets.allTreeWidget.indexOfTopLevelItem(item))
  517. except:
  518. pass
  519. # 强制垃圾回收
  520. gc.collect()
  521. #删除路径
  522. os.remove(dbpath)
  523. QMessageBox.information(self, '成功', f'项目 {dbname} 中的数据已删除')
  524. # 清空树状图
  525. widgets.qureyTreeWidget.clear()
  526. self.refresh_tree()
  527. # # 模拟点击 Enter 键 实现程序自动刷新的效果
  528. # QTest.keyClick(widgets.qureyTreeWidget, Qt.Key_Return)
  529. except Exception as e:
  530. QMessageBox.critical(self, '错误', f'删除数据时出错: {str(e)}')
  531. def delete_item(self):
  532. # 获取当前选中的项目
  533. selected_items = widgets.qureyTreeWidget.selectedItems()
  534. if not selected_items:
  535. QMessageBox.warning(self, '警告', '请先选择一个项目')
  536. return
  537. item = selected_items[0]
  538. data = item.data(0, Qt.UserRole + 1)
  539. if not data:
  540. self.warning = QMessageBox.warning(self, '警告', '所选项目没有关联的数据')
  541. return
  542. # 获取数据库路径和表名
  543. dbname = data['listData'][0]
  544. tablename = data['listData'][2]
  545. dbpath = resource_path(os.path.join('SQL', f"{dbname}.db"))
  546. # 确保 tablename 是 UTF-8 编码的字符串
  547. try:
  548. tablename_utf8 = tablename.encode('utf-8')
  549. except Exception as e:
  550. QMessageBox.critical(self, '错误', f'表名编码转换错误: {str(e)}')
  551. return
  552. # 获取父节点
  553. parent_item = item.parent()
  554. if not parent_item:
  555. QMessageBox.warning(self, '警告', '所选项目没有父节点')
  556. return
  557. parent_name = parent_item.text(0)
  558. # 确定要删除的表
  559. tables_to_delete = []
  560. if parent_name == '水准测段高差稳定计算':
  561. tables_to_delete = ['GC_Input_Param', 'GC_Input_Point', 'GC_Output_Point']
  562. elif parent_name == '控制网复测平面基准计算':
  563. tables_to_delete = ['GS_Input_Param', 'GS_Input_Point', 'GS_Result_Point', 'GS_Trans_Param',
  564. 'GS_Trans_Point']
  565. elif parent_name == '平面控制网稳定性计算':
  566. tables_to_delete = ['WD_Input_Param', 'WD_Input_Point', 'WD_Result_Param', 'WD_Result_Point']
  567. else:
  568. QMessageBox.warning(self, '警告', '未知的父节点')
  569. return
  570. # 确认删除操作
  571. reply = QMessageBox.question(self, '确认删除', f'确定要删除项目表 {tablename} 吗?',
  572. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  573. if reply == QMessageBox.No:
  574. return
  575. # 清空表
  576. try:
  577. conn = sqlite3.connect(dbpath)
  578. cursor = conn.cursor()
  579. for table in tables_to_delete:
  580. cursor.execute(f"DELETE FROM {table} WHERE TableName = ?", (tablename_utf8,))
  581. conn.commit()
  582. conn.close()
  583. QMessageBox.information(self, '成功', f'表 {tablename} 中的数据已从相关表中删除')
  584. # 刷新树状图
  585. self.refresh_tree()
  586. # 模拟点击 Enter 键 实现程序自动刷新的效果
  587. QTest.keyClick(widgets.qureyTreeWidget, Qt.Key_Return)
  588. except Exception as e:
  589. QMessageBox.critical(self, '错误', f'删除数据时出错: {str(e)}')
  590. def export_item(self):
  591. #对话框
  592. file_path, ok = QFileDialog.getSaveFileName(
  593. self, # 父窗口
  594. "保存文件", # 对话框标题
  595. "", # 默认路径(刚才选择的文件夹)
  596. "表格xlsx文件 (*.xlsx);;表格xls文件 (*.xls)", # 文件过滤器
  597. )
  598. if ok and file_path:
  599. # 将路径转换为 Path 对象
  600. path = Path(file_path)
  601. # 提取文件夹名
  602. folder_name = path.parent
  603. # 提取文件名
  604. file_name = path.name
  605. # 获取当前选中的项目
  606. selected_items = widgets.qureyTreeWidget.selectedItems()
  607. if not selected_items:
  608. QMessageBox.warning(self, '警告', '请先选择一个项目')
  609. return
  610. item = selected_items[0]
  611. data = item.data(0, Qt.UserRole + 1)
  612. if not data:
  613. QMessageBox.warning(self, '警告', '所选项目没有关联的数据')
  614. return
  615. # 获取数据库路径和表名
  616. dbname = data['listData'][0]
  617. tablename = data['listData'][2]
  618. tablename_utf8 = tablename.encode('utf-8')
  619. dbpath = resource_path(os.path.join('SQL', f"{dbname}.db"))
  620. # 获取父节点
  621. parent_item = item.parent()
  622. if not parent_item:
  623. QMessageBox.warning(self, '警告', '所选项目没有父节点')
  624. return
  625. parent_name = parent_item.text(0)
  626. # 根据父节点名称确定导出操作
  627. if parent_name == '水准测段高差稳定计算':
  628. GCExport.main_function_initial(self, tablename_utf8, dbpath,folder_name,file_name) # 导出初始文件
  629. GCExport.main_function_result(self, tablename_utf8, dbpath,folder_name,file_name) # 导出结果文件
  630. elif parent_name == '控制网复测平面基准计算':
  631. GSExport.main_function(self, dbpath, tablename,folder_name,file_name) # 导出结果文件
  632. GSExport.main_function_initial(self, dbpath, tablename_utf8,folder_name,file_name) # 导出初始文件
  633. elif parent_name == '平面控制网稳定性计算':
  634. WDExport.main_function(self, dbpath, tablename,folder_name,file_name) # 导出结果文件
  635. WDExport.main_function_initial(self, dbpath, tablename_utf8,folder_name,file_name) # 导出初始文件
  636. else:
  637. QMessageBox.warning(self, '警告', '未知的父节点')
  638. return
  639. def refresh_tree(self):
  640. # 调用 MainWindow 的 refresh_tree 方法
  641. main_window = QApplication.instance().activeWindow()
  642. if isinstance(main_window, MainWindow):
  643. main_window.refresh_tree()
  644. class CustomLineEdit(QLineEdit):
  645. def __init__(self, parent=None):
  646. super().__init__(parent)
  647. def contextMenuEvent(self, event):
  648. # 不执行任何操作,屏蔽右键菜单
  649. pass
  650. class CustomItemDelegate(QItemDelegate):
  651. def createEditor(self, parent, option, index):
  652. editor = CustomLineEdit(parent)
  653. return editor
  654. # class DatabaseChangeHandler(FileSystemEventHandler):
  655. # def __init__(self, main_window):
  656. # self.main_window = main_window
  657. #
  658. # def on_modified(self, event):
  659. # # 忽略 .db-journal 文件的变化
  660. # if event.src_path.endswith('.db-journal'):
  661. # return
  662. # if event.src_path.endswith('.db'):
  663. # self.main_window.refresh_tree()
  664. class MainWindow(QMainWindow):
  665. def __init__(self):
  666. QMainWindow.__init__(self)
  667. self.file_path = None # 初始化时文件路径设置为None
  668. # super().__init__()
  669. # SET AS GLOBAL WIDGETS
  670. # ///////////////////////////////////////////////////////////////
  671. self.ui = Ui_MainWindow()
  672. self.ui.setupUi(self)
  673. # 连接信号与槽函数,实现点击操作
  674. self.ui.createFile.clicked.connect(self.on_create_file_clicked)
  675. self.ui.export_2.clicked.connect(self.on_export_2_clicked)
  676. # 初始化数据库监控
  677. # self.observer = Observer()
  678. # self.observer.schedule(DatabaseChangeHandler(self), path=os.path.abspath('../SQL'), recursive=False)
  679. # self.observer.start()
  680. # self.comboBox_2 = QComboBox(self)
  681. # ...此处为省略代码...
  682. global widgets
  683. widgets = self.ui
  684. widgets.search.clicked.connect(self.buttonClick)
  685. # 设置 datainfo 页面的焦点策略,使其能够捕获键盘事件
  686. widgets.datainfo.setFocusPolicy(Qt.StrongFocus)
  687. widgets.datainfo.keyPressEvent = self.datainfo_keyPressEvent
  688. # 初始化 item_index 和 oritext
  689. self.item_index = None
  690. self.oritext = None
  691. # 设置自定义的 QItemDelegate 给 QTableView
  692. self.custom_delegate = CustomItemDelegate(self)
  693. self.ui.resultTableView1.setItemDelegate(self.custom_delegate)
  694. # 是否使用系统自带标题栏 True是不使用,False使用
  695. # ///////////////////////////////////////////////////////////////
  696. Settings.ENABLE_CUSTOM_TITLE_BAR = True
  697. # APP名称
  698. # ///////////////////////////////////////////////////////////////
  699. title = "控制网复测平面基准归算程序"
  700. description = "控制网复测平面基准归算程序"
  701. # APPLY TEXTS
  702. self.setWindowTitle(title)
  703. widgets.titleRightInfo.setText(description)
  704. # TOGGLE MENU
  705. # ///////////////////////////////////////////////////////////////
  706. widgets.toggleButton.clicked.connect(lambda: UIFunctions.toggleMenu(self, True))
  707. # SET UI DEFINITIONS
  708. # ///////////////////////////////////////////////////////////////
  709. UIFunctions.uiDefinitions(self)
  710. # QTableWidget PARAMETERS
  711. # ///////////////////////////////////////////////////////////////
  712. # widgets.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
  713. # 点击事件
  714. # ///////////////////////////////////////////////////////////////
  715. # 左边菜单
  716. # 首页
  717. widgets.btn_home.clicked.connect(self.buttonClick)
  718. # 输入表格
  719. widgets.btn_widgets.clicked.connect(self.buttonClick)
  720. # 成果预览
  721. widgets.btn_new.clicked.connect(self.buttonClick)
  722. # 数据一览
  723. widgets.btn_data.clicked.connect(self.buttonClick)
  724. # 皮肤切换
  725. widgets.btn_message.clicked.connect(self.buttonClick)
  726. # 打开上传文件夹
  727. widgets.upload.clicked.connect(self.buttonClick)
  728. # 文件计算
  729. widgets.compute.clicked.connect(self.buttonClick)
  730. # 数据一览的搜索键
  731. widgets.search.clicked.connect(self.buttonClick)
  732. # 拓展左侧栏
  733. # def openCloseLeftBox():
  734. # UIFunctions.toggleLeftBox(self, True)
  735. # widgets.toggleLeftBox.clicked.connect(openCloseLeftBox)
  736. # widgets.extraCloseColumnBtn.clicked.connect(openCloseLeftBox)
  737. # EXTRA RIGHT BOX
  738. def openCloseRightBox():
  739. UIFunctions.toggleRightBox(self, True)
  740. widgets.settingsTopBtn.clicked.connect(openCloseRightBox)
  741. # 展示APP
  742. # ///////////////////////////////////////////////////////////////
  743. self.show()
  744. # 设置主题
  745. # ///////////////////////////////////////////////////////////////
  746. if getattr(sys, 'frozen', False):
  747. absPath = os.path.dirname(os.path.abspath(sys.executable))
  748. elif __file__:
  749. absPath = os.getcwd()
  750. useCustomTheme = True
  751. self.useCustomTheme = useCustomTheme
  752. self.absPath = absPath
  753. themeFile = r"themes\py_dracula_light.qss"
  754. # 设置主题和HACKS
  755. if useCustomTheme:
  756. # LOAD AND APPLY STYLE
  757. UIFunctions.theme(self, themeFile, True)
  758. # SET HACKS
  759. AppFunctions.setThemeHack(self)
  760. # 设置主页和选择菜单
  761. # ///////////////////////////////////////////////////////////////
  762. widgets.stackedWidget.setCurrentWidget(widgets.home)
  763. widgets.btn_home.setStyleSheet(UIFunctions.selectMenu(widgets.btn_home.styleSheet()))
  764. # self.bind()
  765. # # 初始化树状数据库
  766. # self.refresh_tree()
  767. # tree_button = self.sql_init()
  768. # tree_button.itemClicked.connect(self.itembuttonClick)
  769. # tree_button.itemDoubleClicked.connect(self.itembuttonClick)
  770. # 单元格的右键
  771. def show_custom_context_menu(self, pos):
  772. # 创建一个右键菜单
  773. menu = QMenu(self.ui.resultTableView1)
  774. menu.setStyleSheet("QMenu { background-color: #FFFFFF; }")
  775. # 获取选中单元格的索引
  776. index = self.ui.resultTableView1.indexAt(pos)
  777. # # 添加菜单项和对应的操作
  778. # action_1 = QAction("操作1", self)
  779. # action_1.triggered.connect(lambda: self.do_something(index))
  780. # menu.addAction(action_1)
  781. # 添加菜单项和对应的操作
  782. action_2 = QAction("编辑单元格", self)
  783. action_2.triggered.connect(self.edit_dataclicked)
  784. menu.addAction(action_2)
  785. action_1 = QAction("删除该行", self)
  786. action_1.triggered.connect(self.del_Dataclicked)
  787. menu.addAction(action_1)
  788. action_3 = QAction("添加一行", self)
  789. action_3.triggered.connect(self.add_Dataclicked)
  790. menu.addAction(action_3)
  791. menu.exec(self.ui.resultTableView1.mapToGlobal(pos))
  792. # def closeEvent(self, event):
  793. # # 停止监控
  794. # self.observer.stop()
  795. # self.observer.join()
  796. # event.accept()
  797. # 绑定组件
  798. def bind(self):
  799. # 计算
  800. widgets.compute.clicked.connect(self.buttonClick)
  801. # 删除tableview
  802. def delete_table_view(table_view):
  803. table_view.setParent(None)
  804. table_view.deleteLater()
  805. # ///////////////////////////////////////////////////////////////
  806. def buttonClick(self):
  807. # GET BUTTON CLICKED
  808. btn = self.sender()
  809. btnName = btn.objectName()
  810. # 首页
  811. if btnName == "btn_home":
  812. widgets.stackedWidget.setCurrentWidget(widgets.home)
  813. UIFunctions.resetStyle(self, btnName)
  814. btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet()))
  815. # 输入表格
  816. if btnName == "btn_widgets":
  817. widgets.stackedWidget.setCurrentWidget(widgets.widgets)
  818. UIFunctions.resetStyle(self, btnName)
  819. btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet()))
  820. # 成果预览
  821. if btnName == "btn_new":
  822. widgets.stackedWidget.setCurrentWidget(widgets.new_page) # SET PAGE
  823. UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
  824. btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
  825. # 数据一览
  826. if btnName == "btn_data":
  827. # 初始化树状数据库
  828. self.refresh_tree()
  829. widgets.stackedWidget.setCurrentWidget(widgets.datainfo) # SET PAGE
  830. UIFunctions.resetStyle(self, btnName) # RESET ANOTHERS BUTTONS SELECTED
  831. btn.setStyleSheet(UIFunctions.selectMenu(btn.styleSheet())) # SELECT MENU
  832. # 皮肤切换
  833. if btnName == "btn_message":
  834. if self.useCustomTheme:
  835. themeFile = os.path.abspath(os.path.join(self.absPath, "themes/py_dracula_dark.qss"))
  836. UIFunctions.theme(self, themeFile, True)
  837. # SET HACKS
  838. AppFunctions.setThemeHack(self)
  839. self.useCustomTheme = False
  840. else:
  841. themeFile = os.path.abspath(os.path.join(self.absPath, "themes/py_dracula_light.qss"))
  842. UIFunctions.theme(self, themeFile, True)
  843. # SET HACKS
  844. AppFunctions.setThemeHack(self)
  845. self.useCustomTheme = True
  846. # 文件上传
  847. if btnName == "upload":
  848. # 使用 QFileDialog 获取文件路径
  849. file_path, _ = QFileDialog.getOpenFileName(
  850. self,
  851. "选择文件",
  852. "",
  853. "表格文件 (*.xls *.xlsx)"
  854. # 水准后期添加支持.xls文件
  855. )
  856. if file_path:
  857. # 处理选中的文件
  858. self.file_path = file_path # 将获取的路径保存到类的属性中
  859. UIFunctions.execute_script_based_on_selection(self, file_path)
  860. # 文件计算
  861. if btnName == "compute":
  862. if self.file_path: # 确保有文件路径后再进行处理
  863. # 计算与展示的业务代码
  864. UIFunctions.compute_show_process_excel_file(self, self.file_path)
  865. # 1秒后自动跳转
  866. QTimer.singleShot(1000, lambda: self.simulateButtonClick("btn_new"))
  867. else:
  868. QMessageBox.warning(self, '警告', '请先选择项目并上传文件')
  869. # 树状查询
  870. if btnName == "search":
  871. self.searchClick()
  872. # 输出点击回馈
  873. print(f'Button "{btnName}" pressed!')
  874. # 辅助函数,点击计算后自动跳转页面
  875. def simulateButtonClick(self, btnName):
  876. # 根据按钮名称找到对应的按钮
  877. btn = self.findChild(QObject, btnName)
  878. if btn:
  879. # 触发按钮点击事件
  880. btn.click()
  881. # 新增槽函数来调用 create_database_and_tables
  882. def on_create_file_clicked(self):
  883. Back.Program_Run.database_operations.create_database_and_tables(self, self.ui)
  884. # 定义导出数据库的槽函数
  885. def on_export_2_clicked(self):
  886. #不清楚位置的按钮(?)
  887. #方法还是那个方法
  888. # 弹出输入对话框,让用户输入文件名
  889. file_path, ok = QFileDialog.getSaveFileName(
  890. self, # 父窗口
  891. "保存文件", # 对话框标题
  892. "", # 默认路径(刚才选择的文件夹)
  893. "表格xlsx文件 (*.xlsx);;表格xls文件 (*.xls)", # 文件过滤器
  894. )
  895. if ok and file_path:
  896. # 将路径转换为 Path 对象
  897. path = Path(file_path)
  898. # 提取文件夹名
  899. folder_name = path.parent
  900. # 提取文件名
  901. file_name = path.name
  902. # 在这里处理文件保存逻辑
  903. if self.file_path:
  904. UIFunctions.export_database_to_excel(self, self.file_path, folder_name, file_name)
  905. QMessageBox.information(self, "保存成功", f"文件将保存到: {file_name}")
  906. else:
  907. QMessageBox.warning(self, '警告', '请先选择项目并上传文件')
  908. else:
  909. QMessageBox.warning(self, "取消", "用户取消了保存操作")
  910. # RESIZE EVENTS
  911. # ///////////////////////////////////////////////////////////////
  912. def resizeEvent(self, event):
  913. # Update Size Grips
  914. UIFunctions.resize_grips(self)
  915. # 鼠标点击事件
  916. # ///////////////////////////////////////////////////////////////
  917. def mousePressEvent(self, event):
  918. # SET DRAG POS WINDOW
  919. # self.dragPos = event.globalPos()
  920. self.dragPos = event.globalPosition().toPoint() # 设置鼠标拖动位置
  921. # 输出鼠标事件
  922. if event.buttons() == Qt.LeftButton:
  923. print('Mouse click: LEFT CLICK')
  924. if event.buttons() == Qt.RightButton:
  925. print('Mouse click: RIGHT CLICK')
  926. # 修改 show_custom_context_menu 调用
  927. # if event.button() == Qt.RightButton:
  928. # self.show_custom_context_menu(event.position().toPoint())
  929. # 设一个全局变量,存数据库中所有的包含内容(数据库-三种方法-表)
  930. dblist = []
  931. # 初始化数据一览(数据库全展示)
  932. def sql_init(self):
  933. # 清空 dblist 以确保每次初始化时都是空的
  934. self.dblist = []
  935. # 初始化全部数据库
  936. inpath = resource_path('SQL')
  937. # 读取所有的数据库名
  938. sqlitem = []
  939. id = 1
  940. for filename in os.listdir(inpath):
  941. # 数据库
  942. dbname = filename.split('.', -1)[0]
  943. if dbname != 'DataBase':
  944. dbpath = os.path.join(inpath, filename)
  945. sqlitem.append(TreeWidgetItem(id, 0, dbname, icon=QIcon(
  946. os.path.abspath(os.path.join(self.absPath, "images/icons/cil-clone.png")))))
  947. pid = id
  948. id = id + 1
  949. # 三种方法
  950. # 读取所有的表名(三种方式往下)
  951. db1 = sqlite3.connect(dbpath)
  952. # 获取游标
  953. cursor1 = db1.cursor()
  954. sqlstr1 = 'SELECT TableName FROM GC_Input_Param;'
  955. cursor1.execute(sqlstr1)
  956. result1 = cursor1.fetchall()
  957. if len(result1) != 0:
  958. sqlitem.append(TreeWidgetItem(id, pid, '水准测段高差稳定计算', icon=QIcon(
  959. os.path.join(self.absPath, "images/icons/cil-description.png"))))
  960. gcid = id
  961. id = id + 1
  962. for re1 in result1:
  963. str1 = re1[0].decode('utf-8')
  964. list1 = []
  965. list1.append(dbname)
  966. list1.append('水准测段高差稳定计算')
  967. list1.append(str1)
  968. self.dblist.append(list1)
  969. sqlitem.append(TreeWidgetItem(id, gcid, str1, icon=QIcon(
  970. os.path.join(self.absPath, "images/icons/cil-file.png")), extend={'listData': list1}))
  971. id = id + 1
  972. sqlstr2 = 'SELECT TableName FROM GS_Input_Param;'
  973. cursor1.execute(sqlstr2)
  974. result2 = cursor1.fetchall()
  975. if len(result2) != 0:
  976. sqlitem.append(TreeWidgetItem(id, pid, '控制网复测平面基准计算', icon=QIcon(
  977. os.path.join(self.absPath, "images/icons/cil-description.png"))))
  978. gsid = id
  979. id = id + 1
  980. for re2 in result2:
  981. str2 = re2[0].decode('utf-8')
  982. list2 = []
  983. list2.append(dbname)
  984. list2.append('控制网复测平面基准计算')
  985. list2.append(str2)
  986. self.dblist.append(list2)
  987. sqlitem.append(TreeWidgetItem(id, gsid, str2,
  988. icon=QIcon(os.path.join(self.absPath, "images/icons/cil-file.png")),
  989. extend={'listData': list2}))
  990. id = id + 1
  991. sqlstr3 = 'SELECT TableName FROM WD_Input_Param;'
  992. cursor1.execute(sqlstr3)
  993. result3 = cursor1.fetchall()
  994. if len(result3) != 0:
  995. sqlitem.append(TreeWidgetItem(id, pid, '平面控制网稳定性计算', icon=QIcon(
  996. os.path.join(self.absPath, "images/icons/cil-description.png"))))
  997. wdid = id
  998. id = id + 1
  999. for re3 in result3:
  1000. str3 = re3[0].decode('utf-8')
  1001. list3 = []
  1002. list3.append(dbname)
  1003. list3.append('平面控制网稳定性计算')
  1004. list3.append(str3)
  1005. self.dblist.append(list3)
  1006. sqlitem.append(TreeWidgetItem(id, wdid, str3,
  1007. icon=QIcon(os.path.join(self.absPath, "images/icons/cil-file.png")),
  1008. extend={'listData': list3}))
  1009. id = id + 1
  1010. button = ElTree(ElTreeData(sqlitem))
  1011. return button
  1012. # 刷新树状图
  1013. def refresh_tree(self):
  1014. # 清空当前的树状图
  1015. widgets.allTreeWidget.clear()
  1016. # 重新初始化树状图
  1017. tree_button = self.sql_init()
  1018. tree_button.itemClicked.connect(self.itembuttonClick)
  1019. tree_button.itemDoubleClicked.connect(self.itembuttonClick)
  1020. # 关键词查询
  1021. def searchClick(self):
  1022. # GET BUTTON CLICKED
  1023. btn = self.sender()
  1024. btnName = btn.objectName()
  1025. # 获取文本
  1026. text1 = self.ui.lineEdit_2.text()
  1027. # 符合的list
  1028. fhlist = []
  1029. # 查询(待优化)
  1030. for list1 in self.dblist:
  1031. for li in list1:
  1032. if text1 in li:
  1033. fhlist.append(list1)
  1034. break
  1035. # 更新item值
  1036. sqlitem = []
  1037. # 前两层是否一致
  1038. str1 = ''
  1039. str2 = ''
  1040. id = 1
  1041. pid = 0
  1042. fid = 0
  1043. zdy = []
  1044. for list2 in fhlist:
  1045. dbname = list2[0]
  1046. if dbname != str1:
  1047. str1 = dbname
  1048. pid = id
  1049. str2 = ''
  1050. sqlitem.append(TreeWidgetItem(id, 0, dbname, icon=QIcon(
  1051. os.path.join(self.absPath, "images/icons/cil-clone.png"))))
  1052. zdy1 = []
  1053. zdy1.append(id)
  1054. zdy1.append(0)
  1055. zdy1.append(dbname)
  1056. zdy.append(zdy1)
  1057. id = id + 1
  1058. mename = list2[1]
  1059. if mename != str2:
  1060. str2 = mename
  1061. fid = id
  1062. sqlitem.append(TreeWidgetItem(id, pid, mename, icon=QIcon(
  1063. os.path.join(self.absPath, "images/icons/cil-description.png"))))
  1064. zdy1 = []
  1065. zdy1.append(id)
  1066. zdy1.append(pid)
  1067. zdy1.append(mename)
  1068. zdy.append(zdy1)
  1069. id = id + 1
  1070. sqlitem.append(TreeWidgetItem(id, fid, list2[2], icon=QIcon(
  1071. os.path.join(self.absPath, "images/icons/cil-file.png")), extend={'listData': list2}))
  1072. zdy1 = []
  1073. zdy1.append(id)
  1074. zdy1.append(fid)
  1075. zdy1.append(list2[2])
  1076. zdy.append(zdy1)
  1077. id = id + 1
  1078. search_button = ElTree1(ElTreeData(sqlitem))
  1079. search_button.itemClicked.connect(self.itembuttonClick1)
  1080. search_button.itemDoubleClicked.connect(self.itembuttonClick1)
  1081. # 隐藏默认label
  1082. self.ui.defaultLabel.setVisible(False)
  1083. # 清空搜索框内容
  1084. self.ui.lineEdit_2.clear()
  1085. # 全树的item展示
  1086. def itembuttonClick(self):
  1087. # 判定是否获取的是根节点
  1088. pd = 1
  1089. select_item = self.ui.allTreeWidget.currentItem()
  1090. # 获取点击的item的text和它对应的上两个节点
  1091. str1 = select_item.text(0)
  1092. current_text = '' # 初始化 current_text
  1093. str3 = '' # 初始化 str3
  1094. try:
  1095. pa_item = select_item.parent()
  1096. current_text = pa_item.text(0)
  1097. z_item = pa_item.parent()
  1098. str3 = z_item.text(0)
  1099. except:
  1100. pd = -1
  1101. if current_text == '':
  1102. pd = -1
  1103. if str3 == '':
  1104. pd = -1
  1105. if pd == -1:
  1106. pass
  1107. else:
  1108. # 数据库目录
  1109. inpath = resource_path('SQL')
  1110. file_path = inpath + '\\' + str3 + '.db'
  1111. # 数据库路径,哪种方法,表名
  1112. self.selectModel = UIFunctions.search_data_to_show(self, file_path, current_text, str1)
  1113. # self.ui.resultTableView1.doubleClicked.connect(self.seleceModel_itemclicked)
  1114. # 设置右键菜单策略为CustomContextMenu
  1115. self.ui.resultTableView1.setContextMenuPolicy(Qt.CustomContextMenu)
  1116. # 关联自定义的右键菜单方法到customContextMenuRequested信号
  1117. self.ui.resultTableView1.customContextMenuRequested.connect(self.show_custom_context_menu)
  1118. # 关闭编辑
  1119. self.ui.resultTableView1.setEditTriggers(QTableView.EditTrigger.NoEditTriggers)
  1120. # 搜索的item展示
  1121. def itembuttonClick1(self):
  1122. # 判定是否获取的是根节点
  1123. pd = 1
  1124. select_item = self.ui.qureyTreeWidget.currentItem()
  1125. # 获取点击的item的text和它对应的上两个节点
  1126. str1 = select_item.text(0)
  1127. current_text = '' # 初始化 current_text
  1128. str3 = '' # 初始化 str3
  1129. try:
  1130. pa_item = select_item.parent()
  1131. current_text = pa_item.text(0)
  1132. z_item = pa_item.parent()
  1133. str3 = z_item.text(0)
  1134. except:
  1135. pd = -1
  1136. if current_text == '':
  1137. pd = -1
  1138. if str3 == '':
  1139. pd = -1
  1140. if pd == -1:
  1141. pass
  1142. else:
  1143. # 数据库目录
  1144. inpath = resource_path('SQL')
  1145. file_path = inpath + '\\' + str3 + '.db'
  1146. # 数据库路径,哪种方法,表名
  1147. self.selectModel = UIFunctions.search_data_to_show(self, file_path, current_text, str1)
  1148. # self.ui.resultTableView1.doubleClicked.connect(self.seleceModel_itemclicked)
  1149. # 设置右键菜单策略为CustomContextMenu
  1150. self.ui.resultTableView1.setContextMenuPolicy(Qt.CustomContextMenu)
  1151. # 关联自定义的右键菜单方法到customContextMenuRequested信号
  1152. self.ui.resultTableView1.customContextMenuRequested.connect(self.show_custom_context_menu)
  1153. # 关闭编辑
  1154. self.ui.resultTableView1.setEditTriggers(QTableView.EditTrigger.NoEditTriggers)
  1155. # 键盘回车事件,目前用于搜索按钮
  1156. def datainfo_keyPressEvent(self, event):
  1157. if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
  1158. # 检查 lineEdit_2 中是否有内容
  1159. if widgets.lineEdit_2.text():
  1160. # 模拟 search 按钮点击事件
  1161. self.ui.search.click()
  1162. else:
  1163. # 检查是否有选中的项
  1164. select_item = self.ui.allTreeWidget.currentItem()
  1165. if not select_item:
  1166. select_item = self.ui.qureyTreeWidget.currentItem()
  1167. if select_item:
  1168. # 用于编辑完成操作
  1169. response = QMessageBox.question(None, "提示", "是(Yes)否(No)更新数据?",
  1170. QMessageBox.Yes | QMessageBox.No)
  1171. if response == QMessageBox.Yes:
  1172. self.update_dataclicked()
  1173. else:
  1174. print("没有数据可插入数据库")
  1175. else:
  1176. QMessageBox.warning(self, '警告', '请先选择一个项目')
  1177. else:
  1178. # 调用默认的 keyPressEvent 处理其他按键事件
  1179. super(widgets.datainfo.__class__, widgets.datainfo).keyPressEvent(event)
  1180. # 右键对应行可删除对应行
  1181. def del_Dataclicked(self):
  1182. curIndex = self.selectModel.currentIndex()
  1183. self.ui.resultTableView1.model().removeRow(curIndex.row())
  1184. # 双击开启编辑
  1185. self.edit_dataclicked()
  1186. # 编辑完了集中读取
  1187. def update_dataclicked(self):
  1188. inputmodel = self.ui.resultTableView1.model()
  1189. # 转化为list
  1190. list1 = []
  1191. ii = 0
  1192. while ii < inputmodel.rowCount():
  1193. list2 = []
  1194. jj = 0
  1195. while jj < inputmodel.columnCount():
  1196. index1 = inputmodel.index(ii, jj)
  1197. list2.append(inputmodel.data(index1))
  1198. jj = jj + 1
  1199. list1.append(list2)
  1200. ii = ii + 1
  1201. # 读取对应的db和方法
  1202. select_item = self.ui.allTreeWidget.currentItem()
  1203. if not select_item:
  1204. select_item = self.ui.qureyTreeWidget.currentItem()
  1205. if not select_item:
  1206. QMessageBox.warning(self, '警告', '请先选择一个项目')
  1207. return
  1208. # 获取数据库路径和表名
  1209. tablename = select_item.text(0)
  1210. tablename_utf8 = tablename.encode('utf-8')
  1211. # 获取父节点
  1212. parent_item = select_item.parent()
  1213. parent_name = parent_item.text(0)
  1214. dbname = parent_item.parent().text(0)
  1215. dbpath = resource_path(os.path.join('SQL', f"{dbname}.db")) # 使用 resource_path 获取数据库路径
  1216. # 重新组织表的内容,方便重新计算
  1217. UIFunctions.update_to_db(self, list1, parent_name, tablename_utf8, dbpath)
  1218. # 1秒后自动跳转
  1219. QTimer.singleShot(1000, lambda: self.simulateButtonClick("btn_new"))
  1220. # 数据库路径,哪种方法,表名
  1221. self.selectModel = UIFunctions.search_data_to_show(self, dbpath, parent_name, tablename)
  1222. # self.ui.resultTableView1.doubleClicked.connect(self.seleceModel_itemclicked)
  1223. # 设置右键菜单策略为CustomContextMenu
  1224. self.ui.resultTableView1.setContextMenuPolicy(Qt.CustomContextMenu)
  1225. # 关联自定义的右键菜单方法到customContextMenuRequested信号
  1226. self.ui.resultTableView1.customContextMenuRequested.connect(self.show_custom_context_menu)
  1227. # 把编辑状态改回去
  1228. self.ui.resultTableView1.setEditTriggers(QTableView.EditTrigger.NoEditTriggers)
  1229. def edit_dataclicked(self):
  1230. # 所有条件都可以开启编辑
  1231. self.ui.resultTableView1.setEditTriggers(QTableView.EditTrigger.DoubleClicked)
  1232. # 安装事件过滤器
  1233. self.ui.resultTableView1.viewport().installEventFilter(self)
  1234. def eventFilter(self, source, event):
  1235. if event.type() == QEvent.MouseButtonDblClick:
  1236. # 获取双击的单元格
  1237. self.item_index = self.ui.resultTableView1.indexAt(event.position().toPoint())
  1238. if self.item_index.isValid():
  1239. # 保留原先的内容
  1240. ori = self.ui.resultTableView1.model().itemData(self.item_index)
  1241. self.oritext = ori[0] if 0 in ori else ''
  1242. # 清空单元格内容
  1243. self.ui.resultTableView1.model().setData(self.item_index, '')
  1244. if event.type() == QEvent.MouseButtonPress:
  1245. # 检查是否为空
  1246. if self.item_index is not None and len(self.ui.resultTableView1.model().itemData(self.item_index)[0]) == 0:
  1247. # 自动填充原来的内容
  1248. self.ui.resultTableView1.model().setData(self.item_index, self.oritext)
  1249. return super().eventFilter(source, event)
  1250. def add_Dataclicked(self):
  1251. # 获取显示用的model
  1252. inputmodel = self.ui.resultTableView1.model()
  1253. rowcount = inputmodel.rowCount()
  1254. colcount = inputmodel.columnCount()
  1255. # 添加一行
  1256. self.ui.resultTableView1.model().insertRow(rowcount)
  1257. # 所有条件都可以开启编辑
  1258. # 双击开启编辑
  1259. self.edit_dataclicked()
  1260. def on_download_1_clicked(self):
  1261. # 获取应用的安装目录
  1262. app_install_dir = os.getcwd()
  1263. # 构建数据库路径
  1264. db_path = resource_path(os.path.join('SQL', 'DataBase.db'))
  1265. file_name = "平面控制网稳定性计算示例表.xlsx"
  1266. excelname_utf8 = file_name.encode('utf-8')
  1267. file_path, ok = QFileDialog.getSaveFileName(
  1268. self, # 父窗口
  1269. "保存文件", # 对话框标题
  1270. "", # 默认路径(刚才选择的文件夹)
  1271. "表格xlsx文件 (*.xlsx);;表格xls文件 (*.xls)", # 文件过滤器
  1272. )
  1273. if ok and file_path:
  1274. # 将路径转换为 Path 对象
  1275. path = Path(file_path)
  1276. # 提取文件夹名
  1277. folder_name = path.parent
  1278. # 提取文件名
  1279. file_name = path.name
  1280. # 在这里处理文件保存逻辑
  1281. Back.WD.WDExport.main_function_example(self, db_path, excelname_utf8,folder_name,file_name)
  1282. # QMessageBox.information(self, "保存成功", f"文件将保存到: {file_name}")
  1283. else:
  1284. QMessageBox.warning(self, "取消", "用户取消了保存操作")
  1285. def on_download_2_clicked(self):
  1286. # 获取应用的安装目录
  1287. app_install_dir = os.getcwd()
  1288. # 构建数据库路径
  1289. db_path = resource_path(os.path.join('SQL', 'DataBase.db'))
  1290. file_name = "控制网复测平面基准计算示例表.xlsx"
  1291. excelname_utf8 = file_name.encode('utf-8')
  1292. file_path, ok = QFileDialog.getSaveFileName(
  1293. self, # 父窗口
  1294. "保存文件", # 对话框标题
  1295. "", # 默认路径(刚才选择的文件夹)
  1296. "表格xlsx文件 (*.xlsx);;表格xls文件 (*.xls)", # 文件过滤器
  1297. )
  1298. if ok and file_path:
  1299. # 将路径转换为 Path 对象
  1300. path = Path(file_path)
  1301. # 提取文件夹名
  1302. folder_name = path.parent
  1303. # 提取文件名
  1304. file_name = path.name
  1305. # 在这里处理文件保存逻辑
  1306. Back.GS.GSExport.main_function_example(self, db_path, excelname_utf8,folder_name,file_name)
  1307. # QMessageBox.information(self, "保存成功", f"文件将保存到: {file_name}")
  1308. else:
  1309. QMessageBox.warning(self, "取消", "用户取消了保存操作")
  1310. def on_download_3_clicked(self):
  1311. # 获取应用的安装目录
  1312. app_install_dir = os.getcwd()
  1313. # 构建数据库路径
  1314. db_path = resource_path(os.path.join('SQL', 'DataBase.db'))
  1315. file_name = "水准测段高差稳定计算示例文件.xlsx"
  1316. utf_en = file_name.encode('utf-8')
  1317. file_path, ok = QFileDialog.getSaveFileName(
  1318. self, # 父窗口
  1319. "保存文件", # 对话框标题
  1320. "", # 默认路径(刚才选择的文件夹)
  1321. "表格xlsx文件 (*.xlsx);;表格xls文件 (*.xls)", # 文件过滤器
  1322. )
  1323. if ok and file_path:
  1324. # 将路径转换为 Path 对象
  1325. path = Path(file_path)
  1326. # 提取文件夹名
  1327. folder_name = path.parent
  1328. # 提取文件名
  1329. file_name = path.name
  1330. # 在这里处理文件保存逻辑
  1331. Back.GC.GCExport.main_function_example(self, utf_en, db_path,folder_name,file_name)
  1332. # QMessageBox.information(self, "保存成功", f"文件将保存到: {file_name}")
  1333. else:
  1334. QMessageBox.warning(self, "取消", "用户取消了保存操作")
  1335. # 调用main_function_example函数
  1336. def main():
  1337. app = QApplication(sys.argv)
  1338. app.setWindowIcon(QIcon("icon.ico"))
  1339. window = MainWindow()
  1340. sys.exit(app.exec())
  1341. if __name__ == "__main__":
  1342. main()