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:完成