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)