#Robot_ModuleGUI_Refactoring_50%

dev-linux
Ivan Maslov 6 years ago
parent 165b6290b1
commit 35aa1ea7ef

@ -20,6 +20,16 @@ from threading import Timer
#################################### ####################################
# GUI Module - interaction with Desktop application # GUI Module - interaction with Desktop application
#GUI Naming convention
#<InArgument>_<ActivityName>_<OutArgument - if exist>
#UIO - UI Object (class of pywinauto UI object)
#UIOSelector - List of dict (key attributes)
#PWA - PyWinAuto
#PWASpecification - List of dict (key attributes in pywinauto.find_window notation)
#UIOTree - Recursive Dict of Dict ... (UI Parent -> Child hierarchy)
#UIOInfo - Dict of UIO attributes
#UIOActivity - Activity of the UIO (UI object) from the Pywinauto module
#inActivitySpecificationDict: #inActivitySpecificationDict:
#{ #{
@ -43,185 +53,42 @@ from threading import Timer
# Result: <Result, returned from the Activity, int, str, boolean, list, dict> - required if ErrorFlag is false # Result: <Result, returned from the Activity, int, str, boolean, list, dict> - required if ErrorFlag is false
#} #}
mFlagIsDebug=False #inUIOSelector:
#[
mPywinautoApplication=pywinauto.Application(backend="win32") # {
#mPywinautoActiveBackend="win32" # "index":<Позиция элемента в родительском объекте>,
mPywinautoActiveBackend="uia" # "depth_start" - глубина, с которой начинается поиск (по умолчанию 1),
#mPywinautoApplication=pywinauto.Application(backend="uia") # "depth_end" - глубина, до которой ведется поиск (по умолчанию 1),
# "class_name" - наименование класса, который требуется искать,
##### # "title" - наименование заголовка,
##Внимание! Нельзя делать print так как он уходит в родительский поток и ломает механизм взаимодействия # "rich_text" - наименование rich_text,
##Чтобы его использовать надо писать функцию обертку # "backend": <"win32"||"uia", only for the 1-st list element> - if not specified, use mDefaultPywinautoBackend
##### # },
# { ... }
########################### #
####Модуль Automation #]
###########################
#inElementSpecificationList = [ [{lvl_0},{lvl_1},{lvl_2}],... ]
#result = pywinauto element wrapper instance or None
def AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline=True):
lGUISearchElementSelected=None
#Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.4
lElementFoundedList=[]
#Ветка поиска в режиме реального времени
if inFlagIsSearchOnline:
#Сбросить нажатие Ctrl, если оно было
bool(win32api.GetAsyncKeyState(17))
lFlagLoop = True
while lFlagLoop:
#Проверить, нажата ли клавиша Ctrl (код 17)
lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17))
#Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз
if not lFlagKeyPressedCtrl:
#Получить координаты мыши
(lX,lY) = win32api.GetCursorPos()
lElementFounded={}
#Создать карту пикселей и элементов
#####Внимание! Функция GUISearchElementByRootXY не написана
lElementFoundedList=GUISearchElementByRootXY(PywinautoExtElementGet(inElementSpecification),lX,lY)
#print(lElementFoundedList)
lElementFounded=lElementFoundedList[-1]["element"]
#Подсветить объект, если он мышь раньше стояла на другом объекте
if lGUISearchElementSelected != lElementFounded:
lGUISearchElementSelected = lElementFounded
#Доработанная функция отрисовки
if lElementFounded is not None:
draw_outline_new(lElementFounded)
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Ветка поиска по заранее созданной карте
else:
###################################
#Внимание Старая ветка (неправильный результат)
###################################
lBitmap={}
#Создать карту пикселей и элементов
lBitmap=GUISearchBitmapCreate(PywinautoExtElementGet(inElementSpecification),lBitmap)
#Выдать сообщение, что поиск готов к использованию
#print("GUISearch: Ready for search!")
###########
#Версия с задержкой (без таймеров, событий в отдельных потоках)
###########
#Сбросить нажатие Ctrl, если оно было
bool(win32api.GetAsyncKeyState(17))
lFlagLoop = True
while lFlagLoop:
#Проверить, нажата ли клавиша Ctrl (код 17)
lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17))
#Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз
if not lFlagKeyPressedCtrl:
#Получить координаты мыши
(lX,lY) = win32api.GetCursorPos()
#Подсветить объект, если мышь над ним
if (lX,lY) in lBitmap:
if lGUISearchElementSelected != lBitmap[lX,lY]:
lGUISearchElementSelected = lBitmap[lX,lY]
#Классическая функция отрисовки (из pywinauto)
#lBitmap[lX,lY].draw_outline()
#Доработанная функция отрисовки
draw_outline_new(lBitmap[lX,lY])
else:
lGUISearchElementSelected = None
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска
return lElementFoundedList
def AutomationSearchMouseElementHierarchy(inElementSpecification,inFlagIsSearchOnline=True):
lItemInfo = []
#Запустить функцию поиска элемента по мыши
lElementList = AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline)
lElement = lElementList[-1]['element']
#Detect backend of the elements
lFlagIsBackendWin32 = True
#Если объект имеется (не None), то выполнить построение иерархии
#pdb.set_trace()
if lElement is not None:
if lElement.backend.name == 'uia':
lFlagIsBackendWin32 = False
#Циклическое создание дерева
#while lElement is not None:
lListIterator=0
lItemInfo2=lItemInfo
for lListItem in lElementList:
lElement = lListItem["element"]
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
#if not lFlagIsBackendWin32 and lElement.parent() is None:
# lElement = None
#else:
#Получить информацию про объект
lItemInfo2.append(ElementInfoExportObject(lElement.element_info))
#Дообогатить информацией об индексе ребенка в родительском объекте
if "index" in lListItem:
if lListItem["index"] is not None:
lItemInfo2[-1]['ctrl_index']=lListItem["index"]
else:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
else:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
lItemInfo2[-1]['SpecificationChild']=[]
lItemInfo2=lItemInfo2[-1]['SpecificationChild']
#Переход на родительский объект
#lElement = lElement.parent()
lListIterator=lListIterator+1
#Вернуть результат
return lItemInfo
#return [1,2,3,4,5,3]
#Default parameters
mDefaultPywinautoBackend="win32"
########################### ############################
####Модуль PywinautoExt #Новая версия
########################### ############################
def PywinautoExtElementCtrlIndexGet(inElement):
lResult = None
#Выполнить алгоритм, если есть Element
if inElement is not None:
lElementParent = inElement.parent()
if lElementParent is not None:
lResult = 0
lFlagFind = True
#Получить список потомков
lElementParentChildrenList = lElementParent.children()
#Циклический поиск до того момента, пока не упремся в текущий элемент
while lFlagFind:
if lResult<len(lElementParentChildrenList):
#Прекратить поиск, если элемент был обнаружен
if inElement == lElementParentChildrenList[lResult]:
lFlagFind = False
else:
#Прекратить поиски, если итератор вышел за пределы списка
if lResult>=len(lElementParentChildrenList):
lResult = None
lFlagFind = False
else:
lResult = lResult + 1
else:
lResult=-1
lFlagFind=False
#Вернуть результат
return lResult
#Получить список элементов, который удовлетворяет условиям через расширенный движок поиска #Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
#[ { #[
#"index":<Позиция элемента в родительском объекте>, # {
# "depth_start" - глубина, с которой начинается поиск (по умолчанию 1) # "index":<Позиция элемента в родительском объекте>,
# "depth_end" - глубина, до которой ведется поиск (по умолчанию 1) # "depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
# "class_name" - наименование класса, который требуется искать # "depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
# "title" - наименование заголовка # "class_name" - наименование класса, который требуется искать
# "rich_text" - наименование rich_text # "title" - наименование заголовка
#} ] # "rich_text" - наименование rich_text
def PywinautoExtElementsGet (inSpecificationList,inElement=None): # }
#]
################
#return: List of UI Object
#old name - PywinautoExtElementsGet
def UIOSelector_Get_UIOList (inSpecificationList,inElement=None):
lResultList=[] lResultList=[]
lChildrenList=[] lChildrenList=[]
#Получить родительский объект если на вход ничего не поступило #Получить родительский объект если на вход ничего не поступило
@ -307,95 +174,37 @@ def PywinautoExtElementsGet (inSpecificationList,inElement=None):
else: else:
lResultList.extend(lChildrenList) lResultList.extend(lChildrenList)
return lResultList return lResultList
#Получить список информационных объектов, который удовлетворяет условиям
def PywinautoExtElementsGetInfo (inSpecificationList,inElement=None): #################################################################################################
#Получить родительский объект если на вход ничего не поступило #Get first (in more than one) UIO (UI Object)
lResultList=PywinautoExtElementsGet(inSpecificationList,inElement) #inSpecificationList - UIOSelector
lIterator = 0 #old name - PywinautoExtElementGet
for lItem in lResultList: def UIOSelector_Get_UIO (inSpecificationList,inElement=None):
lResultList[lIterator]=ElementInfoExportObject(lResultList[lIterator].element_info)
lIterator = lIterator + 1
return lResultList
#Получить элемент через расширенный движок поиска
#[ {
#"index":<Позиция элемента в родительском объекте>,
#
#} ]
def PywinautoExtElementGet (inSpecificationList,inElement=None):
lResult=None lResult=None
#Получить родительский объект если на вход ничего не поступило #Получить родительский объект если на вход ничего не поступило
lResultList=PywinautoExtElementsGet(inSpecificationList,inElement) lResultList=PywinautoExtElementsGet(inSpecificationList,inElement)
if len(lResultList)>0: if len(lResultList)>0:
lResult=lResultList[0] lResult=lResultList[0]
return lResult return lResult
#Проверить, существует ли объект
def PywinautoExtElementExist (inSpecificationList):
#pdb.set_trace()
return len(PywinautoExtElementsGet(inSpecificationList))>0
#Ожидать появления элемента
def PywinautoExtElementWaitAppear(inSpecificationList,inTimeout=60):
lTimeoutSeconds = 0
while (not PywinautoExtElementExist(inSpecificationList) and inTimeout>lTimeoutSeconds):
lTimeoutSeconds = lTimeoutSeconds + 0.5
#Заснуть на полсекунды
time.sleep(0.5)
return PywinautoExtElementExist(inSpecificationList)
#Функция, которая попытается восстановить окно, если оно есть, но свернуто (особенность uia backend - он не может прицепиться к окну, если оно свернуто)
def PywinautoExtTryToRestore(inSpecificationList):
#pdb.set_trace()
try:
#Подготовка взодного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inSpecificationList)
#Выполнить подключение к объекту. Восстановление необходимо только в бэке win32, так как в uia свернутое окно не распознается
lRPAApplication = pywinauto.Application(backend="win32")
lRPAApplication.connect(**inSpecificationList[0])
lRPAApplication.top_window().restore()
except Exception:
True==False
################################
#Функция повторяющегося таймера
#############################
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.start()
def _run(self):
self.is_running = False
self.start()
self.function(*self.args, **self.kwargs)
def start(self):
if not self.is_running:
self._timer = Timer(self.interval, self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False
#mTimer.start() # after 30 seconds, "hello, world" will be printed
#Флаг отладки напрямую (не выполнять чтение буфера stdin)
################################## ##################################################################################################
###Методы взаимодействия с GUI интерфейсом #inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation
################################## #Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
#pywinauto #return UIO object
def GetControl(inControlSpecificationArray): #old name - GetControl
#Подготовка взодного массива def PWASpecification_Get_UIO(inControlSpecificationArray):
#Определение backend
lBackend=mDefaultPywinautoBackend
if "backend" in inControlSpecificationArray[0]:
lBackend=inControlSpecificationArray[0]["backend"]
#Подготовка входного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray) inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
lResultList=[]; lResultList=[];
lTempObject=None lTempObject=None
if len(inControlSpecificationArray) > 0: if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту #Выполнить подключение к объекту
lRPAApplication = pywinauto.Application(backend=mPywinautoActiveBackend) lRPAApplication = pywinauto.Application(backend=lBackend)
#Проверка разрядности #Проверка разрядности
try: try:
lRPAApplication.connect(**inControlSpecificationArray[0]) lRPAApplication.connect(**inControlSpecificationArray[0])
@ -416,8 +225,179 @@ def GetControl(inControlSpecificationArray):
lTempObject=lTempObject.window(**lWindowSpecification) lTempObject=lTempObject.window(**lWindowSpecification)
return lTempObject return lTempObject
#Получить массив свойств и методов у элемента ###########################################################################################################
def ElementActionGetList (inControlSpecificationArray): #inElementSpecificationList = UIOSelector (see description on the top of the document)
#result = pywinauto element wrapper instance or None
#old name - AutomationSearchMouseElement
def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
lGUISearchElementSelected=None
#Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.4
lElementFoundedList=[]
#Ветка поиска в режиме реального времени
#Сбросить нажатие Ctrl, если оно было
bool(win32api.GetAsyncKeyState(17))
lFlagLoop = True
while lFlagLoop:
#Проверить, нажата ли клавиша Ctrl (код 17)
lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17))
#Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз
if not lFlagKeyPressedCtrl:
#Получить координаты мыши
(lX,lY) = win32api.GetCursorPos()
lElementFounded={}
#Создать карту пикселей и элементов
#####Внимание! Функция GUISearchElementByRootXY не написана
lElementFoundedList=GUISearchElementByRootXY(PywinautoExtElementGet(inElementSpecification),lX,lY)
#print(lElementFoundedList)
lElementFounded=lElementFoundedList[-1]["element"]
#Подсветить объект, если он мышь раньше стояла на другом объекте
if lGUISearchElementSelected != lElementFounded:
lGUISearchElementSelected = lElementFounded
#Доработанная функция отрисовки
if lElementFounded is not None:
draw_outline_new(lElementFounded)
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска
return lElementFoundedList
####################################################################################################
#inElementSpecification - UIOSelector
#old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inElementSpecification):
lItemInfo = []
#Запустить функцию поиска элемента по мыши
lElementList = UIOSelector_SearchChildByMouse_UIO(inElementSpecification,inFlagIsSearchOnline)
lElement = lElementList[-1]['element']
#Detect backend of the elements
lFlagIsBackendWin32 = True
#Если объект имеется (не None), то выполнить построение иерархии
#pdb.set_trace()
if lElement is not None:
if lElement.backend.name == 'uia':
lFlagIsBackendWin32 = False
#Циклическое создание дерева
#while lElement is not None:
lListIterator=0
lItemInfo2=lItemInfo
for lListItem in lElementList:
lElement = lListItem["element"]
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
#if not lFlagIsBackendWin32 and lElement.parent() is None:
# lElement = None
#else:
#Получить информацию про объект
lItemInfo2.append(ElementInfoExportObject(lElement.element_info))
#Дообогатить информацией об индексе ребенка в родительском объекте
if "index" in lListItem:
if lListItem["index"] is not None:
lItemInfo2[-1]['ctrl_index']=lListItem["index"]
else:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
else:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
lItemInfo2[-1]['SpecificationChild']=[]
lItemInfo2=lItemInfo2[-1]['SpecificationChild']
#Переход на родительский объект
#lElement = lElement.parent()
lListIterator=lListIterator+1
#Вернуть результат
return lItemInfo
####################################################################################################
#inElement- UIO (UI Object)
#old name - PywinautoExtElementCtrlIndexGet
def UIO_GetCtrlIndex_Int(inElement):
lResult = None
#Выполнить алгоритм, если есть Element
if inElement is not None:
lElementParent = inElement.parent()
if lElementParent is not None:
lResult = 0
lFlagFind = True
#Получить список потомков
lElementParentChildrenList = lElementParent.children()
#Циклический поиск до того момента, пока не упремся в текущий элемент
while lFlagFind:
if lResult<len(lElementParentChildrenList):
#Прекратить поиск, если элемент был обнаружен
if inElement == lElementParentChildrenList[lResult]:
lFlagFind = False
else:
#Прекратить поиски, если итератор вышел за пределы списка
if lResult>=len(lElementParentChildrenList):
lResult = None
lFlagFind = False
else:
lResult = lResult + 1
else:
lResult=-1
lFlagFind=False
#Вернуть результат
return lResult
####################################################################################################
#Получить список информационных объектов, который удовлетворяет условиям
#inSpecificationList - UIOSelector
#old name - PywinautoExtElementsGetInfo
def UIOSelector_Get_UIOInfoList (inSpecificationList,inElement=None):
#Получить родительский объект если на вход ничего не поступило
lResultList=PywinautoExtElementsGet(inSpecificationList,inElement)
lIterator = 0
for lItem in lResultList:
lResultList[lIterator]=ElementInfoExportObject(lResultList[lIterator].element_info)
lIterator = lIterator + 1
return lResultList
####################################################################################################
#Check is the UIO/UIO's by the UIOSelector exist
#inSpecificationList - UIOSelector
#old name - PywinautoExtElementExist
def UIOSelector_IsExist_Bool (inSpecificationList):
return len(PywinautoExtElementsGet(inSpecificationList))>0
####################################################################################################
#Wait for the UIO by the UIOSelector appear
#inSpecificationList - UIOSelector
#result - { }
#old name - PywinautoExtElementWaitAppear
def UIOSelector_WaitAppear_Dict(inSpecificationList,inTimeout=60):
lTimeoutSeconds = 0
while (not PywinautoExtElementExist(inSpecificationList) and inTimeout>lTimeoutSeconds):
lTimeoutSeconds = lTimeoutSeconds + 0.5
#Заснуть на полсекунды
time.sleep(0.5)
return PywinautoExtElementExist(inSpecificationList)
####################################################################################################
#Try to restore (maximize) window, if it's was minimized
#(особенность uia backend - он не может прицепиться к окну, если оно свернуто)
#inSpecificationList - UIOSelector
#old name - PywinautoExtTryToRestore
def UIOSelector_TryRestore_Dict(inSpecificationList):
lResult={}
try:
#Подготовка взодного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inSpecificationList)
#Выполнить подключение к объекту. Восстановление необходимо только в бэке win32,
#так как в uia свернутое окно не распознается
lRPAApplication = pywinauto.Application(backend="win32")
lRPAApplication.connect(**inSpecificationList[0])
lRPAApplication.top_window().restore()
except Exception:
True==False
return lResult
####################################################################################################
#Get the list of the UI object activities
#inControlSpecificationArray - UIOSelector
#old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inControlSpecificationArray):
#Получить объект #Получить объект
lObject=PywinautoExtElementGet(inControlSpecificationArray) lObject=PywinautoExtElementGet(inControlSpecificationArray)
lActionList=dir(lObject) lActionList=dir(lObject)
@ -431,8 +411,14 @@ def ElementActionGetList (inControlSpecificationArray):
if lActionItem[0].isupper(): if lActionItem[0].isupper():
lResult.remove(lActionItem) lResult.remove(lActionItem)
return lResult return lResult
#Выполнить действие над элементом
def ElementRunAction(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}): ####################################################################################################
#Run the activity in UIO (UI Object)
#inControlSpecificationArray - UIOSelector
#inActionName - UIOActivity (name) from Pywinauto
#old name - ElementRunAction
def UIOSelectorUIOActivity_Run_Dict(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}):
lResult={}
#Определить объект #Определить объект
lObject=PywinautoExtElementGet(inControlSpecificationArray) lObject=PywinautoExtElementGet(inControlSpecificationArray)
#Получить метод для вызова #Получить метод для вызова
@ -455,8 +441,12 @@ def ElementRunAction(inControlSpecificationArray,inActionName,inArgumentList=[],
return lResult return lResult
else: else:
raise e raise e
return lResult
def ElementGetInfo(inControlSpecificationArray): ####################################################################################################
#Get the UIO dict of the attributes
#old name - ElementGetInfo
def UIOSelector_Get_UIOInfo(inControlSpecificationArray):
#Подготовка входного массива #Подготовка входного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray) inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив #Выполнить идентификацию объектов, если передан массив
@ -469,6 +459,16 @@ def ElementGetInfo(inControlSpecificationArray):
#Добавить информацию об обнаруженом объекте #Добавить информацию об обнаруженом объекте
lResultList.append(ElementInfoExportObject(lTempObjectInfo)); lResultList.append(ElementInfoExportObject(lTempObjectInfo));
return lResultList return lResultList
############################
#Старая версия
############################
mFlagIsDebug=False
##################################
############################################ ############################################
###Модуль поиска объекта на экране ###Модуль поиска объекта на экране
############################################ ############################################

Loading…
Cancel
Save