commit ed6b60e14a7c365eb0f634c1c5776e00f406e9fa
Author: qrbian <1641582285@qq.com>
Date: Fri Mar 7 10:37:50 2025 +0800
first
diff --git a/Scripts/.idea/.gitignore b/Scripts/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/Scripts/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/Scripts/.idea/Scripts.iml b/Scripts/.idea/Scripts.iml
new file mode 100644
index 0000000..8437fe6
--- /dev/null
+++ b/Scripts/.idea/Scripts.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Scripts/.idea/inspectionProfiles/profiles_settings.xml b/Scripts/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/Scripts/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Scripts/.idea/misc.xml b/Scripts/.idea/misc.xml
new file mode 100644
index 0000000..9de2865
--- /dev/null
+++ b/Scripts/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Scripts/.idea/modules.xml b/Scripts/.idea/modules.xml
new file mode 100644
index 0000000..d038d5e
--- /dev/null
+++ b/Scripts/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Scripts/.vscode/settings.json b/Scripts/.vscode/settings.json
new file mode 100644
index 0000000..0ce7a27
--- /dev/null
+++ b/Scripts/.vscode/settings.json
@@ -0,0 +1,20 @@
+{
+ "MicroPython.executeButton": [
+ {
+ "text": "▶",
+ "tooltip": "运行",
+ "alignment": "left",
+ "command": "extension.executeFile",
+ "priority": 3.5
+ }
+ ],
+ "MicroPython.syncButton": [
+ {
+ "text": "$(sync)",
+ "tooltip": "同步",
+ "alignment": "left",
+ "command": "extension.execute",
+ "priority": 4
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Scripts/@AutomationLog.txt b/Scripts/@AutomationLog.txt
new file mode 100644
index 0000000..243e607
--- /dev/null
+++ b/Scripts/@AutomationLog.txt
@@ -0,0 +1,26 @@
+2024-04-11 20:23:56.466 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: ListItemControl}
+2024-04-11 20:24:06.474 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: ListItemControl}
+2024-04-11 20:24:16.517 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: ListItemControl}
+2024-04-11 20:24:26.567 pydevd_resolver.py[189] _get_py_dictionary -> 2024-04-11 21:07:33.369 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {Control: 6160838, ControlType: DataGridControl}
+2024-04-11 21:07:45.575 pydevd_resolver.py[189] _get_py_dictionary -> 2024-04-11 21:17:30.731 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-04-11 21:17:41.020 pydevd_resolver.py[189] _get_py_dictionary -> 2024-04-11 21:18:15.553 pydevd_resolver.py[189] _get_py_dictionary -> 2024-04-11 21:18:47.237 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-27 19:00:04.823 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {Name: 'AACE 登录', ControlType: WindowControl}
+2024-05-27 19:00:14.991 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {Name: 'AACE 登录', ControlType: WindowControl}
+2024-05-27 19:00:25.181 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {Name: 'AACE 登录', ControlType: WindowControl}
+2024-05-27 19:00:35.334 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-28 16:48:40.572 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: ListControl}
+2024-05-28 16:48:50.705 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: ListControl}
+2024-05-28 16:49:00.704 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-29 15:21:38.378 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:21:48.827 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:21:59.232 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:22:09.638 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:22:19.706 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:22:30.139 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:22:40.564 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 15:22:51.016 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-29 15:25:05.120 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: DataGridControl}
+2024-05-29 15:25:15.708 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: DataGridControl}
+2024-05-29 15:25:26.312 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: DataGridControl}
+2024-05-29 15:25:36.881 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: DataGridControl}
+2024-05-29 15:25:47.480 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-29 17:20:34.260 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 17:20:44.778 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: DataGridControl}
+2024-05-29 17:20:55.294 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-29 17:22:53.176 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-29 17:23:27.293 pydevd_resolver.py[189] _get_py_dictionary -> Find Control Timeout(10s): {ControlType: DataGridControl}
+2024-05-29 17:23:37.679 pydevd_resolver.py[189] _get_py_dictionary -> 2024-05-29 17:24:09.109 pydevd_resolver.py[189] _get_py_dictionary -> 2025-01-21 13:49:35.431 1.py[354] click_create_table -> 2025-01-22 11:04:23.034 aacecontrol.py[493] is_finished -> Find Control Timeout(10s): {ClassName: 'TMyListView', ControlType: ListControl}
+2025-01-22 11:04:37.901 pydevd_resolver.py[189] _get_py_dictionary ->
\ No newline at end of file
diff --git a/Scripts/Data/1.txt b/Scripts/Data/1.txt
new file mode 100644
index 0000000..eeda195
--- /dev/null
+++ b/Scripts/Data/1.txt
@@ -0,0 +1,121 @@
+ .ANL
+ 230818E.run
+ : 2023/8/18
+ : 2024/4/11
+
+
+-----------------------------------------------------------------------------------------
+1. δֵ, ͨ: 1
+
+Pk# Type Cl. CLP Group Digit Conc mAU Start Pos R A Weight Dilution
+-----------------------------------------------------------------------------------------
+
+ 0 B 0 1 0 8414 0.0000 0.00 807 813 0 0 1.000 1.000
+ 1 P & 0 0 0 25031 0.0000 362.23 840 899 0 0 1.000 1.000
+ 2 D A 0 0 0 25282 0.0000 367.70 960 1017 0 0 1.000 1.000
+ 3 N A 0 0 0 8531 0.0000 2.55 1080 1157 0 0 1.000 1.000
+ 4 C A 0 0 0 11168 2.0000 60.03 1200 1258 0 0 1.000 1.000
+ 5 C A 0 0 0 14476 4.0000 132.14 1320 1380 0 0 1.000 1.000
+ 6 C A 0 0 0 18484 6.0000 219.51 1440 1496 0 0 1.000 1.000
+ 7 C A 0 0 0 21860 8.0000 293.10 1560 1612 0 0 1.000 1.000
+ 8 C A 0 0 0 25795 10.0000 378.88 1680 1739 0 0 1.000 1.000
+ 9 N A 0 0 0 8553 0.6484 3.03 1800 1877 0 0 1.000 1.000
+ 10 S A 0 0 0 14226 3.7452 126.69 1920 1970 0 0 1.000 1.000
+ 11 S A 0 0 0 11593 2.3079 69.30 2040 2086 0 0 1.000 1.000
+ 12 S A 0 0 0 12282 2.6840 84.32 2160 2212 0 0 1.000 1.000
+ 13 S A 0 0 0 8448 0.5911 0.74 2280 2357 0 0 1.000 1.000
+ 14 S A 0 0 0 21703 7.8267 289.68 2400 2451 0 0 1.000 1.000
+ 15 S C 0 0 0 27638 11.0665 419.06 2520 2564 0 0 1.000 1.000
+ 16 S A 0 0 0 11761 2.3996 72.96 2640 2695 0 0 1.000 1.000
+ 17 S A 0 0 0 12285 2.6856 84.38 2760 2818 0 0 1.000 1.000
+ 18 S A 0 0 0 8496 0.6173 1.79 2880 2921 0 0 1.000 1.000
+ 19 S A 0 0 0 8466 0.6009 1.13 3000 3081 0 0 1.000 1.000
+ 20 S A 0 0 0 16361 4.9106 173.23 3120 3172 0 0 1.000 1.000
+ 21 S A 0 0 0 8570 0.6577 3.40 3240 3281 0 0 1.000 1.000
+ 22 S A 0 0 0 8690 0.7232 6.02 3360 3413 0 0 1.000 1.000
+ 23 S A 0 0 0 8584 0.6653 3.71 3480 3523 0 0 1.000 1.000
+ 24 S A 0 0 0 35741 15.4898 595.69 3600 3653 0 0 1.000 1.000
+ 25 S A 0 0 0 41497 18.6319 721.16 3720 3772 0 0 1.000 1.000
+ 26 S A 0 0 0 23084 8.5806 319.79 3840 3894 0 0 1.000 1.000
+ 27 S A 0 0 0 20095 6.9490 254.63 3960 4015 0 0 1.000 1.000
+ 28 S A 0 0 0 23096 8.5871 320.05 4080 4138 0 0 1.000 1.000
+ 29 S A 0 0 0 23188 8.6374 322.05 4200 4257 0 0 1.000 1.000
+ 30 S A 0 0 0 9208 1.0059 17.31 4320 4396 0 0 1.000 1.000
+ 31 S A 0 0 0 20005 6.8998 252.67 4440 4495 0 0 1.000 1.000
+ 32 S A 0 0 0 25446 9.8700 371.27 4560 4614 0 0 1.000 1.000
+ 33 S A 0 0 0 16559 5.0187 177.55 4680 4737 0 0 1.000 1.000
+ 34 S A 0 0 0 13113 3.1376 102.43 4800 4865 0 0 1.000 1.000
+ 35 S A 0 0 0 60146 28.8121 1127.69 4920 4977 0 0 1.000 1.000
+ 36 S O 0 0 0 91039 45.6760 1801.11 5040 5093 0 0 1.000 1.000
+ 37 S A 0 0 0 9374 1.0966 20.93 5160 5236 0 0 1.000 1.000
+ 38 S A 0 0 0 20797 7.3322 269.93 5280 5331 0 0 1.000 1.000
+ 39 S A 0 0 0 8810 0.7887 8.63 5400 5477 0 0 1.000 1.000
+ 40 S A 0 0 0 8622 0.6861 4.53 5520 5597 0 0 1.000 1.000
+ 41 S A 0 0 0 8663 0.7084 5.43 5640 5681 0 0 1.000 1.000
+ 42 S A 0 0 0 8687 0.7215 5.95 5760 5805 0 0 1.000 1.000
+ 43 S A 0 0 0 20987 7.4359 274.07 5880 5929 0 0 1.000 1.000
+ 44 S A 0 0 0 9483 1.1561 23.30 6000 6048 0 0 1.000 1.000
+ 45 S A 0 0 0 27405 10.9394 413.98 6120 6170 0 0 1.000 1.000
+ 46 S A 0 0 0 8848 0.8094 9.46 6240 6317 0 0 1.000 1.000
+ 47 B A 0 0 0 8541 0.6418 0.00 6480 6536 0 0 1.000 1.000
+ 48 D A 0 0 0 26215 10.2898 385.27 6600 6652 0 0 1.000 1.000
+ 49 B 0 1 0 8728 0.0000 0.00 6993 6999 0 0 1.000 1.000
+
+
+-----------------------------------------------------------------------------------------
+2. ֵ, ͨ: 1
+
+Pk# Type Cl. CLP Group Digit Conc mAU Start Pos R A Weight Dilution
+-----------------------------------------------------------------------------------------
+
+ 0 B 0 1 0 8414 0.5666 0.00 807 813 0 0 1.000 1.000
+ 1 P & 0 0 0 25029 9.7020 362.18 840 899 0 0 1.000 1.000
+ 2 D A 0 0 0 25277 9.8384 367.59 960 1017 0 0 1.000 1.000
+ 3 N A 0 0 0 8523 0.6265 2.38 1080 1157 0 0 1.000 1.000
+ 4 C A 0 0 0 11153 2.0726 59.71 1200 1258 0 0 1.000 1.000
+ 5 C A 0 0 0 14445 3.8826 131.47 1320 1380 0 0 1.000 1.000
+ 6 C A 0 0 0 18430 6.0737 218.33 1440 1496 0 0 1.000 1.000
+ 7 C A 0 0 0 21778 7.9145 291.32 1560 1612 0 0 1.000 1.000
+ 8 C A 0 0 0 25674 10.0566 376.24 1680 1739 0 0 1.000 1.000
+ 9 N A 0 0 0 8528 0.6293 2.49 1800 1877 0 0 1.000 1.000
+ 10 S A 0 0 0 14156 3.7237 125.17 1920 1970 0 0 1.000 1.000
+ 11 S A 0 0 0 11538 2.2843 68.10 2040 2086 0 0 1.000 1.000
+ 12 S A 0 0 0 12214 2.6559 82.83 2160 2212 0 0 1.000 1.000
+ 13 S A 0 0 0 8414 0.5666 0.00 2280 2357 0 0 1.000 1.000
+ 14 S A 0 0 0 21516 7.7704 285.61 2400 2451 0 0 1.000 1.000
+ 15 S C 0 0 0 27363 10.9853 413.06 2520 2564 0 0 1.000 1.000
+ 16 S A 0 0 0 11675 2.3596 71.09 2640 2695 0 0 1.000 1.000
+ 17 S A 0 0 0 12186 2.6405 82.22 2760 2818 0 0 1.000 1.000
+ 18 S A 0 0 0 8448 0.5853 0.74 2880 2921 0 0 1.000 1.000
+ 19 S A 0 0 0 8416 0.5677 0.04 3000 3081 0 0 1.000 1.000
+ 20 S A 0 0 0 16175 4.8338 169.18 3120 3172 0 0 1.000 1.000
+ 21 S A 0 0 0 8513 0.6210 2.16 3240 3281 0 0 1.000 1.000
+ 22 S A 0 0 0 8628 0.6843 4.66 3360 3413 0 0 1.000 1.000
+ 23 S A 0 0 0 8522 0.6260 2.35 3480 3523 0 0 1.000 1.000
+ 24 S A 0 0 0 35112 15.2459 581.98 3600 3653 0 0 1.000 1.000
+ 25 S A 0 0 0 40716 18.3271 704.14 3720 3772 0 0 1.000 1.000
+ 26 S A 0 0 0 22686 8.4137 311.11 3840 3894 0 0 1.000 1.000
+ 27 S A 0 0 0 19751 6.8000 247.13 3960 4015 0 0 1.000 1.000
+ 28 S A 0 0 0 22664 8.4016 310.63 4080 4138 0 0 1.000 1.000
+ 29 S A 0 0 0 22739 8.4429 312.26 4200 4257 0 0 1.000 1.000
+ 30 S A 0 0 0 9109 0.9487 15.15 4320 4396 0 0 1.000 1.000
+ 31 S A 0 0 0 19610 6.7225 244.06 4440 4495 0 0 1.000 1.000
+ 32 S A 0 0 0 24886 9.6234 359.07 4560 4614 0 0 1.000 1.000
+ 33 S A 0 0 0 16238 4.8685 170.55 4680 4737 0 0 1.000 1.000
+ 34 S A 0 0 0 12885 3.0249 97.46 4800 4865 0 0 1.000 1.000
+ 35 S A 0 0 0 58461 28.0838 1090.95 4920 4977 0 0 1.000 1.000
+ 36 S O 0 0 0 88325 44.5039 1741.95 5040 5093 0 0 1.000 1.000
+ 37 S A 0 0 0 9248 1.0252 18.18 5160 5236 0 0 1.000 1.000
+ 38 S A 0 0 0 20285 7.0936 258.77 5280 5331 0 0 1.000 1.000
+ 39 S A 0 0 0 8697 0.7222 6.17 5400 5477 0 0 1.000 1.000
+ 40 S A 0 0 0 8512 0.6205 2.14 5520 5597 0 0 1.000 1.000
+ 41 S A 0 0 0 8550 0.6414 2.96 5640 5681 0 0 1.000 1.000
+ 42 S A 0 0 0 8570 0.6524 3.40 5760 5805 0 0 1.000 1.000
+ 43 S A 0 0 0 20400 7.1568 261.28 5880 5929 0 0 1.000 1.000
+ 44 S A 0 0 0 9330 1.0702 19.97 6000 6048 0 0 1.000 1.000
+ 45 S A 0 0 0 26535 10.5300 395.01 6120 6170 0 0 1.000 1.000
+ 46 S A 0 0 0 8713 0.7310 6.52 6240 6317 0 0 1.000 1.000
+ 47 B A 0 0 0 8414 0.5666 0.00 6480 6536 0 0 1.000 1.000
+ 48 D A 0 0 0 25277 9.8384 367.59 6600 6652 0 0 1.000 1.000
+ 49 B 0 1 0 8414 0.5666 0.00 6993 6999 0 0 1.000 1.000
+
diff --git a/Scripts/WinUIBase.py b/Scripts/WinUIBase.py
new file mode 100644
index 0000000..aef1114
--- /dev/null
+++ b/Scripts/WinUIBase.py
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+# @Author: Luxuan
+# @Date: 2024-05-23 21:50:44
+# @Last Modified by: Luxuan
+# @Last Modified time: 2024-05-25 11:07:03
+
+
+import pyautogui as pag
+import pywinauto
+import win32gui
+import win32con
+import uiautomation as uiauto
+import psutil
+from PIL import ImageGrab,ImageSequence
+
+class WinUIBase(object):
+ def __init__(self):
+ self.app = None
+ pass
+
+ def launcher(self, app_name, backend='win32',timeout=2):
+ """
+ :param app_name: app进程名称或者app路径
+ :return:
+ """
+ pid_list = self._check_processes(app_name)
+ if len(pid_list) == 0:
+ self.app = pywinauto.application.Application(backend=backend).start(app_name, timeout=timeout, retry_interval=2)
+ else:
+ pid = pid_list[0]
+ self.app = pywinauto.application.Application(backend=backend).connect(process=pid, timeout=timeout, retry_interval=2)
+ pass
+
+ def find_window(self, win_title):
+ win = None
+ try:
+ win = self.app.window(title_re=win_title)
+ # self.main_win.maximize()
+ win.wait(wait_for='visible', timeout=3, retry_interval=2)
+ # time.sleep(0.2)
+ return win
+ except Exception as e:
+ print(e)
+ return win
+ pass
+
+ def show_mode(self,win,mode):
+ if mode=="max":
+ win.maximize()
+ elif mode=="min":
+ pass
+ elif mode=="focus":
+ pass
+ elif mode=="top":
+ pass
+ pass
+
+ def get_window(self,name):
+ wins = self.app.windows()
+ win_items = [x for x in wins if x.element_info.name==name]
+ if len(win_items)>0:
+ return win_items[0]
+ return None
+
+ def get_childers(self,control,auto_id = None, class_name = None, name= None):
+ childers = control.descendants()
+ if auto_id:
+ childers = [x for x in childers if x.handle==auto_id]
+ elif class_name:
+ childers = [x for x in childers if x.element_info.class_name==class_name]
+ elif name:
+ childers = [x for x in childers if x.element_info.name==name]
+
+ if len(childers)==1:
+ return childers[0]
+ return childers
+ pass
+
+ def close_popups(self,win,set_show=False):
+ try:
+ popup_hwnd = win.popup_window()
+ if not popup_hwnd or not set_show:
+ return
+ popup_window = self.app.window(handle=popup_hwnd)
+ popup_window.wait(wait_for='visible', timeout=1)
+ popup_window.set_focus()
+ # popup_window.close()
+ popup_window.type_keys("{ENTER}")
+ except Exception as e:
+ print(e)
+ pass
+
+ def _check_processes(self, app_name):
+ pid_list = []
+ processes = psutil.process_iter()
+ for process in processes:
+ try:
+ name = process.name()
+ # conns = process.connections()
+ exe = process.exe()
+ if app_name in name or app_name == exe:
+ pid_list.append(process.pid)
+ except Exception as e:
+ print(e)
+ return pid_list
+ pass
+
+
+if __name__ == "__main__":
+ pass
+
+
+"""
+pywinauto
+What is pywinauto — pywinauto 0.6.8 documentation
+https://pywinauto.readthedocs.io/en/latest/
+GitHub - 2gis/Winium.Desktop: Winium.Desktop is Selenium Remote WebDriver implementation for automated testing of Windows application based on WinFroms and WPF platforms.
+https://github.com/2gis/Winium.Desktop
+
+app2.window(title_re ='Form',class_name_re="WindowsForms10").wait('ready', timeout=10)
+打印所有子控件
+print_control_identifiers()
+
+win.type_keys('{F5}')
+app = Application(backend='win32').start('notepad.exe')
+mainwin = app['无标题 - 记事本']
+mainwin.Edit.type_keys("自动化输入第一行", with_spaces = True)
+mainwin.child_window(class_name="Edit").type_keys("{ENTER} 自动化输入第二行", with_spaces = True)
+mainwin.menu_select('文件 -> 保存')
+app['另存为']['文件名 Edit'].set_text(r'D:\temp\test_pywa\pywa.txt')
+app['另存为']['保存 Button'].click()
+app['pywa.txt - 记事本'].type_keys('%FX')
+
+send_keys('^a^c') # select all (Ctrl+A) and copy to clipboard (Ctrl+C)
+send_keys('+{INS}') # insert from clipboard (Shift+Ins)
+send_keys('%{F4}') # close an active window with Alt+F4
+截图
+bmp = win.capture_as_image()
+pywinauto客户端自动化---窗口进行截图 - 测试-安静 - 博客园
+https://www.cnblogs.com/qican/p/13262198.html
+
+Python图像库PIL的类Image及其方法介绍_python pil image-CSDN博客
+https://blog.csdn.net/leemboy/article/details/83792729
+
+im.getpixel((0,0))
+Python 查找句柄与控件信息(pywinauto库)_pywinauto edit-CSDN博客
+https://blog.csdn.net/lylelo/article/details/120214006
+app[window_title].menu_select("File->open")
+
+使用pywinauto,如何获取静态文本对象的文本,鉴于父对话框的手柄 - VoidCC
+http://cn.voidcc.com/question/p-obaazoml-x.html
+indow_handle = pywinauto.findwindows.find_windows(title = u'My Dialog Name')
+# 返回应用程序当前顶部窗口,是WindowSpecification对象,可以继续使用对象的方法往下继续查找控件
+app.top_window()
+dlg.close() # 关闭界面
+dlg.minimize() # 最小化界面
+dlg.maximize() # 最大化界面
+dlg.restore() # 将窗口恢复为正常大小,比如最小化的让他正常显示在桌面
+dlg.get_show_state() # 正常0,最大化1,最小化2
+
+# 移动鼠标
+mouse.move(coords=(x, y))
+
+# 指定位置,鼠标左击
+mouse.click(button='left', coords=(40, 40))
+
+# 鼠标双击
+mouse.double_click(button='left', coords=(140, 40))
+
+# 将属性移动到(140,40)坐标处按下
+mouse.press(button='left', coords=(140, 40))
+
+# 将鼠标移动到(300,40)坐标处释放,
+mouse.release(button='left', coords=(300, 40))
+
+# 右键单击指定坐标
+mouse.right_click(coords=(400, 400))
+
+keyboard.send('enter')
+keyboard.send('ctrl+v')
+handle = window.handle
+
+
+【python句柄获取】——简单明了的获取窗口句柄,并使用句柄操作获取相应内容(全网最详细)_python获取窗口句柄-CSDN博客
+https://blog.csdn.net/weixin_46625757/article/details/122498299
+# 通过句柄窗口置顶
+win32gui.SetWindowPos('句柄值', win32con.HWND_TOPMOST, 0, 0, 0, 0,win32con.SWP_NOMOVE | win32con.SWP_NOACTIVATE | win32con.SWP_NOOWNERZORDER | win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE)
+# 通过句柄取消窗口置顶
+def set_down(hwnd):
+ win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, 0, 0, 0, 0,
+ win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE | win32con.SWP_NOMOVE)
+set_down("句柄值")
+# 通过句柄将窗口放到最前
+win32gui.SetForegroundWindow("句柄值")
+
+# 通过窗口句柄【最大化窗口】
+win32gui.ShowWindow('句柄值', win32con.SW_MAXIMIZE)
+
+# 通过窗口句柄【最小化窗口】
+win32gui.ShowWindow('句柄值', win32con.SW_MINIMIZE)
+# 通过窗口句柄【关闭当前句柄控件】
+# 是关闭单个句柄控件,不是关闭整个程序,只能关闭输入的句柄值
+win32gui.SendMessage('句柄值', win32con.WM_CLOSE)
+# 在打开此文件所在文件夹并【定位到此文件】
+FILE = 'C:/Windows/System32/notepad.exe'
+subprocess.Popen(f'explorer.exe /select,{FILE}', shell=False)
+#通过窗口标题获取句柄
+hld = win32gui.FindWindow(None,u"此电脑")
+"""
\ No newline at end of file
diff --git a/Scripts/__pycache__/WinUIBase.cpython-310.pyc b/Scripts/__pycache__/WinUIBase.cpython-310.pyc
new file mode 100644
index 0000000..6267e51
Binary files /dev/null and b/Scripts/__pycache__/WinUIBase.cpython-310.pyc differ
diff --git a/Scripts/__pycache__/aacecontrol.cpython-310.pyc b/Scripts/__pycache__/aacecontrol.cpython-310.pyc
new file mode 100644
index 0000000..0add49b
Binary files /dev/null and b/Scripts/__pycache__/aacecontrol.cpython-310.pyc differ
diff --git a/Scripts/__pycache__/file_script.cpython-310.pyc b/Scripts/__pycache__/file_script.cpython-310.pyc
new file mode 100644
index 0000000..6dd3682
Binary files /dev/null and b/Scripts/__pycache__/file_script.cpython-310.pyc differ
diff --git a/Scripts/aacecontrol.py b/Scripts/aacecontrol.py
new file mode 100644
index 0000000..c35b41e
--- /dev/null
+++ b/Scripts/aacecontrol.py
@@ -0,0 +1,571 @@
+
+
+import os,time
+import pywinauto
+import pywinauto.controls
+import pywinauto.keyboard
+import pywinauto.mouse
+import win32gui
+import win32con
+import pyautogui as pag
+import uiautomation as uiauto
+import pyperclip
+from WinUIBase import WinUIBase
+import json,datetime
+
+pag.PAUSE = 0.5
+
+app_config = {
+ "name": r"C:\Program Files (x86)\SEAL Analytical\AACE 8.03 Beta\aace.exe",
+ "data_dir": r"C:\ProgramData\SEAL Analytical\AACE 8.03 Beta\Data",
+ "login_title": "AACE 登录",
+ "main_title": " AACE for Windows"
+}
+
+class AppService(WinUIBase):
+ def __init__(self):
+ self.launcher(app_config["name"])
+ win_login = self.wait_window_show(app_config["login_title"],3)
+ # win_login = self.get_window(app_config["login_title"])
+ if win_login != None:
+ ctrls = win_login.children()
+ btn_oks = [x for x in ctrls if x.element_info.name=="确定"]
+ if len(btn_oks)==1:
+ btn_ok = btn_oks[0]
+ btn_ok.double_click()
+ # time.sleep(3.5)
+ pass
+ pass
+
+ # 等待outtime 秒内窗口出现,出现则返回对应的窗口,否则返回None
+ def wait_window_show(self,title,outtime = 5):
+ start_time = time.time()
+ win_main = None
+ while time.time() - start_time < outtime:
+ win_main = self.get_window(title)
+ if win_main is not None:
+ break
+ time.sleep(0.5)
+ return win_main
+
+ # 等待子窗口显示
+ def wait_child_window_show(self,win_main,title,outtime):
+ start_time = time.time()
+ win_edit = None
+ while time.time() - start_time < outtime:
+ win_edits = self.get_childers(win_main,class_name=title)
+ if win_edits is not None:
+ if isinstance(win_edits,list):
+ if len(win_edits) < 1:
+ print('复制运行打开失败')
+ return -1
+ win_edit = win_edits[0]
+ else:
+ win_edit = win_edits
+ break
+ time.sleep(0.5)
+ return win_edit
+
+ def create(self,args):
+ data = json.loads(args)
+ sample_list = data.get('sampleList',[])
+ num_samples = len(sample_list)
+ TaskTypes = ['氨氮','氨氮&总磷','总磷']
+ tasktype = data.get('taskType')
+ if num_samples < 1 or tasktype not in TaskTypes:
+ print(f'数据错误-{args}')
+ return -1
+ print(f'共-{num_samples}条数据')
+ result = self.click_create_table(tasktype)
+ if result != -1:
+ result = self.start(args)
+ return result
+
+
+ def start(self,args):
+ try:
+ data = json.loads(args)
+ sample_list = data.get('sampleList',[])
+ num_samples = len(sample_list)
+ # TaskTypes = ['氨氮','氨氮&总磷','总磷']
+ # tasktype = data.get('taskType')
+ # if num_samples < 1 or tasktype not in TaskTypes:
+ if num_samples < 1:
+ print(f'数据错误-{args}')
+ return 0
+ except Exception as e:
+ self.loginformation(f'错误-{str(e)}')
+ return 0
+
+ win_main = self.wait_window_show(app_config["main_title"], 5)
+ if win_main == None:
+ return
+ self.read_task_type_list2()
+ self.set_layout_view(win_main)
+
+ try:
+ return self.create_task(win_main,sample_list,"氨氮&总磷")
+ except:
+ return 0
+ pass
+
+
+ def set_layout_view(self,win_main):
+ win_main.set_focus()
+ pag.press(["Alt",'Y',"U"])
+ time.sleep(1)
+ pass
+
+ def create_task(self,win_main,sample_list,task_type="氨氮&总磷"):
+ # 数据处理
+ # 下面是正式开始解析数据,获取到的sorted_unique_positions就是按位置号排序的全部位置
+ unique_positions = set()
+ for sample in sample_list:
+ position = int(sample["position"])
+ unique_positions.add(Convert(position))
+ sorted_unique_positions = sorted(unique_positions)
+
+ # 先执行关闭
+ num_samples = len(sorted_unique_positions)
+ win_edits = self.get_childers(win_main,class_name="TEditAnlDlg")
+ if isinstance(win_edits,list):
+ for win_edit in win_edits:
+ win_edits.set_focus()
+ rect = win_edits.element_info.rectangle
+ pag.click(rect.left+140,rect.top+600)
+ self.close_popups(win_edits)
+ time.sleep(0.5)
+ elif win_edits!=None:
+ win_edits.set_focus()
+ rect = win_edits.element_info.rectangle
+ pag.click(rect.left+140,rect.top+600)
+ self.close_popups(win_edits)
+ time.sleep(0.5)
+ dir_path = os.path.join(app_config["data_dir"],task_type)
+ file_list = os.listdir(dir_path)
+ file_list = [os.path.join(dir_path,str(x)) for x in file_list if str(x).lower().endswith(".run")]
+ file_list = [(x,os.stat(x).st_mtime,time.localtime(os.stat(x).st_mtime)) for x in file_list]
+ file_list.sort(key=lambda x:x[1],reverse=True)
+ last_task = file_list[0]
+ last_task_name = os.path.basename(last_task[0])
+
+ task_type_list = self._show_task_type_view(win_main,"TDirectoryListBox")
+ # listboxItem_data = task_type_list.select(task_type)
+ # pos = task_type_list.item_rect(listboxItem_data)
+ lview = pywinauto.controls.win32_controls.ListBoxWrapper(task_type_list.handle)
+ # texts = lview.item_texts()
+ for dir in ["Data", task_type]:
+ item = lview.select(dir)
+ pos = lview.item_rect(dir)
+ lview.double_click_input(coords=(pos.left+5,pos.top+5))
+ time.sleep(1)
+ # 滚动到最下
+ task_item_list = self._show_task_type_view(win_main,"TMyListView")
+
+ last_item = None
+ for _ in range(2):
+ # 获取列表
+ win_setting_type = self.get_window("设置: 分析")
+ win_main_item = uiauto.ControlFromHandle(win_setting_type.handle)
+ dgv2 = win_main_item.ListControl(ClassName="TMyListView")
+ items = dgv2.GetChildren()
+
+ last_items = [x for x in items if x.Name==last_task_name]
+ if len(last_items)==0:
+ print("在列表中没有找到最新任务")
+ elif len(last_items)==1:
+ rect = last_items[0].BoundingRectangle
+ if rect.left + rect.top!=0:
+ last_item = last_items[0]
+ break
+ pass
+ task_item_list.scroll(direction="down",amount="end")
+ time.sleep(1)
+ rect = last_item.BoundingRectangle
+ last_item_coords=(rect.left+10,rect.top+5)
+ pywinauto.mouse.click(coords=last_item_coords)
+ time.sleep(2)
+ btn_copy_run = self.get_childers(win_setting_type,name="复制运行")
+ btn_copy_run.double_click()
+ # time.sleep(5)
+ # win_edits = self.get_childers(win_main,class_name="TEditAnlDlg")
+ # if isinstance(win_edits,list):
+ # if len(win_edits) < 1:
+ # print('复制运行打开失败')
+ # return -1
+ # win_edit = win_edits[0]
+ # else:
+ # win_edit = win_edits
+
+ win_edit = self.wait_child_window_show(win_main,"TEditAnlDlg",5)
+ if win_edit is None:
+ print('打开复制运行失败')
+ return -1
+ time.sleep(3)
+ case_name = time.strftime("%Y%m%d%H%M%S",time.localtime())+"_auto"
+ pyperclip.copy(f'{case_name}')
+ win_edit.type_keys("^a^v")
+ time.sleep(0.2)
+
+ # 获取盘序按钮并点击.下面代码会报错。先用固定位置
+ # win_edit_tab2 = self.get_childers(win_edit,name="盘序")
+ # win_edit_tab2.click()
+
+ rect = win_edit.element_info.rectangle
+ pag.click(rect.left+70,rect.top+40)
+ time.sleep(0.5)
+ pag.click(rect.left+280,rect.top+590)
+ time.sleep(0.5)
+
+ file_path = r"C:\Users\Lenovo\Videos\wanhua.xlsx"
+ pyperclip.copy(f'{file_path}')
+ pag.hotkey('ctrl', 'v')
+ time.sleep(1)
+ pag.hotkey('enter')
+ time.sleep(0.5)
+
+ win_edits = self.get_childers(win_main,class_name="TEditAnlDlg")
+ #点击盘序
+ pag.click(rect.left+70,rect.top+40)
+ time.sleep(0.5)
+
+ #点击第5行 O 无效的下一行
+ pag.click(rect.left+70,rect.top+165)
+ time.sleep(0.5)
+ # 点击样品按钮 添加样品
+ sample_btn = self.get_childers(win_edits,name="样品")
+ sample_btn.click()
+ sample_btn.click()
+ time.sleep(1)
+ win_samplecup = self.get_window('用于样品的杯')
+ # 找到数量这个文本框,输入数目,杯位无所谓,在外面修改
+ inputs = self.get_childers(win_samplecup,class_name="TSNumberEdit")
+ inputs[1].set_edit_text(num_samples)
+
+ # Alt+确
+ win_samplecup.type_keys("%{确}")
+ time.sleep(0.5)
+
+ # 下面是输入内容,先点击5行图标
+ pag.click(rect.left+70,rect.top+165)
+ time.sleep(0.5)
+ pag.press('right')
+ pag.press('right')
+
+ for pos in sorted_unique_positions:
+ pag.press('space')
+ pag.write(pos)
+ pag.press('tab')
+
+ result = next((x for x in sample_list if (Convert(int(x["position"])) == pos) and int(x["position"]) % 2 != 0), None)
+ if result is not None:
+ pag.press('space')
+ pag.write(result['sampleCode'])
+ print(f"{pos}位置的氨氮值为:{result['sampleCode']}")
+
+ pag.press('tab')
+ pag.press('tab')
+
+ result = next((x for x in sample_list if (Convert(int(x["position"])) == pos) and int(x["position"]) % 2 == 0), None)
+ if result is not None:
+ pag.press('space')
+ pag.write(result['sampleCode'])
+ print(f"{pos}位置的总磷值为:{result['sampleCode']}")
+
+ for _ in range(3):
+ pag.press('tab')
+
+ # for i in range(num_samples):
+ # position = sample_list[i].get('position')
+ # sampleCode = sample_list[i].get('sampleCode')
+ # pag.press('space')
+ # pag.write(position)
+ # # pyperclip.copy(position)
+ # # pag.hotkey('ctrl','v')
+ # pag.press('tab')
+ # pag.press('space')
+ # pag.write(sampleCode)
+
+ # tabcount = 3
+ # match task_type:
+ # case '氨氮':
+ # tabcount = 3
+ # case '氨氮&总磷':
+ # tabcount = 5
+ # case '总磷':
+ # tabcount = 4
+ # case _:
+ # tabcount = 3
+ # for _ in range(tabcount):
+ # pag.press('tab')
+
+ # Alt+确 确定的快捷键
+ win_edit.type_keys("%{确}")
+ # time.sleep(0.5)
+ return 1
+ pass
+
+ def read_task_type_list(self,win_main):
+ listbox_panel = self._show_task_type_view(win_main,"TDirectoryListBox")
+ listboxItem_data = listbox_panel.select("Data")
+ time.sleep(0.1)
+ listboxItem_data.double_click_input(coords=(5,5))
+ time.sleep(0.5)
+ task_type_list = listbox_panel.item_texts()
+ data_index = list(task_type_list).index("Data") + 1
+ task_type_list = task_type_list[data_index:]
+ return task_type_list
+
+ def read_task_type_list2(self):
+ # dir_list = os.listdir(app_config["data_dir"])
+ dir_list = []
+ for root,dirs,file in os.walk(app_config["data_dir"]):
+ dir_list = dirs
+ break
+ pass
+ return dirs
+ pass
+
+
+ def _show_task_type_view(self,win_main,class_name):
+ win_setting_type = self.get_window("设置: 分析")
+ if win_setting_type is None:
+ win_main.set_focus()
+ common_panels = self.get_childers(win_main,class_name="TPanel")
+ rect = common_panels[0].element_info.rectangle
+ coords=(rect.left + 5,rect.top+15)
+ pag.click(coords[0],coords[1])
+ # time.sleep(8)
+ # win_setting_type = self.get_window("设置: 分析")
+ win_setting_type = self.wait_window_show("设置: 分析",8)
+ win_setting_type.set_focus()
+ listbox_panel = self.get_childers(win_setting_type,class_name=class_name)
+ return listbox_panel
+
+
+ # 点击制图,暂时弃用
+ def click_create_table(self, task_type):
+ TaskTypes = ['氨氮','氨氮&总磷','总磷']
+ if task_type not in TaskTypes:
+ print('制图错误')
+ return -1
+
+ # 点击制图按钮
+ win_main = self.get_window(app_config["main_title"])
+ win_main.set_focus()
+ time.sleep(1)
+ create_btn = self.get_childers(win_main,name='制图')
+ if create_btn is None:
+ print('点击制图失败')
+ return -1
+ create_btn.double_click()
+
+ # 弹出的界面点击更改,默认是更改直接点enter
+ win_msg = self.wait_window_show('AACE信息',5)
+ if win_msg is None:
+ print("显示AACE信息失败")
+ return -1
+
+ time.sleep(1)
+ change_btns = self.get_childers(win_msg,name='更改…')
+ change_btn = None
+ if isinstance(change_btns,list):
+ if len(change_btns) < 1:
+ print("未找到更改按钮")
+ return -1
+ else:
+ change_btn = change_btns[0]
+ else:
+ change_btn = change_btns
+ if change_btn is None:
+ print("点击更改...失败")
+ return -1
+ change_btn.double_click()
+
+ #选择分析界面选择 氨氮、氨氮&总磷、总磷 对应的文件
+ win_select_anlysis = self.wait_window_show('选择分析',5)
+ if win_select_anlysis is None:
+ return -1
+
+ # 下面代码为选中对应的模式
+ dir_path = os.path.join(app_config["data_dir"],task_type)
+ file_list = os.listdir(dir_path)
+ file_list = [os.path.join(dir_path,str(x)) for x in file_list if str(x).lower().endswith(".anl")]
+ file_list = [(x,os.stat(x).st_mtime,time.localtime(os.stat(x).st_mtime)) for x in file_list]
+ file_list.sort(key=lambda x:x[1],reverse=True)
+ last_task = file_list[0]
+ last_task_name = os.path.basename(last_task[0])
+
+ win_setting_type = self.get_window("选择分析")
+ if win_setting_type is None:
+ win_main.set_focus()
+ common_panels = self.get_childers(win_main,class_name="TPanel")
+ rect = common_panels[0].element_info.rectangle
+ coords=(rect.left + 5,rect.top+15)
+ pag.click(coords[0],coords[1])
+ # time.sleep(8)
+ # win_setting_type = self.get_window("设置: 分析")
+ win_setting_type = self.wait_window_show("选择分析",8)
+ win_setting_type.set_focus()
+ task_type_list = self.get_childers(win_setting_type,class_name='TDirectoryListBox')
+ lview = pywinauto.controls.win32_controls.ListBoxWrapper(task_type_list.handle)
+ # texts = lview.item_texts()
+ for dir in ["Data", task_type]:
+ item = lview.select(dir)
+ pos = lview.item_rect(dir)
+ lview.double_click_input(coords=(pos.left+5,pos.top+5))
+ time.sleep(1)
+
+ # 点击确认按钮的快捷键
+ win_select_anlysis.type_keys("%{确}")
+ return 1
+
+ # 运行此前设置的分析
+ def run(self,task_type = "氨氮&总磷"):
+ # 点击制图按钮
+ win_main = self.get_window(app_config["main_title"])
+ win_main.set_focus()
+ time.sleep(2)
+ run_btn = self.get_childers(win_main,name='运行')
+ if run_btn is None:
+ return -1
+ run_btn.double_click()
+ #选择分析界面选择 氨氮、氨氮&总磷、总磷 对应的文件
+ win_select_anlysis = self.wait_window_show('运行: 开始',20)
+ if win_select_anlysis is None:
+ print('运行开始界面显示超时')
+ return -1
+
+ # 下面是选择最新的文件
+ dir_path = os.path.join(app_config["data_dir"],task_type)
+ file_list = os.listdir(dir_path)
+ file_list = [os.path.join(dir_path,str(x)) for x in file_list if str(x).lower().endswith(".run")]
+ file_list = [(x,os.stat(x).st_mtime,time.localtime(os.stat(x).st_mtime)) for x in file_list]
+ file_list.sort(key=lambda x:x[1],reverse=True)
+ last_task = file_list[0]
+ last_task_name = os.path.basename(last_task[0])
+
+ task_type_list = self._show_task_type_view_ex(win_main,'运行: 开始',"TDirectoryListBox")
+ # listboxItem_data = task_type_list.select(task_type)
+ # pos = task_type_list.item_rect(listboxItem_data)
+ lview = pywinauto.controls.win32_controls.ListBoxWrapper(task_type_list.handle)
+ # texts = lview.item_texts()
+ for dir in ["Data", task_type]:
+ item = lview.select(dir)
+ pos = lview.item_rect(dir)
+ lview.double_click_input(coords=(pos.left+5,pos.top+5))
+ time.sleep(1)
+ # 滚动到最下
+ task_item_list = self._show_task_type_view_ex(win_main,'运行: 开始',"TMyListView")
+
+ last_item = None
+ for _ in range(2):
+ # 获取列表
+ win_setting_type = self.get_window("运行: 开始")
+ win_main_item = uiauto.ControlFromHandle(win_setting_type.handle)
+ dgv2 = win_main_item.ListControl(ClassName="TMyListView")
+ items = dgv2.GetChildren()
+
+ last_items = [x for x in items if x.Name==last_task_name]
+ if len(last_items)==0:
+ print("在列表中没有找到最新任务")
+ elif len(last_items)==1:
+ rect = last_items[0].BoundingRectangle
+ if rect.left + rect.top!=0:
+ last_item = last_items[0]
+ break
+ pass
+ task_item_list.scroll(direction="down",amount="end")
+ time.sleep(1)
+ rect = last_item.BoundingRectangle
+ last_item_coords=(rect.left+10,rect.top+5)
+ pywinauto.mouse.click(coords=last_item_coords)
+ time.sleep(2)
+ win_select_anlysis.type_keys("%{确}")
+
+ win_start = self.wait_window_show('开始运行',5)
+ if win_start is None:
+ self.loginformation('开始运行界面有误')
+ return -1
+ alarm_checkbox = self.get_childers(win_start,name='声音警报')
+ rect = alarm_checkbox.rectangle()
+ alarm_coords=(rect.left+5,rect.top+5)
+ pywinauto.mouse.click(coords=alarm_coords)
+ time.sleep(1)
+ confirm_coords = (rect.left+5,rect.top+75)
+ pywinauto.mouse.click(coords=confirm_coords)
+ return 1
+
+ # 显示任务类型窗口
+ def _show_task_type_view_ex(self,win_main,title,classname):
+ win_setting_type = self.get_window(title)
+ if win_setting_type is None:
+ win_main.set_focus()
+ common_panels = self.get_childers(win_main,class_name="TPanel")
+ rect = common_panels[0].element_info.rectangle
+ coords=(rect.left + 5,rect.top+15)
+ pag.click(coords[0],coords[1])
+ # time.sleep(8)
+ # win_setting_type = self.get_window("设置: 分析")
+ win_setting_type = self.wait_window_show(title,8)
+ win_setting_type.set_focus()
+ listbox_panel = self.get_childers(win_setting_type,class_name=classname)
+ return listbox_panel
+
+ def loginformation(self,content):
+ print(f'{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}:{content}')
+
+
+ def is_finished(self):
+ win_main = self.get_window("AACE信息")
+ if win_main is None:
+ return 0
+
+ alram_infos = self.get_childers(win_main,name='声音报警')
+ alarm_info = None
+ result = 0
+ if isinstance(alram_infos,list):
+ if len(alram_infos) > 0:
+ alarm_info = alram_infos[0]
+ elif alram_infos is not None:
+ alarm_info = alram_infos
+ if alarm_info is None:
+ result = 0
+ else:
+ #win_main.get_properties()
+ if win_main.is_visible():
+ result = 1
+ return result
+
+ def createThenStart(self,args):
+ if self.start(args) != 1:
+ return 0
+ return self.run()
+
+ def Convert(self,number):
+ if number % 2 == 0:
+ number = number - 1
+ col = number % 6 // 2
+ row = number // 6
+ return 46 + 15 * col + row * 2
+
+def Convert(number):
+ if number % 2 == 0:
+ number = number - 1
+ col = number % 6 // 2
+ row = number // 6
+ return 46 + 15 * col + row * 2
+
+if __name__ == "__main__":
+ # # taskType 为: 氨氮、氨氮&总磷、总磷 3,5,4
+ #json_data = {"taskType":"氨氮","sampleList":[{"sampleCode":"11","position":"1"},{"sampleCode":"12","position":"3"}]}
+ #appService.click_create_table("氨氮")
+ #appService.start(paras)
+ #appService.run("氨氮")
+ # print(appService.is_finished())
+ #pass
+ appService = AppService()
+ json_data = {"sampleList":[{"sampleCode":"111","position":"1"},{"sampleCode":"112","position":"2"},{"sampleCode":"113","position":"7"},{"sampleCode":"114","position":"20"}]}
+ paras = json.dumps(json_data)
+ appService.createThenStart(paras)
+
\ No newline at end of file
diff --git a/Scripts/file_script.py b/Scripts/file_script.py
new file mode 100644
index 0000000..66f2a1a
--- /dev/null
+++ b/Scripts/file_script.py
@@ -0,0 +1,98 @@
+import mimetypes
+import time
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+import http.client
+
+# 服务器的 IP 地址和端口号
+server = "192.168.6.11"
+server_port = 8080
+# 接口路径
+# server_url = "/Interface/Result/Create"
+server_url = "/wanhua-service/equipment/external/checkResult"
+
+class Watcher:
+ def __init__(self, directory_to_watch):
+ self.observer = Observer()
+ self.directory_to_watch = directory_to_watch
+
+ def run(self):
+ print(f'开始监听文件夹{self.directory_to_watch}')
+ event_handler = Handler()
+ self.observer.schedule(event_handler, self.directory_to_watch, recursive=True)
+ self.observer.start()
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ self.observer.stop()
+ finally:
+ self.observer.join()
+
+ def join(self):
+ self.observer.join()
+
+
+
+class Handler(FileSystemEventHandler):
+ @staticmethod
+ def on_created(event):
+ if not event.is_directory:
+ if event.src_path.endswith('.pdf') or event.src_path.endswith('.csv') or event.src_path.endswith('.xlsx'):
+ print(f"监控到---{event.src_path}---已被创建")
+ time.sleep(1)
+ try:
+ # 构建multipart/form-data请求体
+ boundary = 'Boundary-0123456789'
+ headers = {
+ 'Content-Type': f'multipart/form-data; boundary={boundary}'
+ }
+ # 确定文件的MIME类型
+ mime_type, _ = mimetypes.guess_type(event.src_path)
+
+ # 构建请求体
+ body = []
+ body.append(f'--{boundary}')
+ body.append(
+ f'Content-Disposition: form-data; name="file"; filename="{event.src_path}"')
+ body.append(f'Content-Type: {mime_type}')
+ body.append('')
+ with open(event.src_path, mode='r', newline='', encoding='gb2312', errors='ignore') as file:
+ body.append(file.read())
+ body.append(f'--{boundary}--')
+ body.append('')
+ # 将请求体转换为字节串
+ body_bytes = '\r\n'.join(body).encode('utf-8')
+
+ # 创建 HTTP 连接对象
+ conn = http.client.HTTPConnection(server, server_port)
+ # 发送POST请求
+ conn.request("POST", f"{server_url}?deviceKey=titration&passback=false", body=body_bytes, headers=headers)
+
+ # 获取响应
+ response = conn.getresponse()
+
+ # 读取响应内容
+ response_data = response.read()
+
+ # 检查响应状态码
+ if response.status == 200:
+ print('数据发送成功')
+ print(response_data.decode()) # 打印服务器的响应内容
+ else:
+ print('数据发送失败')
+ print(response.status) # 打印错误状态码
+ print(response.reason) # 打印错误状态码
+ print(response_data.decode()) # 打印错误状态码
+ # break # 找到第一个非空行后终止遍历
+ except Exception as e:
+ print(f"发生异常: {e}")
+ finally:
+ # 关闭连接
+ conn.close()
+
+
+if __name__ == '__main__':
+ # logger.info(f"当前用户名: {getuser()}")
+ w = Watcher(r"D:\src\logs")
+ w.run()
diff --git a/Scripts/service.py b/Scripts/service.py
new file mode 100644
index 0000000..e454a7d
--- /dev/null
+++ b/Scripts/service.py
@@ -0,0 +1,236 @@
+# import socket
+# import threading
+# import aacecontrol
+# import ctypes,win32con,win32gui,sys,json
+# import logging
+# # import file_script
+
+
+# IpAddress = '127.0.0.1'
+# FilePath = 'D:\\MegaSoft\\Scripts'
+# Port = 2016
+# # device = md.MultiWinDevice("multiWin")
+# device = aacecontrol.AppService()
+# # 定义互斥量名称
+# mutex_name = "aaca_mutex"
+
+
+# def handle_client(client_socket,addr):
+# device.loginformation(f'监听{addr}的数据')
+# while True:
+# try:
+# # 接收客户端发送的数据
+# data = client_socket.recv(2048)
+# if not data:
+# device.loginformation(f'{addr}-接收到空数据')
+# break
+# # # 处理接收到的数据
+# # device.loginformation(f"Received from {client_socket.getpeername()}: {data.decode('utf-8')}")
+# datadecode = data.decode('utf-8')
+# command = datadecode.partition(':')[0] # 只分割一次
+# paras = datadecode.partition(':')[2]
+# result = -1
+
+# if 'makeGraph' in command:
+# command = 'makeGraph'
+# device.loginformation(f'---收到制图指令 {datadecode}---')
+# result = device.click_create_table(paras)
+# elif 'operate' in command:
+# command = 'operate'
+# device.loginformation(f'---收到创建任务指令 {datadecode}---')
+# result = device.start(paras)
+# elif 'createTask' in command:
+# command = 'createTask'
+# device.loginformation(f'---收到制图创建任务命令 {datadecode}---')
+# result = device.create(paras)
+# elif 'start' in command:
+# command = 'start'
+# device.loginformation(f'---收到启动命令 {datadecode}---')
+# result = device.run(paras)
+# elif 'status' in command:
+# device.loginformation(f'---收到查询状态命令 {datadecode}---')
+# result = 2
+# if device.is_finished():
+# result = 1
+# else:
+# command = '未知命令'
+# device.loginformation('---未知命令---')
+
+# reponse_txt = command + ':' + str(result) + '\n'
+# client_socket.send(reponse_txt.encode('utf-8'))
+# device.loginformation(f'---返回-{reponse_txt}---')
+# except:
+# device.loginformation(f'{addr}-接收数据异常')
+# client_socket.close()
+# return
+# # 关闭连接
+# device.loginformation(f'{addr}-连接断开')
+# client_socket.close()
+
+# def start_server():
+# server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+# server.bind((IpAddress, Port))
+# server.listen(20)
+# device.loginformation(f"Server listening on port {IpAddress}:{Port}...")
+# try:
+# while True:
+# client_socket, addr = server.accept()
+# device.loginformation(f"Accepted connection from {addr}")
+# # 启动一个新线程来处理客户端请求
+# client_handler = threading.Thread(target=handle_client, args=(client_socket,addr))
+# client_handler.start()
+# except:
+# print('服务结束了。。。')
+# finally:
+# ctypes.windll.kernel32.CloseHandle(mutex)
+
+# def message_box(title, message, type=win32con.MB_OK):
+# """
+# 弹出一个消息框
+# :param title: 消息框的标题
+# :param message: 消息框显示的消息
+# :param type: 消息框的类型,例如MB_OK, MB_ICONERROR等
+# :return: 用户点击的消息框按钮的标识符
+# """
+# return win32gui.MessageBox(None, message, title, type)
+
+# if __name__ == "__main__":
+# # 定义互斥锁名称,可以是任意字符串
+# mutex = ctypes.windll.kernel32.CreateMutexW(None, False, mutex_name)
+# # 检查互斥量是否已经存在
+# if ctypes.windll.kernel32.GetLastError() == 183: # ERROR_ALREADY_EXISTS
+# message_box("提醒", "脚本正在运行中,请点击确定关闭。", win32con.MB_ICONWARNING)
+# sys.exit(0)
+
+# ctypes.windll.kernel32.SetThreadExecutionState(0x80000002) # 确保桌面不息屏
+
+# server_thread = threading.Thread(target=start_server)
+# server_thread.start()
+
+# # w = file_script.Watcher(FilePath)
+# # file_thread = threading.Thread(target=w.run)
+# # file_thread.start()
+
+
+import ctypes
+import socket
+import sys
+import threading
+import win32con
+import win32gui
+from file_script import Watcher
+import aacecontrol
+
+
+IpAddress = '127.0.0.1'
+FilePath = 'D:\\MegaSoft\\Scripts'
+Port = 2016
+device = aacecontrol.AppService()
+# 定义互斥量名称
+mutex_name = "aaca_mutex"
+
+def handle_client(client, addr):
+ while True:
+ try:
+ data = client.recv(2048)
+ if not data:
+ device.loginformation("接收数据异常")
+ break
+ datadecode = data.decode('utf-8')
+ device.loginformation(f"接收到---{client.getpeername()}---数据---{datadecode}")
+ result = -1
+ command = datadecode.partition(':')[0] # 只分割一次
+ paras = datadecode.partition(':')[2] # 返回包含分隔符
+
+ # if 'makeGraph' in command:
+ # command = 'makeGraph'
+ # device.loginformation(f'---收到制图指令 {datadecode}---')
+ # result = device.click_create_table(paras)
+ # elif 'operate' in command:
+ # command = 'operate'
+ # device.loginformation(f'---收到创建任务指令 {datadecode}---')
+ # result = device.start(paras)
+ if 'createTask' in command:
+ command = 'createTask'
+ device.loginformation(f'收到创建任务并执行命令 {datadecode}')
+ result = device.createThenStart(paras)
+ # elif 'start' in command:
+ # command = 'start'
+ # device.loginformation(f'---收到启动命令 {datadecode}---')
+ # result = device.run(paras)
+ elif 'status' in command:
+ device.loginformation(f'收到查询状态命令 {datadecode}')
+ result = 2
+ if device.is_finished():
+ result = 0
+ else:
+ command = '未知命令'
+ device.loginformation('未知命令')
+
+ response_txt = command + ':' + str(result) + '\n'
+ device.loginformation(f'返回:{command}:{str(result)}')
+ client.send(response_txt.encode('utf-8'))
+ except:
+ device.loginformation(f'{addr}通讯异常')
+ break
+ # 关闭连接
+ device.loginformation(f'关闭{addr}连接')
+ client.close()
+
+def message_box(title, message, type=win32con.MB_OK):
+ """
+ 弹出一个消息框
+ :param title: 消息框的标题
+ :param message: 消息框显示的消息
+ :param type: 消息框的类型,例如MB_OK, MB_ICONERROR等
+ :return: 用户点击的消息框按钮的标识符
+ """
+ return win32gui.MessageBox(None, message, title, type)
+
+
+class TCPThread(threading.Thread):
+ def run(self):
+ server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server.bind((IpAddress, Port))
+ server.listen(20)
+ device.loginformation(f"服务端---{IpAddress}---{Port}---启动")
+ connected_clients = 0
+ try:
+ while True:
+ client, addr = server.accept()
+ connected_clients = connected_clients + 1
+ device.loginformation(f"客户端---{addr}---已连接,已连接客户端数量:{connected_clients}")
+ client_handle = threading.Thread(target=handle_client, args=(client,addr))
+ client_handle.start()
+ except Exception as e:
+ device.loginformation(f"{str(e)}服务端正在关闭...")
+ server.close()
+ device.loginformation("服务端已关闭")
+ finally:
+ # 释放互斥量
+ ctypes.windll.kernel32.CloseHandle(mutex)
+
+
+
+if __name__ == "__main__":
+ # 定义互斥锁名称,可以是任意字符串
+ mutex = ctypes.windll.kernel32.CreateMutexW(None, False, mutex_name)
+ # 检查互斥量是否已经存在
+ if ctypes.windll.kernel32.GetLastError() == 183: # ERROR_ALREADY_EXISTS
+ message_box("提醒", "脚本正在运行中,请点击确定关闭。", win32con.MB_ICONWARNING)
+ sys.exit(0)
+
+ ctypes.windll.kernel32.SetThreadExecutionState(0x80000002)
+
+ tcp_thread = TCPThread()
+ tcp_thread.start()
+
+ # 创建线程
+ watcher = Watcher(FilePath)
+ watcher_thread = threading.Thread(target=watcher.run)
+ watcher_thread.start()
+
+
+
+
+
diff --git a/Scripts/temp.bmp b/Scripts/temp.bmp
new file mode 100644
index 0000000..b2cd3de
Binary files /dev/null and b/Scripts/temp.bmp differ
diff --git a/Scripts/temp.png b/Scripts/temp.png
new file mode 100644
index 0000000..5f96dc8
Binary files /dev/null and b/Scripts/temp.png differ
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..a0b467d
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,21 @@
+## 通讯协议TCP,控制脚本作为server端
+192.168.6.**:2016 (未插网线ip待定)
+
+
+# 客户做之前需要点击制图-氨氮&总磷 确认制图正确
+
+## 设置分析并启动(客户自己确认已制图完成):
+发送:createTask:{"sampleList":[
+{"sampleCode":"111","position":"1"},
+{"sampleCode":"112","position":"2"}]
+}
+
返回:1成功 0失败
+
+注: position给料盘实际编号就行,仪器需要的类型及位置通过脚本来自行判断,position位置为1~48,流动注射仪未开启会失败返回0
+
+## 状态查询命令:
+发送:status
+
返回: 0:就绪 2:完成
+
注:完成之后有个弹窗,只能通过该弹窗判断是否完成任务,没有弹窗时无法区分是就绪还是运行中
+
+
diff --git a/readme1 (2).md b/readme1 (2).md
new file mode 100644
index 0000000..1d10de3
--- /dev/null
+++ b/readme1 (2).md
@@ -0,0 +1,31 @@
+## python打包成exe
+Pyinstaller -F service.py
+
+## 通讯协议TCP,控制脚本作为server端
+192.168.6.**:2016
+
+
+# 如果客户不手动点击制图则调用如下方法:
+# 打包
+
+
+## 制图
+makeGraph:*** (注意: ***为:氨氮、氨氮&总磷、总磷 三个之一)
+(如果客户手动点制图就无需发送):
+
+## 设置分析:
+createTask:{"sampleList":[
+{"sampleCode":"111","position":"1"},
+{"sampleCode":"112","position":"2"}]
+}
+
+注:position为料盘实际的编号,脚本自己转化仪器需要的位置
+
+## 发送启动(确认制图没问题之后发送,如果提前确认好制图那么在设置分析之后发送):
+start:*** (注意: ***为:氨氮、氨氮&总磷、总磷 三个之一)
+start
+注:现在均用总磷&氨氮这一个方法
+
+## 状态查询命令:
+status
+返回: 0:停止 1:运行 2:完成