#概要
設計検討
https://qiita.com/asahi4549/items/b63affa193a2f422586a
をもとに実装してみた。
#各機能実装説明
GUI画面を示す。各機能について同実装したか説明する
"Read picture"クリック時の処理コードを示す。
フォルダを選択できるダイアログを表示し、そこで選択されたフォルダのpath情報を取得する。
path情報から選択されたフォルダ内の画像ファイルをリストデータとして保存しウィジェットに表示させている
AK003_V1002.py
def click_read_file(self):
#ファイルオープンダイアログの表示
#(file_path, selectedFilter) = QtWidgets.QFileDialog.getOpenFileName(self,filter="png jpeg (*.png *.jpeg)")
#フォルダのみ選択する方法に変更
#第2引数はダイアログのタイトル, 第3引数は初期表示したいpath
dir_path_tmp = QtWidgets.QFileDialog.getExistingDirectory(self, 'Open Directory', "./picture")
if(dir_path_tmp != ""):
#path_absは絶対path
path_abs = pathlib.Path(dir_path_tmp)
#relative_toで相対パスに変換,引数は起点となるパス
#path_abs.cwd()でカレントディレクトリのパスを取得
self.dir_path_rel = path_abs.relative_to( path_abs.cwd() )
#pathからファイル名取得
file_name = os.listdir(self.dir_path_rel)
#file_name = os.path.basename(file_path)
print(file_name)
#.pngファイル名をPicture listにセット
#ファイル名をリストモデルに追加
#self.list_model.setStringList([file_name])
self.list_model.setStringList(file_name)
#リストモデルをリストビューに追加
#リストビューに追加することでウィジェットに反映される
self.ui.listView_picture_list.setModel(self.list_model)
AK003_V1002.py
def click_execute(self):
#code_text解析処理
#code textの文字列取得
code = self.ui.plainTextEdit_code_text.toPlainText()
#codeを引数にして文法チェック関数に渡す。check_syntaxの中で改行判定を行い、命令分を抽出する
#selfも引数で渡さないと,uiの変数が扱えない
syntax_result = Check_syntax(self,code)
#textコードに問題がなければ実行用リストの実行
if(syntax_result != FAIL):
self.ui.plainTextEdit_result.appendPlainText("executed successfully")
#デスクトップ画面を表示
msg_ret = QMessageBox.question(None,"確認","自動化プログラムを実行しますがよろしいですか?", QMessageBox.Ok,QMessageBox.Cancel )
if(msg_ret != QMessageBox.Cancel ):
#実行用リストを上から実行
pg.sleep(2)
QMessageBox.information(None, "情報","デスクトップ画面を表示してから2sec後にこの画面が表示されているはず")
args_cnt = 0
for func in self.list_exec_func:
exec_handler(self,func, self.list_exec_args[args_cnt])
time.sleep(0.5)
args_cnt = args_cnt + 1
#実行用配列をクリア
#2回目のコード実行時に前回の命令が残らないように
self.list_exec_func.clear()
self.list_exec_args.clear()
else:
self.ui.plainTextEdit_result.appendPlainText("program cancelled")
return
#文法チェックがngのときエラー処理
else:
self.ui.plainTextEdit_result.appendPlainText("execution failure")
return
AK003_V1002.py
def click_save_code(self):
#code_txtから文字列取得
code = self.ui.plainTextEdit_code_text.toPlainText()
#保存ファイル名取得
(file_name_path, selectedFilter) = QtWidgets.QFileDialog.getSaveFileName(self, 'Open Directory', './code')
if(file_name_path != ''):
#pathからファイル名取得
file_name = os.path.basename(file_name_path)
self.ui.plainTextEdit_result.appendPlainText(file_name+"を保存しました")
#取得した文字列をほぞしたいファイルに書き出し
#withを使うことで自動でcloseしてくれる
with open('./code/'+file_name,"w" ) as save_code_file:
save_code_file.write(code)
#コールバック関数
def exec_handler(self,func , *arg):
func(self,*arg)
```python:AK003_V1002.py
#文法チェック関数
def Check_syntax(self,txt_code):
#改行の文字列までの命令分を抽出
list_code_tmp = []
#特定の文字列の場所を取得して、そこまで削除を考えたが、改行でリストかする関数があったのでそちらを使う
#改行ごとでリスト化
list_code_tmp = txt_code.splitlines()
print(list_code_tmp)
#コードリストの中身を上から文法チェック
for code in list_code_tmp: #clickの文字を正規表現で抽出
#note: matchは先頭文字からあっているか
if(re.match('click',code)):
#note 過去の文字を消さずに文字を追加
#setPlainTextもあるがこれは過去の文字を無視する
#self.ui.plainTextEdit_result.appendPlainText(code_tmp)
#()があるか
#note()も正規表現の一つなので\でエスケープしている
#(から)で終わる文字の最後を抽出
ob_recode_tmp = re.search('\(.*\)',code)
print(ob_recode_tmp)
#()が見つからない場合はエラー処理
#note オブジェクトの一致判定は is をつかう
if(ob_recode_tmp is not None):
#group()でmatchした文字列を抽出
code_tmp = ob_recode_tmp.group()
#引数cod_argを抽出
#note 0文字目と-1文字目以外を抽出
code_arg = code_tmp[1:-1]
print(code_arg)
#clickの引数は画像idで与えられるので、idをlist_modelのインデックスのメンバにし、list_model内のデータを取得する
#index指定して.dataでリストモデルに登録してるデータを取得できる
#indexの引数はintなのでintに変換している
code_arg = self.list_model.index(int(code_arg),0).data()
#引数をselectpictureの中から探索
#note stringListでlist_modelからリストを抽出,
#if inより完全一致検索をかける。一文字でもあっている場合は判定したいときはmatch関数をつかう
str_list = self.list_model.stringList()
#str_listの中にcode_argがあるか判定
if code_arg in str_list:
self.ui.plainTextEdit_result.appendPlainText("画像が見つかりました")
#clickを実行用リストに追加
self.list_exec_func.append(pc_op.click)
self.list_exec_args.append(code_arg)
else:
self.ui.plainTextEdit_result.appendPlainText("引数が正しくありません")
return FAIL
else:
self.ui.plainTextEdit_result.appendPlainText("()がありません")
return FAIL
elif(re.match('dclick',code)):
#note 過去の文字を消さずに文字を追加
#setPlainTextもあるがこれは過去の文字を無視する
#self.ui.plainTextEdit_result.appendPlainText(code_tmp)
#()があるか
#note()も正規表現の一つなので\でエスケープしている
#(から)で終わる文字の最後を抽出
ob_recode_tmp = re.search('\(.*\)',code)
print(ob_recode_tmp)
#()が見つからない場合はエラー処理
#note オブジェクトの一致判定は is をつかう
if(ob_recode_tmp is not None):
#group()でmatchした文字列を抽出
code_tmp = ob_recode_tmp.group()
#引数cod_argを抽出
#note 0文字目と-1文字目以外を抽出
code_arg = code_tmp[1:-1]
print(code_arg)
#clickの引数は画像idで与えられるので、idをlist_modelのインデックスのメンバにし、list_model内のデータを取得する
#index指定して.dataでリストモデルに登録してるデータを取得できる
#indexの引数はintなのでintに変換している
code_arg = self.list_model.index(int(code_arg),0).data()
#引数をselectpictureの中から探索
#note stringListでlist_modelからリストを抽出,
#if inより完全一致検索をかける。一文字でもあっている場合は判定したいときはmatch関数をつかう
str_list = self.list_model.stringList()
#str_listの中にcode_argがあるか判定
if code_arg in str_list:
self.ui.plainTextEdit_result.appendPlainText("画像が見つかりました")
#dclickとその引数を実行用リストに追加
self.list_exec_func.append(pc_op.dclick)
self.list_exec_args.append(code_arg)
else:
self.ui.plainTextEdit_result.appendPlainText("引数が正しくありません")
return FAIL
else:
self.ui.plainTextEdit_result.appendPlainText("()がありません")
return FAIL
elif(re.match('typekey',code)):
#()があるか
#note()も正規表現の一つなので\でエスケープしている
#(から)で終わる文字の最後を抽出
ob_recode_tmp = re.search('\(.*\)',code)
#()が見つからない場合はエラー処理
#note オブジェクトの一致判定は is をつかう
if(ob_recode_tmp is not None):
#group()でmatchした文字列を抽出
code_tmp = ob_recode_tmp.group()
#引数cod_argを抽出
#note 0文字目と-1文字目以外を抽出
code_arg = code_tmp[1:-1]
print(code_arg)
#typekey関数とその引数を実行リストに追加
self.list_exec_func.append(pc_op.typekey)
self.list_exec_args.append(code_arg)
else:
self.ui.plainTextEdit_result.appendPlainText("()がありません")
return FAIL
elif(re.match('wait',code)):
#()があるか
#note()も正規表現の一つなので\でエスケープしている
#(から)で終わる文字の最後を抽出
ob_recode_tmp = re.search('\(.*\)',code)
#()が見つからない場合はエラー処理
#note オブジェクトの一致判定は is をつかう
if(ob_recode_tmp is not None):
#group()でmatchした文字列を抽出
code_tmp = ob_recode_tmp.group()
#引数cod_argを抽出
#note 0文字目と-1文字目以外を抽出
code_arg = code_tmp[1:-1]
#typekey関数とその引数を実行リストに追加
self.list_exec_func.append(pc_op.wait)
self.list_exec_args.append(code_arg)
else:
self.ui.plainTextEdit_result.appendPlainText("()がありません")
return FAIL
elif(re.match('enter',code)):
self.list_exec_func.append(pc_op.enter)
code_arg = 0
self.list_exec_args.append(code_arg)
elif(re.match('desktop',code)):
self.list_exec_func.append(pc_op.desktop)
code_arg = 0
self.list_exec_args.append(code_arg)
else:
self.ui.plainTextEdit_result.appendPlainText("invalid function")
return FAIL
return SUCCESS
AK003_V1001func.py
# -*- coding: utf-8 -*-
"""
Created on Sun Dec 27 16:27:00 2020
@author: asahi
"""
import time
import pyautogui as pg
import threading
def click(self,args):
print("clickが呼ばれました引数{}".format(args))
#state_search = 'STATE_SEARCH_CHROME'
#検索画像が見つかった場所の座標系が返る
nsec = 0
timeout = 5
while True:
#state_search = 'STATE_SEARCH_CHROME'
#検索画像が見つかった場所の座標系が返る
#button_position = get_locate_from_filename(args)
#pg.hotkeyがすぐ動いてくれない?
#note
#.はpythonファイルがあるフォルダ(カレントディレクトリ)を表しpictureフォルダ内の画像を引数とする
#+を使うことで文字列の中に変数を展開できる
#print(str(self.dir_path_rel)+"\\"+args)
#print("./picture/grope_0/"+args)
#dir_path_relはwindowsパス(¥¥)表記なので+で連結できない
#なのでstrで文字列に直す
button_position = get_locate_from_filename("./"+str(self.dir_path_rel)+"/"+args)
#button_position = get_locate_from_filename("./picture/grope_0/"+args)
#button_position = get_locate_from_filename("C:/Users/asahi/Documents/30_業務/40_改善提案/FF_kitada/00_program/AK003_V1001/picture/grope_0/chrome.png")
if(button_position != None):
#pg.click(button_position)
print("button_position = {}".format(button_position) )
pg.click(button_position)
break
else:
time.sleep(0.5)
print("もう一回探します")
nsec += 1
if( nsec > timeout):
pg.alert(text = 'タイムアウト', button ='OK')
break
def dclick(self,args):
print("dclickが呼ばれました引数{}".format(args))
#state_search = 'STATE_SEARCH_CHROME'
#検索画像が見つかった場所の座標系が返る
nsec = 0
timeout = 5
print(str(self.dir_path_rel))
while True:
button_position = get_locate_from_filename("./"+str(self.dir_path_rel)+"/"+args)
if(button_position != None):
print("button_position = {}".format(button_position) )
pg.doubleClick(button_position)
break
else:
time.sleep(0.5)
print("もう一回探します")
nsec += 1
if( nsec > timeout):
pg.alert(text = 'タイムアウト', button ='OK')
break
def typekey(self,args):
print("typekeyが呼ばれました引数{}".format(args))
pg.typewrite(args)
def enter(self,args):
print("enterが呼ばれました引数{}".format(args))
pg.press('enter',presses = 2, interval = 0.5)
def wait(self,args):
print("waitが呼ばれました引数{}".format(args))
#sleepの引数はintでないといけないのでキャストしている
time.sleep(int(args))
def press_key(self,args):
print("press_keyが呼ばれました")
pass
def desktop(self,args):
print("desktopが呼ばれました")
pg.hotkey('win','d')
#画像ファイルから座標を取得する処理
def get_locate_from_filename(filename):
locate = None
time.sleep(1)
#グレイスケール処理で95%一致判定
#検索画像の座標取得
print(filename)
try:
locate = pg.locateCenterOnScreen(filename,grayscale = True,confidence=0.8)
return locate
except:
print("画像ありません")
return False