Что нового

Возможно ли программно в скрипте определить полный класс окна с INSTANCE:

Norm

Продвинутый
Сообщения
269
Репутация
70
Всем доброго дня.
Не знаю как решить один вопрос.
Есть окно программы и в этом окне ещё насколько окон с различными классами.
В процессе работы программы происходит смена параметра INSTANCE у этих внутренних окон (изменяется цифра).
Проблема ещё в том, что таких внутренних окон с такими же классами тоже много, поэтому необходимо обращаться с полым названием класса, то есть с INSTANCE.
Поскольку эти номера INSTANCE меняются, то не знаю как обратиться к окну.
Команда типа:
Код:
ControlSend("Tools MS","","[CLASS:TreeView]","{RIGHT}",0)

не срабатывает, поскольку не хватает INSTANCE. И только если я посмотрю полный класс с INSTANCE и изменю его, то на короткий период это работает, а потом такая же проблема.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
если я посмотрю полный класс с INSTANCE и изменю его, то на короткий период это работает
Не думаю, что INSTANCE меняется хаотичным образом. Скорее всего он зависит от текущей раскладки элементов, вызванной определёнными действиями. Поэтому, после выполнения конкретного действия смотрите через Au3Info текущий INSTANCE и обращайтесь по нему.

Например, в калькуляторе Win7 кнопка "=" в режимах "Обычный" и "Инженерный" имеет INSTANCE:28, а в режиме "Программист" - INSTANCE:53. Следовательно, в скрипте после переключения в режим "Обычный" нужно обращаться по индексу 28, а после переключения в режим "Программист" - по индексу 53.
 
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Не думаю, что INSTANCE меняется хаотичным образом. Скорее всего он зависит от текущей раскладки элементов, вызванной определёнными действиями. Поэтому, после выполнения конкретного действия смотрите через Au3Info текущий INSTANCE и обращайтесь по нему.

Например, в калькуляторе Win7 кнопка "=" в режимах "Обычный" и "Инженерный" имеет INSTANCE:28, а в режиме "Программист" - INSTANCE:53. Следовательно, в скрипте после переключения в режим "Обычный" нужно обращаться по индексу 28, а после переключения в режим "Программист" - по индексу 53.
Я тоже практически сразу заметил эту закономерность, и хотел было пойти путем описанным Вами путем, но это очень сильно усложнило бы все алгоритмы и появился бы фактор не недежности.
Надо было бы запоминать каждое действие и потом исходя из пройденного пути подставлять нужный INSTANCE.
Почему нет 100%-го способы это определить :( ?
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
Почему нет 100%-го способы это определить :( ?
Что определить-то? Instans? Ну, допустим, вы перечислили кнопки калькулятора и получили instans'ы с 1 до 28. Переключили режим и теперь у вас кнопки с 1 до 55. Какая из них кнопка "%"? А есть ли вообще в этом режиме данная кнопка? А может в этом режиме она заблокирована? Понимаете? Вам всё равно нужно знать, какой у кнопки instans в данный конкретный момент, чтобы её нажать.
 
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Что определить-то? Instans? Ну, допустим, вы перечислили кнопки калькулятора и получили instans'ы с 1 до 28. Переключили режим и теперь у вас кнопки с 1 до 55. Какая из них кнопка "%"? А есть ли вообще в этом режиме данная кнопка? А может в этом режиме она заблокирована? Понимаете? Вам всё равно нужно знать, какой у кнопки instans в данный конкретный момент, чтобы её нажать.
Дак яж об этом и говорю, что мне нужно это знать, а точнее программно узнать без создания алгоритмов и их возможных вариаций.
На калькуляторе только две раскладки, а у меня только раскладок 12 и в них кнопки тоже. Это нужно где-то хранить. А если у программы будет обновление и что-то изменится, то мне тоже надо всё менять.
Ведь можно же программно определить класс и Au3Info определяет же как-то помимо класса ещё и INSTANCE.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
если у программы будет обновление и что-то изменится, то мне тоже надо всё менять
Так будет довольно часто. Этого не избежать.

Ведь можно же программно определить класс и Au3Info определяет же как-то помимо класса ещё и INSTANCE
Да, можно. Только в вашем случае это не поможет.
Запустите скрипт, наведите на контрол - в тултипе отобразится информация
Код:
#include <WinAPI.au3>

HotKeySet("{ESC}", "Quit")

While Sleep(333)
  $Pos = _WinAPI_GetMousePos()
  $Control = _WinAPI_WindowFromPoint($Pos)
  If $Control = _WinAPI_GetAncestor($Control, 2) Then $Control = ""
  ToolTip("Class : " & _WinAPI_GetClassName($Control) & @CRLF & _
          "Instance : " & GetInstance($Control))
WEnd

Func GetInstance($Control)
  Local $Class, $Wins, $Inst = 0
  $Class = _WinAPI_GetClassName($Control)
  If @error Then Return ""
  $Wins = _WinAPI_EnumChildWindows(_WinAPI_GetAncestor($Control, 2), False)
  If IsArray($Wins) Then
    For $i = 1 To $Wins[0][0]
      If $Wins[$i][1] = $Class Then $Inst += 1
      If $Wins[$i][0] = $Control Then Return $Inst
    Next
  EndIf
  Return ""
EndFunc

Func Quit()
  Exit
EndFunc
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Да, можно. Только в вашем случае это не поможет.
Запустите скрипт, наведите на контрол - в тултипе отобразится информация
Код:
#include <WinAPI.au3>

HotKeySet("{ESC}", "Quit")

While Sleep(333)
  $Pos = _WinAPI_GetMousePos()
  $Control = _WinAPI_WindowFromPoint($Pos)
  If $Control = _WinAPI_GetAncestor($Control, 2) Then $Control = ""
  ToolTip("Class : " & _WinAPI_GetClassName($Control) & @CRLF & _
          "Instance : " & GetInstance($Control))
WEnd

Func GetInstance($Control)
  Local $Class, $Wins, $Inst = 0
  $Class = _WinAPI_GetClassName($Control)
  If @error Then Return ""
  $Wins = _WinAPI_EnumChildWindows(_WinAPI_GetAncestor($Control, 2), False)
  If IsArray($Wins) Then
    For $i = 1 To $Wins[0][0]
      If $Wins[$i][1] = $Class Then $Inst += 1
      If $Wins[$i][0] = $Control Then Return $Inst
    Next
  EndIf
  Return ""
EndFunc

Func Quit()
  Exit
EndFunc
Это уже очень хорошее решение
В качестве полумеры/альтернативы я пока использую обычное MouseMove, MouseClick и Send.
Но всё это не совсем надежно, поскольку нет обращения к названию окна или класса. И если активируется какое-то постороннее окно, то могут быть проблемы.
Так что я и мыш готов подтаскивать куда нужно.
Я попробую самостоятельно Ваш скрипт у себя прикрутить, но если не получится, то Вы не будите против, если я в личку спрошу?
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
не будите против, если я в личку спрошу?
Буду. Не хватало ещё в личке вам объяснять, что вы не с той стороны проблему решаете.
Вот вы пишете
использую обычное MouseMove, MouseClick
Значит, вы знаете, куда мышь двигать. Следовательно, понимаете текущее расположение контролов. Вот посмотрите, какой в этот момент instance и обратитесь по нему.
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Не злитесь пожалуйста, это был только вопрос на который Вы и ответили.
То что Вы дали в ответе, Ваше решениe, сам бы я не смог реализовать, но далее буду естественно сам стараться разобраться.
...... что вы не с той стороны проблему решаете.
Возможно Вы и правы но я пока нахожу Ваше решение очень даже верным,
когда посмотрю на то что мне нужно проделывать со множеством различных окон и подокон и вкладок к этим окнам.
 

Вложения

  • MEP.png
    MEP.png
    181.6 КБ · Просмотры: 12
Последнее редактирование:

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Можно ещё так:

Код:
ControlSend("Tools MS","","[REGEXPCLASS:^TreeView(1|2)$]","{RIGHT}",0)
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Можно ещё так:

Код:
ControlSend("Tools MS","","[REGEXPCLASS:^TreeView(1|2)$]","{RIGHT}",0)
Я прочел Ваш урок 5. Там Вы написали, что это только для CLASS и как я понял без INSTANCE, но всё равно проверил.
Код:
ControlSend("tools","","[REGEXPCLASS:^TTreeView:INSTANCE:(1|2|3|4|5)$]","{TAB}",0)

К сожалению это не стаботало. Но всё равно спасибо за информацию на будущее.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Там Вы написали, что это только для CLASS и как я понял без INSTANCE, но всё равно проверил.
А если так:
Код:
$sTitle = 'Tools MS'
$sClass = 'TreeView'
$iInstance = _ControlGetInstance($sTitle, $sClass, 1, 5)

ControlSend($sTitle, '', $sClass & $iInstance, '{RIGHT}', 0)

Func _ControlGetInstance($sTitle, $sCtrlClass, $iStart, $iEnd)
    For $i = $iStart To $iEnd
        If ControlGetHandle($sTitle, '', '[CLASS:' & $sCtrlClass & ';INSTANCE:' & $i & ']') Then
            Return $i
        EndIf
    Next
    
    Return -1
EndFunc
 
  • Like
Реакции: Norm

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
Нет, нельзя. CLASSNN не поддерживает регулярные выражения.
просто решили эту проблему
А в чём решение проблемы? Эта функция всегда возвращает 1. Даже при наличии нескольких элементов. С таким же успехом можно тупо писать "TreeView1".
 
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Нет, нельзя. CLASSNN не поддерживает регулярные выражения.

А в чём решение проблемы? Эта функция всегда возвращает 1. Даже при наличии нескольких элементов. С таким же успехом можно тупо писать "TreeView1".
Не хочу ни скем спорить.
Но это работает. Я специально проверял в одном и том же окне сначала с одним INSTANCE, а затем с другим INSTANCE.
В скрипте ни одного "жестко" прописанного INSTANCE не указывал. Всё прекрасно работает.
Если не указывать INSTANCE вообще, то в окнах ничего не срабатывает.
Код:
ControlSend("Tools MS","","[CLASS:TreeView]","{RIGHT}",0)

Код:
WinActivate("tools")
Sleep(1000)

Local $sTitle = 'tools'
Local $sClass = 'TTreeView'
Local $sClass2 = 'TPageControl'
Local $iInstance = _ControlGetInstance($sTitle, $sClass, 1, 5)
Local $i
ControlSend($sTitle, '', $sClass & $iInstance, '{TAB}', 0) ; Перепрыгиваю в другое подокно
Sleep(1000)
ControlSend($sTitle, '', $sClass2 & $iInstance, '{RIGHT}', 0) ; Посылаю команду уже в другом


Func _ControlGetInstance($sTitle, $sCtrlClass, $iStart, $iEnd)
For $i = $iStart To $iEnd
If ControlGetHandle($sTitle, '', '[CLASS:' & $sCtrlClass & ';INSTANCE:' & $i & ']') Then
Return $i
EndIf
    Next

    Return -1
EndFunc
По поводу возврата 1
я в самом начале каласс для второго подокна забыл указать и там мне всегда -1 возвращался.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
CLASSNN не поддерживает регулярные выражения
В справке написано иначе, и речь про Class, и да в этом случае это не поможет, т.к меняется не Class а Instance.
Но оно работает:
Код:
$hChrome = ControlGetHandle('[CLASS:Chrome_WidgetWin_1]', '', '[REGEXPCLASS:Intermediate D3D Win.*;Instance:1]')
MsgBox(64, @ScriptName, $hChrome)


в чём решение проблемы? Эта функция всегда возвращает 1
Да, я изначально хотел перебирать цикл с конца, но забыл про это:

Код:
Func _ControlGetInstance($sTitle, $sCtrlClass, $iStart, $iEnd)
    For $i = $iEnd To $iStart Step -1
        If ControlGetHandle($sTitle, '', '[CLASS:' & $sCtrlClass & ';INSTANCE:' & $i & ']') Then
            Return $i
        EndIf
    Next
    
    Return -1
EndFunc


Но тогда это вернёт самый последний Instance.
 
Последнее редактирование:
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Да, я изначально хотел перебирать цикл с конца, но забыл про это:

Код:
Func _ControlGetInstance($sTitle, $sCtrlClass, $iStart, $iEnd)
    For $i = $iEnd To $iStart Step -1
        If ControlGetHandle($sTitle, '', '[CLASS:' & $sCtrlClass & ';INSTANCE:' & $i & ']') Then
            Return $i
        EndIf
    Next
 
    Return -1
EndFunc


Но тогда это вернёт самый последний Instance.
И хорошо, потому что задом на перёд не хочет работать.
 
Верх