From 2066821eb802eff8058f4389e08bde10e0a315c6 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Sun, 24 Mar 2019 22:10:37 +0300 Subject: [PATCH] #GUISearchModeOnline #Customization #HelpLinks #DebugFix --- Index.xhtml | 67 ++++++---- winGUI.py | 377 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 314 insertions(+), 130 deletions(-) diff --git a/Index.xhtml b/Index.xhtml index ec80a8fc..db0a26fa 100644 --- a/Index.xhtml +++ b/Index.xhtml @@ -124,7 +124,7 @@ \ \
\ -
'+inItem.name+'
\ +
'+inItem.title+'
\
process_id:'+inItem.process_id+'; handle:'+inItem.handle+'; class_name: '+inItem.class_name+'; RECT:L'+inItem.rectangle.left+' T'+inItem.rectangle.top+' R'+inItem.rectangle.right+' B'+inItem.rectangle.bottom+'
\ '+lSubListHTML+'\
\ @@ -158,7 +158,7 @@ \ \
\ -
'+lResponseJSON.outputObject[i].name+'
\ +
'+lResponseJSON.outputObject[i].title+'
\
process_id:'+lResponseJSON.outputObject[i].process_id+'; handle:'+lSubItemHandleId+'; class_name: '+lResponseJSON.outputObject[i].class_name+'; RECT:L'+lResponseJSON.outputObject[i].rectangle.left+' T'+lResponseJSON.outputObject[i].rectangle.top+' R'+lResponseJSON.outputObject[i].rectangle.right+' B'+lResponseJSON.outputObject[i].rectangle.bottom+'
\
\ ' @@ -197,7 +197,26 @@ $(".rpa-hierarchy").html(lHTMLList) $(".rpa-object-tree .item").css("background-color",""); $("#"+inElementId).css("background-color","RGB(128,128,128)"); - $(".rpa-gui-selector")[0].value=(JSON.stringify(lSpecificationArray)) + ///Создать урезанную версию селектора + lTextAreaSpecificationArray=Array.from(lSpecificationArray); + for (var i = 0; i< lTextAreaSpecificationArray.length; i++) { + Object.assign(lTextAreaSpecificationArray[i],lTextAreaSpecificationArray[i]); + ///Очистить ненужные ключи для выборки + delete lTextAreaSpecificationArray[i]['rich_text'] + delete lTextAreaSpecificationArray[i]['process_id'] + delete lTextAreaSpecificationArray[i]['rectangle'] + delete lTextAreaSpecificationArray[i]['control_id'] + delete lTextAreaSpecificationArray[i]['process'] + delete lTextAreaSpecificationArray[i]['name'] + delete lTextAreaSpecificationArray[i]['handle'] + delete lTextAreaSpecificationArray[i]['control_type'] + delete lTextAreaSpecificationArray[i]['runtime_id'] + if (i!=0) { + delete lTextAreaSpecificationArray[i]['title'] + delete lTextAreaSpecificationArray[i]['class_name'] + } + } + $(".rpa-gui-selector")[0].value=(JSON.stringify(lTextAreaSpecificationArray)) } mGlobal.ElementPropertyListLoad=function(inElementId) { //Подгрузка массива спецификаций @@ -270,7 +289,7 @@ $.ajax({ type: "POST", url: 'GUIAction', - data: '{"functionName":"ElementDrawOutlineNew","argsArray":['+lSpecificationArray+']}', + data: '{"functionName":"ElementDrawOutlineNewFocus","argsArray":['+lSpecificationArray+']}', success: function(lData,l2,l3) { @@ -463,7 +482,7 @@ \
\
\ - '+lResponseJSON.outputObject[i].name+'\ + '+lResponseJSON.outputObject[i].title+'\ process_id:'+lResponseJSON.outputObject[i].process_id+'; handle:'+lSubItemHandleId+'; class_name: '+lResponseJSON.outputObject[i].class_name+'; RECT:L'+lResponseJSON.outputObject[i].rectangle.left+' T'+lResponseJSON.outputObject[i].rectangle.top+' R'+lResponseJSON.outputObject[i].rectangle.right+' B'+lResponseJSON.outputObject[i].rectangle.bottom+'
\
\ ' @@ -543,9 +562,9 @@

OpenRPA

-
+
-
+
by UnicodeLabs
@@ -587,7 +606,7 @@
Edit GUI selector
- +
@@ -639,35 +658,35 @@

OpenRPA

-

Open source Robotic Process Automation software by the Unicode Labs (Ivan Maslov). Under the MIT license.

+

Open source Robotic Process Automation software by the Unicode Labs (Created by Ivan Maslov). Under the MIT license.

diff --git a/winGUI.py b/winGUI.py index 933d50ff..6aad3aad 100644 --- a/winGUI.py +++ b/winGUI.py @@ -16,6 +16,8 @@ from threading import Timer mFlagIsDebug=False mPywinautoApplication=pywinauto.Application(backend="win32") +mPywinautoActiveBackend="win32" +#mPywinautoActiveBackend="uia" #mPywinautoApplication=pywinauto.Application(backend="uia") ##### @@ -29,57 +31,85 @@ mPywinautoApplication=pywinauto.Application(backend="win32") #inElementSpecificationList = [ [{lvl_0},{lvl_1},{lvl_2}],... ] #result = pywinauto element wrapper instance or None -def AutomationSearchMouseElement(inElementSpecification): - lBitmap={} +def AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline=True): lGUISearchElementSelected=None - #Создать карту пикселей и элементов - lBitmap=GUISearchBitmapCreate(GetControl(inElementSpecification),lBitmap) - #Выдать сообщение, что поиск готов к использованию - #print("GUISearch: Ready for search!") - ########### - #Версия с задержкой (без таймеров, событий в отдельных потоках) - ########### - #Сбросить нажатие Ctrl, если оно было - bool(win32api.GetAsyncKeyState(17)) #Настройка - частота обновления подсвечивания - lTimeSleepSeconds=0.7 - - 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() + lTimeSleepSeconds=0.4 + #Ветка поиска в режиме реального времени + 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 не написана + lElementFounded=GUISearchElementByRootXY(GetControl(inElementSpecification),lX,lY) + #Подсветить объект, если он мышь раньше стояла на другом объекте + if lGUISearchElementSelected != lElementFounded: + lGUISearchElementSelected = lElementFounded #Доработанная функция отрисовки - draw_outline_new(lBitmap[lX,lY]) + if lElementFounded is not None: + draw_outline_new(lElementFounded) else: - lGUISearchElementSelected = None - else: - #Была нажата клавиша Ctrl - выйти из цикла - lFlagLoop=False; - #Заснуть до следующего цикла - time.sleep(lTimeSleepSeconds) + #Была нажата клавиша Ctrl - выйти из цикла + lFlagLoop=False; + #Заснуть до следующего цикла + time.sleep(lTimeSleepSeconds) + #Ветка поиска по заранее созданной карте + else: + lBitmap={} + #Создать карту пикселей и элементов + lBitmap=GUISearchBitmapCreate(GetControl(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 lGUISearchElementSelected -def AutomationSearchMouseElementHierarchy(inElementSpecification): +def AutomationSearchMouseElementHierarchy(inElementSpecification,inFlagIsSearchOnline=True): lItemInfo = None #Запустить функцию поиска элемента по мыши - lElement = AutomationSearchMouseElement(inElementSpecification) + lElement = AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline) #Detect backend of the elements lFlagIsBackendWin32 = True - if lElement.backend.name == 'uia': - lFlagIsBackendWin32 = False #Если объект имеется (не None), то выполнить построение иерархии if lElement is not None: + if lElement.backend.name == 'uia': + lFlagIsBackendWin32 = False #Циклическое создание дерева while lElement is not None: #Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None @@ -197,9 +227,9 @@ def ProcessParentWriteString(lString): #print(b"Result: "+lByteString) #lByteString= b'x\x9c\xdd\x95]O\xc20\x14\x86\xffJ\xb3[5\xa1Cqz\x07\xc4\xe8\x8d\x1fQ\x13.\x0cYJw\xb6U\xbav\xe9\xce"\x84\xf0\xdfm\'"\xb8\xa0L%Q\xb3\x9b\xf6=\xdfO\x9a\xb3\x99\x17\x97\x8a\xa3\xd0\xea\x8ae\xe0\x9d\x12\xaf[\xa2\xce\x98S\xee\x80\x19\x9e^\xea\xb2\x803\t\x19(\xbc\x10`\x9c6\xf5\xf6\x89\xc7LRt\x8daS\x1b\xf5\xf00\xf3\xd4"\xc1u\x0e\xea\xf6\xa6K\x0e\xc8\xb9\xd6\x89\x04\xd2O\x8d\xb6&\x1bb\x04OC\x84\t~\xe2\x97\x1b\xcd\xa1(B\x11YG\xdaj\xfb\xc1\x9b\xb8\xa2\xa4LE\xd2\xd5\xa4\xf6\xdenY\x85Kf\xc3^;yI\x18\x0eD\x94\x00\x0e\x84{{n}}\xa9K\xce\xb5B\xa3e\x88\xd3\xbc\xf2Z\xd5\xaa\x82\xaa\x94\xd25\x0b\x1c\x99J\xaa\x023OB\xec\xbavEP\xe7\x8b\x93\x11I\xeaTz\xe2\xbb\xebH\xa3eW5\xe8\xb7\xe6\xce^*\x14\xb6\x83e\xda\xf9phe]b^\xe2\xf5\xe8\xd1Vp\xf0\xfe.\xbb\x1b\xa6`\x87\xfc8\x1a\x9bSE0q\xa2\x15\xeer\xe0"\x16\xbcz\x9f\xfdT\xc8h\x9d\xdf\xc7\xd4\xbe\xcdj1\xd9:\xa9\x1f\xe1B7\x81\xa1\xef\xc0\xd0:\x98\xc3-\xc0\xd4X\xfc\xda\xf1i\xbb\xe9\xfc\xdb<\x8c\xff2\x7f\'\xa8\x8d\xdf\xdab\xfc\x9e\xd6\xe3\x8c\x99qQ\xe3\xb0f\xd9\x19\x90{\xade\x8f\x99/3\xa1AC(\xfe\x16P\x06F \x90\xb3\t\x07Iba\x17\x83P\xa4\xbf\xb7G\x9e\x04\xa6vE\x13\xb6\xfc\x13\xd6\xa85\x0b\xdd\x19\xd6^i\x11\xa8FT;G\xfe\x06\xac\xc1q\xb0N\x956\xd84\xae\xe4p\xbe\xfa=\x03\x01\xce\x95\x9a' #lByteString = b"x\x9c\xb5\x91\xcfO\xc3 \x14\xc7\xff\x95\xa6\xd7uI\xf9Q\x8a\xde\xd4\x93\x07\xbdx\xf00\x97\x05)[I(\x90\x8ef3\xcb\xfew\x81M\xbb\xd9M]\x8c!y\xd0\xf7}\xbc\xef\xe3\xd3\xc9&\xd5\xac\x11\xe9u\x92j\xb1J@2N\x1e\x8d\x13\x96U\xa3Q\x9a%i+y=sb\xed\xceV\xd8\xd6p\xb1\\\xced\xe5K{{n}}\x80`\x9f\xeb\x135\xd3\x95{{n}}.\x08RR\xe4>\xc3\x15\xf3\x97>\xbc\x8f:r\xa3]k\xd4\xcc\xbd\xd9(>K]\x99\xd5\xa1\x12\xbd\x00\xc6\xb0\xcc\xcb0\xa4\xe0\x8e\xe9E4\xd8\xa4J\xcc\xc3\xb44\x07^r\xc6\xfa3\x04(\xbeeQ\x07\x05P\x1a\xa4W\xe3\x9ci\xfc\xf7\x15(\xb6A\xee\xb4\x93\x8d\xd85\x9f`?\xf6n\xd8i0v\xadw\xd5\x95X\x87n>\xf1d\x05\x97s\xc9\x99\x93F\xdf\xd5R\xc5K=\xcc\x1bk\xd5^\x1d`\xfc\xa2]\x06PwJ\r\xf0\x9d\xa2\xf6 tw\xcb\xda\x01\xb6}\x83\xd3\xcc\x00\xec\x99\x15\xf4\x88Y\x99\x1f2\x83\xb4\xfc\x8e\x99\xdf\xb3d\x0c\x01.1E\x04\x93l\xff\x8e\xcf\x7f6\xa4Z\xfc\x82\xeaK\x97c BD\xf3\x101\x89g\xba\x8b\x03\xd0?\x97\xff#\xfb{'\x9a\x8b\xe0\x03H\xc89\xfa\x08\x15\x7f\xa2\x0f >\x80_\x0e\xe0\x93\xb3\xf0\xc3\xc4\xd3m\\\xef\xf8\x958\xa0" - lt=open("logSendByteStringWithoutN.log","wb") - lt.write(lByteString) - lt.close() + #lt=open("logSendByteStringWithoutN.log","wb") + #lt.write(lByteString) + #lt.close() ############################ sys.stdout.buffer.write(lByteString+bytes("\n","utf-8")) sys.stdout.flush(); @@ -226,7 +256,7 @@ def GetControl(inControlSpecificationArray): lResultList=[]; if len(inControlSpecificationArray) > 0: #Выполнить подключение к объекту - lRPAApplication = pywinauto.Application() + lRPAApplication = pywinauto.Application(backend=mPywinautoActiveBackend) #Проверка разрядности lRPAApplication.connect(**inControlSpecificationArray[0]) #lTempObject=lRPAApplication.window(**inControlSpecificationArray[0]) @@ -243,7 +273,17 @@ def GetControl(inControlSpecificationArray): def ElementActionGetList (inControlSpecificationArray): #Получить объект lObject=GetControl(inControlSpecificationArray) - return dir(lObject.wrapper_object()) + lActionList=dir(lObject.wrapper_object()) + lResult=dir(lObject.wrapper_object()) + #Выполнить чистку списка от неактуальных методов + for lActionItem in lActionList: + #Удалить те, которые начинаются на _ + if lActionItem[0]=='_': + lResult.remove(lActionItem) + #Удалить те, которые начинаются с символа верхнего регистра + if lActionItem[0].isupper(): + lResult.remove(lActionItem) + return lResult #Выполнить действие над элементом def ElementRunAction(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}): #Определить объект @@ -308,7 +348,7 @@ def GUISearchRun(inSpecificationArray): #Создать карту пикселей и элементов lBitmap=GUISearchBitmapCreate(GetControl(inSpecificationArray),lBitmap) #Выдать сообщение, что поиск готов к использованию - print("GUISearch: Ready for search!") + #print("GUISearch: Ready for search!") #mBitmap=lBitmap # Collect events until released #Версия с Events (занимает поток, чтобы использовать общие переменные) @@ -351,6 +391,78 @@ def GUISearchRun(inSpecificationArray): time.sleep(lTimeSleepSeconds) #Вернуть результат поиска return lGUISearchElementSelected + +############################################################# +#Поиск элементов +############################################################# +def GUISearchElementByRootXY(inRootElement,inX,inY): + #Инициализация результирующего значения + lResultElement = None + lResultElementX1 = None + lResultElementX2 = None + lResultElementY1 = None + lResultElementY2 = None + #Получить координаты текущего объекта + try: + lRootElementRectX1=inRootElement.element_info.rectangle.left + lRootElementRectX2=inRootElement.element_info.rectangle.right + lRootElementRectY1=inRootElement.element_info.rectangle.top + lRootElementRectY2=inRootElement.element_info.rectangle.bottom + #Добавить объект в результирующий, если координаты попадают в него + if inX>=lRootElementRectX1 and inX<=lRootElementRectX2 and inY>=lRootElementRectY1 and inY<=lRootElementRectY2: + lResultElement = inRootElement + lResultElementX1 = lRootElementRectX1 + lResultElementX2 = lRootElementRectX2 + lResultElementY1 = lRootElementRectY1 + lResultElementY2 = lRootElementRectY2 + #Получить список детей и добавить в карту + for lChildElement in inRootElement.children(): + lChildFoundedElement = GUISearchElementByRootXY(lChildElement,inX,inY) + #Установить обнаруженный элемент, если текущий результат пустой + if lResultElement is None and lChildFoundedElement is not None: + lResultElement = lChildFoundedElement + lResultElementX1 = lResultElement.element_info.rectangle.left + lResultElementX2 = lResultElement.element_info.rectangle.right + lResultElementY1 = lResultElement.element_info.rectangle.top + lResultElementY2 = lResultElement.element_info.rectangle.bottom + #Выполнить сверку lChildFoundedElement и lResultElement если оба имеются + elif lResultElement is not None and lChildFoundedElement is not None: + #Правила перезатирания карты, если имеется старый объект + #[Накладываемый объект] - НО - ElementNew + #[Имеющийся объект] - ИО - ElementOld + #3 типа вхождения объектов + #тип 1 - [имеющийся объект] полностью входит в [накладываемый объект] (ИО X1 Y1 >= НО X1 Y1; ИО X2 Y2 <= НО X2 Y2) - не вносить НО в bitmap в эти диапазоны + #тип 2 - [имеющийся объект] полностью выходит за пределы [накладываемого объекта] (ИО X1 Y1 < НО X1 Y1; ИО X2 Y2 > НО X2 Y2) - вносить НО в bitmap + #тип 3 - [имеющийся объект] частично входит в [накладываемый объект] (все остальные случаи)- вносить НО в bitmap + #Получить координаты ИО + lChildFoundedElementInfo = lChildFoundedElement.element_info + #lElementNew = inElement + lChildFoundedElementX1 = lChildFoundedElementInfo.rectangle.left + lChildFoundedElementX2 = lChildFoundedElementInfo.rectangle.right + lChildFoundedElementY1 = lChildFoundedElementInfo.rectangle.top + lChildFoundedElementY2 = lChildFoundedElementInfo.rectangle.bottom + #Проверка вхождения по типу 1 + if (lResultElementX1>=lChildFoundedElementX1) and (lResultElementY1>=lChildFoundedElementY1) and (lResultElementX2<=lChildFoundedElementX2) and (lResultElementY2<=lChildFoundedElementY2): + False == True + #Проверка вхождения по типу 3 + elif (lResultElementX1lChildFoundedElementX2) and (lResultElementY2>lChildFoundedElementY2): + lResultElement = lChildFoundedElement + lResultElementX1 = lChildFoundedElementX1 + lResultElementX2 = lChildFoundedElementX2 + lResultElementY1 = lChildFoundedElementY1 + lResultElementY2 = lChildFoundedElementY2 + #Проверка вхождения по типу 2 + else: + lResultElement = lChildFoundedElement + lResultElementX1 = lChildFoundedElementX1 + lResultElementX2 = lChildFoundedElementX2 + lResultElementY1 = lChildFoundedElementY1 + lResultElementY2 = lChildFoundedElementY2 + except Exception as e: + False == False + return lResultElement +#Техническая функция + def GUISearchBitmapCreate (inElement,inBitmapDict={}): #Добавить в карту информацию о текущем объекте inBitmapDict=GUISearchBitmapElementFill(inElement,inBitmapDict) @@ -362,6 +474,7 @@ def GUISearchBitmapCreate (inElement,inBitmapDict={}): #GUISearchBitmapElementFill def GUISearchBitmapElementFill (inElement,inBitmapDict): lElementInfo=inElement.element_info + #pdb.set_trace() #Получить параметры прямоугольника lElementRectX1 = 0 lElementRectX2 = 0 @@ -373,22 +486,64 @@ def GUISearchBitmapElementFill (inElement,inBitmapDict): lElementRectX2=lElementInfo.rectangle.right lElementRectY1=lElementInfo.rectangle.top lElementRectY2=lElementInfo.rectangle.bottom + #Выполнить установку элемента, если прямоугольник получить удалось + if lFlagHasRect: + lX=lElementRectX1 + #Циклический обход по оси X + while lX<=lElementRectX2: + lY=lElementRectY1 + #Циклический обход по Оси Y + while lY<=lElementRectY2: + ###################### + #Если объект в карте есть + if (lX,lY) in inBitmapDict: + if inBitmapDict[lX,lY] is not None: + #Правила перезатирания карты, если имеется старый объект + #[Накладываемый объект] - НО - ElementNew + #[Имеющийся объект] - ИО - ElementOld + #3 типа вхождения объектов + #тип 1 - [имеющийся объект] полностью входит в [накладываемый объект] (ИО X1 Y1 >= НО X1 Y1; ИО X2 Y2 <= НО X2 Y2) - не вносить НО в bitmap в эти диапазоны + #тип 2 - [имеющийся объект] полностью выходит за пределы [накладываемого объекта] (ИО X1 Y1 < НО X1 Y1; ИО X2 Y2 > НО X2 Y2) - вносить НО в bitmap + #тип 3 - [имеющийся объект] частично входит в [накладываемый объект] (все остальные случаи)- вносить НО в bitmap + #Получить координаты ИО + lElementOldInfo = inBitmapDict[lX,lY].element_info + #lElementNew = inElement + lElementOldX1 = lElementOldInfo.rectangle.left + lElementOldX2 = lElementOldInfo.rectangle.right + lElementOldY1 = lElementOldInfo.rectangle.top + lElementOldY2 = lElementOldInfo.rectangle.bottom + #Проверка вхождения по типу 1 + if (lElementOldX1>=lElementRectX1) and (lElementOldY1>=lElementRectY1) and (lElementOldX2<=lElementRectX2) and (lElementOldY2<=lElementRectY2): + #Выполнить корректировку каретки по lY, чтобы не проходить по всем пикселям в рамках этой линии + lY = lElementOldY2 + 1 + #Проверка вхождения по типу 3 + elif (lElementOldX1lElementRectX2) and (lElementOldY2>lElementRectY2): + #Установка элемента по адресу [,] + inBitmapDict[lX,lY]=inElement + #Инкремент y + lY=lY+1 + #Проверка вхождения по типу 2 + else: + #Установка элемента по адресу [,] + inBitmapDict[lX,lY]=inElement + #Инкремент y + lY=lY+1 + #Если объекта в карте нет + else: + #Установка элемента по адресу [,] + inBitmapDict[lX,lY]=inElement + #Инкремент y + lY=lY+1 + else: + #Установка элемента по адресу [,] + inBitmapDict[lX,lY]=inElement + #Инкремент y + lY=lY+1 + ###################### + #Инкремент X + lX=lX+1 except Exception as e: lFlagHasRect = False - #Выполнить установку элемента, если прямоугольник получить удалось - if lFlagHasRect: - lX=lElementRectX1 - #Циклический обход по оси X - while lX<=lElementRectX2: - lY=lElementRectY1 - #Циклический обход по Оси Y - while lY<=lElementRectY2: - #Установка элемента по адресу [,] - inBitmapDict[lX,lY]=inElement - #Инкремент y - lY=lY+1 - #Инкремент X - lX=lX+1 return inBitmapDict #debug def ElementGetChildElementList(inControlSpecificationArray=[]): @@ -593,10 +748,10 @@ def JSONNormalizeDictList(inDictList): #Получить объект из атрибутов, которые удалось прочитать def ElementInfoExportObject(inElementInfo): #Подготовить выходную структуру данных - lResult = {"name":None,"rich_text":None,"process_id":None,"process":None,"handle":None,"class_name":None,"control_type":None,"control_id":None,"rectangle":{"left":None,"top":None,"right":None,"bottom":None}, 'runtime_id':None} + lResult = {"title":None,"rich_text":None,"process_id":None,"process":None,"handle":None,"class_name":None,"control_type":None,"control_id":None,"rectangle":{"left":None,"top":None,"right":None,"bottom":None}, 'runtime_id':None} #Проверка name try: - lResult['name']=inElementInfo.name + lResult['title']=inElementInfo.name except Exception as e: True == False #Проверка rich_text @@ -670,52 +825,62 @@ def GetRootElementList(): def ElementDrawOutlineNew(inSpecificationArray): draw_outline_new(GetControl(inSpecificationArray)) return -def draw_outline_new(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None): - """ - Draw an outline around the window. - * **colour** can be either an integer or one of 'red', 'green', 'blue' - (default 'green') - * **thickness** thickness of rectangle (default 2) - * **fill** how to fill in the rectangle (default BS_NULL) - * **rect** the coordinates of the rectangle to draw (defaults to - the rectangle of the control) - """ - #pdb.set_trace() - # don't draw if dialog is not visible - #if not lWrapperObject.is_visible(): - # return - colours = { - "green": 0x00ff00, - "blue": 0xff0000, - "red": 0x0000ff, - } - # if it's a known colour - if colour in colours: - colour = colours[colour] - if rect is None: - rect = lWrapperObject.rectangle() - # create the pen(outline) - pen_handle = win32functions.CreatePen( - win32defines.PS_SOLID, thickness, colour) - # create the brush (inside) - brush = win32structures.LOGBRUSH() - brush.lbStyle = fill - brush.lbHatch = win32defines.HS_DIAGCROSS - brush_handle = win32functions.CreateBrushIndirect(ctypes.byref(brush)) - # get the Device Context - dc = win32functions.CreateDC("DISPLAY", None, None, None ) - # push our objects into it - win32functions.SelectObject(dc, brush_handle) - win32functions.SelectObject(dc, pen_handle) - # draw the rectangle to the DC - win32functions.Rectangle( - dc, rect.left, rect.top, rect.right, rect.bottom) - # Delete the brush and pen we created - win32functions.DeleteObject(brush_handle) - win32functions.DeleteObject(pen_handle) - # delete the Display context that we created - win32functions.DeleteDC(dc) - +def ElementDrawOutlineNewFocus(inSpecificationArray): + draw_outline_new_focus(GetControl(inSpecificationArray)) + return +def draw_outline_new(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None,inFlagSetFocus=False): + if lWrapperObject is not None: + """ + Draw an outline around the window. + * **colour** can be either an integer or one of 'red', 'green', 'blue' + (default 'green') + * **thickness** thickness of rectangle (default 2) + * **fill** how to fill in the rectangle (default BS_NULL) + * **rect** the coordinates of the rectangle to draw (defaults to + the rectangle of the control) + """ + if inFlagSetFocus: + #Установить фокус на объект, чтобы было видно выделение + lWrapperObject.set_focus() + + #pdb.set_trace() + # don't draw if dialog is not visible + #if not lWrapperObject.is_visible(): + # return + colours = { + "green": 0x00ff00, + "blue": 0xff0000, + "red": 0x0000ff, + } + # if it's a known colour + if colour in colours: + colour = colours[colour] + if rect is None: + rect = lWrapperObject.rectangle() + # create the pen(outline) + pen_handle = win32functions.CreatePen( + win32defines.PS_SOLID, thickness, colour) + # create the brush (inside) + brush = win32structures.LOGBRUSH() + brush.lbStyle = fill + brush.lbHatch = win32defines.HS_DIAGCROSS + brush_handle = win32functions.CreateBrushIndirect(ctypes.byref(brush)) + # get the Device Context + dc = win32functions.CreateDC("DISPLAY", None, None, None ) + # push our objects into it + win32functions.SelectObject(dc, brush_handle) + win32functions.SelectObject(dc, pen_handle) + # draw the rectangle to the DC + win32functions.Rectangle( + dc, rect.left, rect.top, rect.right, rect.bottom) + # Delete the brush and pen we created + win32functions.DeleteObject(brush_handle) + win32functions.DeleteObject(pen_handle) + # delete the Display context that we created + win32functions.DeleteDC(dc) +#Аналог подсвечивания + установка фокуса +def draw_outline_new_focus(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None): + draw_outline_new(lWrapperObject,'green',2,win32defines.BS_NULL,None,True) #run() lText = "Bitness:" + str(struct.calcsize("P") * 8) #for line in sys.stdin: