Что нового

Какой смысл использования функции ControlClick?

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Для идентификации контрола в функции ControlClick используется его ID, в качестве которого могут выступать непосредственно ID, имя (Advanced (Class) или текст контрола. Но все эти данные изменяются почти при каждом очередном запуске программы и, соответственно окна, к которому применяется эта функция. Допустим, если окно представляет из себя форму на которой находится много кнопок, например кнопки набора телефонного номера, то функция ControlClick: ControlClick ( "title", "text", controlID [, button [, clicks [, x [, y ]]]] ) применяется каждый раз к разным кнопкам, в зависимости от того, какой ID будет назначен каждой конкретной кнопке в очередной раз. Так какой смысл использовать эту функцию, если ее работа непредсказуема?
 

dwerf

Использует ArchLinux
Сообщения
478
Репутация
218
Обычно ID контролов не изменяется. А если изменяется, то ControlClick позволяет нажимать их ориентируясь на текст. Например на цифры на кнопках для набора телефонного номера.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Да в том то и дело, что меняется. Прилагаю скриншоты из которых видно, что при двух разных открытиях окна для одной и той же кнопки №1 все, что может быть использовано в качестве ID разное.


Добавлено:
Сообщение автоматически объединено:

Да, забыл отметить, что как видно из этих же картинок, текст на кнопке также отсутствует. По указанным выше причинам написанный с помощью ControlClick скрипт набирает все время другой номер.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
В таких случаях можно дополнительно для детекта кнопки использовать ее положение на форме, размер и т.д., т.е.
Код:
ControlGetPos
и условия.


Хорошая вещь - функция
Код:
_WinAPI_EnumChildWindows()
из библиотеки WinAPIEx.au3 http://autoit-script.ru/index.php/topic,47.0.html
Позволяет получить массив всех элементов окна с идентификаторами и классами.


Кроме того, можно просканировать кнопки Control Viewer
http://autoit-script.ru/index.php/topic,4579.0.html
и InqSoft Window Scanner http://kickme.to/inqsoft
Возможно, будет получена дополнительная информация.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Какой смысл пользоваться функцией ControlGetPos, если она тоже использует ID контрола? Суть состоит в том, что в скрипте необходимо раз и навсегда прописать доступ к определенному контролу, чтобы этот доступ можно было бы реализовать независимо от времени запуска программы и работы с ней. А так не то, что при каждом очередном запуске программы, а даже при работе с ее другими окнами, ID контролов постоянно меняются. Так что остается только возможность работы с координатами. Вот и возникает вопрос: зачем тогда нужна функция ControlClick, ровно как и другие функции работы с контролами, если их нельзя идентифицировать с абсолютной точностью?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 714
Как правило, ID остаются постоянными. В данном случае, программа формирует элементы по ходу ее работы. Аналогичная ситуация возникает на вкладках Windows.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 320
vitaliy4us,
ИМХО, у Вас очень поверхностное знакомство с AutoIt и, зная о языке очень мало, Вы считаете, что его функции не работают, а зря. Кроме ID, в функциях Control*** можно много еще чего использовать в качестве указателя на элемент окна. Скачал и установил GWTalk версии 2.0.0.25. AutoIt без проблем с его окном работает у меня. Вот Вам пример набора номера двумя способами (есть еще третий - через Handle):
Код:
Dim $aButtonNum[10] = ['14]', '16]', '17]', '13]', '18]', '19]', '20]', '21]', '22]', '23]']
$sR = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:15]'; #
$sZ = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:24]';*
$sClear = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:27]';CLEAR
$sButton = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:'
$sEdit = '[NAME:tbDialNumber]'

If Not WinExists('GWTalk') Then
	Run(@ProgramFilesDir & '\SKyPRO\GWTalk\GWTalk.exe')
EndIf
$hWin = WinWait('GWTalk', '', 20)
If Not $hWin Then
	MsgBox(16, 'Error', 'Нет окна')
	Exit
EndIf
;кликаем по кнопкам:
For $i = 1 To 5
	If _ActivateWin($hWin) Then
		ControlClick($hWin, '', $sClear)
		Sleep(100)
	Else
		MsgBox(16, 'Error', 'Error')
		Exit
	EndIf
	;создаем произвольный номер
	$sNum_Random = ''
	For $j = 1 To 10
		$sNum_Random &= Random(0, 9, 1)
	Next
	$aNum_Random = StringSplit($sNum_Random, '')
	If Not Mod($i, 3) Then $sNum_Random &= '#'
	If Not Mod($i, 4) Then $sNum_Random &= '*'
	MsgBox(64, $i & ' (5)', 'Будем набирать: ' & $sNum_Random)
	For $j = 1 To $aNum_Random[0]
		If _ActivateWin($hWin) Then
			ControlClick($hWin, '', $sButton & $aButtonNum[Number($aNum_Random[$j])])
		Else
			MsgBox(16, 'Error', 'Error')
			Exit
		EndIf
		Sleep(100)
	Next
	If Not Mod($i, 3) Then ControlClick($hWin, '', $sR)
	If Not Mod($i, 4) Then ControlClick($hWin, '', $sZ)
	MsgBox(64, $i & ' (5)', 'Должны набрать:' & @TAB & $sNum_Random & @LF & 'Набрали номер:' & _
			@TAB & ControlGetText($hWin, '', $sEdit))
Next
;сразу пишем номер:
For $i = 1 To 5
	If _ActivateWin($hWin) Then
		ControlClick($hWin, '', $sClear)
		Sleep(100)
	Else
		MsgBox(16, 'Error', 'Error')
		Exit
	EndIf
	;создаем произвольный номер
	$sNum_Random = ''
	For $j = 1 To 10
		$sNum_Random &= Random(0, 9, 1)
	Next
	If Not Mod($i, 3) Then $sNum_Random &= '#'
	If Not Mod($i, 4) Then $sNum_Random &= '*'
	MsgBox(64, $i & ' (5)', 'Будем набирать: ' & $sNum_Random)
	If _ActivateWin($hWin) Then
		ControlSetText($hWin, '', $sEdit, $sNum_Random)
		Sleep(100)
		MsgBox(64, $i & ' (5)', 'Должны набрать:' & @TAB & $sNum_Random & @LF & 'Набрали номер:' & _
				@TAB & ControlGetText($hWin, '', $sEdit))
	Else
		MsgBox(16, 'Error', 'Error')
		Exit
	EndIf
Next

Func _ActivateWin($h_Wnd)
	If Not WinExists($h_Wnd) Then Return False
	If Not WinActive($h_Wnd) Then WinActivate($h_Wnd)
	Return WinWaitActive($h_Wnd, '', 5) = $h_Wnd
EndFunc   ;==>_ActivateWin
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Конечно, мои знания AutoIT очень поверхностные, потому и пишу в эту конференцию. Однако Ваш скрипт проблему не решает :( (см. прилагаемый скриншот).
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 320
vitaliy4us [?]
скрипт проблему не решает
ИМХО, Вам надо поменять вот эти данные на свои:
Код:
Dim $aButtonNum[10] = ['14]', '16]', '17]', '13]', '18]', '19]', '20]', '21]', '22]', '23]']
;цифры 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
$sR = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:15]'; #
$sZ = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:24]';*
$sClear = '[CLASS:WindowsForms10.Window.8.app.0.2bb23b; INSTANCE:27]';CLEAR
;...

У меня - как на скриншоте, у Вас может быть другие.

У меня еще так работает:
Код:
#include <WinAPIEx.au3>;Yashied, http://autoit-script.ru/index.php/topic,47.0.html
;#include <Array.au3>


;координаты смотрел на разрешении 1024x768, у Вас могут быть другие
Dim $aNum[13][3] = [[12],[4, 296, 1],[66, 296, 2],[128, 296, 3], _
		[4, 326, 4],[66, 326, 5],[128, 326, 6], _
		[4, 356, 7],[66, 356, 8],[128, 356, 9], _
		[4, 386, '*'],[66, 386, 0],[128, 386, '#']]
$sEdit = '[NAME:tbDialNumber]'
$j = 0

If Not WinExists('GWTalk') Then
	Run(@ProgramFilesDir & '\SKyPRO\GWTalk\GWTalk.exe')
EndIf
$hWin = WinWait('GWTalk', '', 20)
If Not $hWin Then
	MsgBox(16, 'Error', 'Нет окна')
	Exit
EndIf
$aData = _WinAPI_EnumChildWindows($hWin)
If @error Then
	MsgBox(16, 'Error', 'Error')
	Exit
EndIf

Dim $aButton[$aData[0][0] + 1][2]
For $i = 1 To $aData[0][0]
	$aTemp = ControlGetPos($hWin, '', $aData[$i][0])
	If Not @error Then
		If $aTemp[2] == 60 And $aTemp[3] == 28 Then
			$j += 1
			For $q = 1 To $aNum[0][0]
				If $aTemp[0] == $aNum[$q][0] And $aTemp[1] == $aNum[$q][1] Then
					$aButton[$j][0] = $aNum[$q][2]
					ExitLoop
				EndIf
			Next
			$aButton[$j][1] = $aData[$i][0]
		ElseIf $aTemp[2] == 184 And $aTemp[3] == 21 Then
			$j += 1
			$aButton[$j][0] = 'Clear'
			$aButton[$j][1] = $aData[$i][0]
		EndIf
	EndIf
Next
If $j <> 13 Then
	MsgBox(16, 'Error', 'Error')
	Exit
EndIf
$aData = 0
$aTemp = 0
ReDim $aButton[$j + 1][2]
$aButton[0][0] = $j
;_ArrayDisplay($aButton, 'Buttons')

For $i = 1 To 5
	For $j = 1 To $aButton[0][0]
		If $aButton[$j][0] == 'Clear' Then
			If _ActivateWin($hWin) Then
				ControlClick($hWin, '', $aButton[$j][1])
				Sleep(100)
				ConsoleWrite(ControlGetText($hWin, '', $sEdit) & @LF)
				ExitLoop
			Else
				MsgBox(16, 'Error', 'Error')
				Exit
			EndIf
		EndIf
	Next
	$sNum_Random = ''
	For $j = 1 To 10
		$sNum_Random &= Random(0, 9, 1)
	Next
	If Not Mod($i, 3) Then $sNum_Random &= '#'
	If Not Mod($i, 4) Then $sNum_Random &= '*'
	MsgBox(64, $i & ' (5)', 'Будем набирать: ' & $sNum_Random)
	$aNum_Random = StringSplit($sNum_Random, '')
	For $j = 1 To $aNum_Random[0]
		For $q = 1 To $aButton[0][0]
			If $aNum_Random[$j] == $aButton[$q][0] Then
				If _ActivateWin($hWin) Then
					ControlClick($hWin, '', $aButton[$q][1])
					Sleep(100)
					ConsoleWrite(ControlGetText($hWin, '', $sEdit) & @LF)
					ExitLoop
				Else
					MsgBox(16, 'Error', 'Error')
					Exit
				EndIf
			EndIf
		Next
	Next
	MsgBox(64, $i & ' (5)', 'Должны набрать:' & @TAB & $sNum_Random & @LF & 'Набрали номер:' & _
			@TAB & ControlGetText($hWin, '', $sEdit))
Next

Func _ActivateWin($h_Wnd)
	If Not WinExists($h_Wnd) Then Return False
	If Not WinActive($h_Wnd) Then WinActivate($h_Wnd)
	Return WinWaitActive($h_Wnd, '', 5) = $h_Wnd
EndFunc   ;==>_ActivateWin
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
В том то и дело, что бывают такие, а бывают другие. Они переназначаются. Если у Вас установлен GWTalk, то можете попробовать запустить его и посмотреть ID контролов главного окна. Затем попробуйте открыть окно "Отправить сообщение" любому контакту из списка контактов. Закройте окно и снова проверьте ID контролов главного окна. Они будут другими!
 

madmasles

Модератор
Глобальный модератор
Сообщения
7 790
Репутация
2 320
vitaliy4us [?]
Если у Вас установлен GWTalk
У меня нет скайпа и GWTalk я установил только чтобы поковыряться с окном. :smile:
Если изменяются значения INSTANCE, ИМХО, добавляются какие-либо новые элементы. Можно попробовать отследить зависимость значения INSTANCE от общего кол-ва видимых элементов и применять нужные значения. Попробуйте в разных режимах окна найти эту зависимость.
Код:
#include <WinAPIEx.au3>;Yashied, http://autoit-script.ru/index.php/topic,47.0.html

If Not WinExists('GWTalk') Then
	Run(@ProgramFilesDir & '\SKyPRO\GWTalk\GWTalk.exe')
EndIf
$hWin = WinWait('GWTalk', '', 20)
If Not $hWin Then
	MsgBox(16, 'Error', 'Нет окна')
	Exit
EndIf
$aData = _WinAPI_EnumChildWindows($hWin)
If @error Then
	MsgBox(16, 'Error', '_WinAPI_EnumChildWindows')
	Exit
EndIf
MsgBox(64, 'Info', 'Кол-во элементов: ' & $aData[0][0])
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Новых элементов не обнаружено, думаю что это тот случай, как и тот, о котором говорит Yashied.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 714
Есть Instance, а есть ID. Первое, это просто порядковый номер элемента в пределах одного класса. Второе, это уникальный идентификатор элемента, который назначается самой программой. Этот идентификатор не меняется при добавлении и удалении элементов. Но беда в том, что эта программа назначает ID случайным образом.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
Метод перебора всех хэндлов и сравнения координат\размеров все равно должен работать.
 
Верх