Что нового

[Элементы GUI] Зависимость состояния одного контрола от состояния другого

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
Вопрос вроде как не сложный, но я на нем "завис")

Есть, допустим, чекбокс и элемент ввода:

Код:
#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>

Global $nCh1, $nI
GUICreate('My GUI Checkbox', 200, 200)

$nCh1 = GUICtrlCreateCheckbox('Checkbox 1', 10, 10, 120, 20)

$nI = GUICtrlCreateInput('', 10, 40, -1, 20)
GUICtrlSetState(-1, $GUI_DISABLE)
GUISetState()

HotKeySet('{Pause}', '_ff')

While 1
	$msg = GUIGetMsg()
	If $msg = $GUI_EVENT_CLOSE Then ExitLoop

	If $msg = $nCh1 Then
		ConsoleWrite('Нажат чекбокс' & @LF)
		GUICtrlSetState($nI, $GUI_ENABLE)
	EndIf
WEnd

Func _ff()
	GUICtrlSetState($nCh1, $GUI_CHECKED)
EndFunc   ;==>_ff


Необходимо, чтобы при установке в чекбокс галки инпут разблокировался.
В простом случае ловим событие через GUIGetMsg(), добавляем тут же GUICtrlSetState()

А вот если сам чекбокс устанавливается через GUICtrlSetState, и таких функций, как _ff() в примере, не одна, а несколько десятков...

В общем, нужно, чтобы между чекбоксом и инпутом была зависимость, независимо, каким способом устанавливается галка.
Наверно, можно как-то через GUIRegisterMsg() и $WM_COMMAND?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Код:
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

$hForm1 = GUICreate("", 246, 87, 192, 114)
$hInput1 = GUICtrlCreateInput("", 24, 14, 121, 21)
GUICtrlSetState(-1, $GUI_DISABLE)
$hCheckbox1 = GUICtrlCreateCheckbox("Check Box 1", 152, 16, 81, 17)
$hInput2 = GUICtrlCreateInput("", 24, 40, 121, 21)
GUICtrlSetState(-1, $GUI_DISABLE)
$hCheckbox2 = GUICtrlCreateCheckbox("Check Box 2", 152, 42, 81, 17)
GUISetState(@SW_SHOW)


While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

		Case $hCheckbox1
			_ff($hInput1)
		Case $hCheckbox2
			_ff($hInput2)
	EndSwitch
WEnd

Func _ff($i_CtrlID)
	Select
		Case  BitAND(GUICtrlGetState($i_CtrlID), $GUI_ENABLE) = $GUI_ENABLE
			GUICtrlSetState($i_CtrlID, $GUI_DISABLE)
		Case  BitAND(GUICtrlGetState($i_CtrlID), $GUI_DISABLE) = $GUI_DISABLE
			GUICtrlSetState($i_CtrlID, $GUI_ENABLE)
	EndSelect
EndFunc
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
WSWR
Как вариант вы можете вести наблюдение за чекбоксом в цикле (как вы это и делаете), а функцию GUICtrlSetState заменить на свою, к примеру:

Код:
Func _CheckBox_SetState( $iState )
	GUICtrlSetState( $nCh1, $iState )
	; << Помечаем состояние в переменных
EndFunc


WSWR [?]
Наверно, можно как-то через GUIRegisterMsg() и $WM_COMMAND?
WM_NOTIFY если быть точным, только я что то не смог найти информации о нужной структуре с которой смог бы получить нужную вам информацию:

Код:
#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
#Include <APIConstants.au3>
#include <WinAPI.au3>

Global $nCh1, $nI
GUICreate('My GUI Checkbox', 200, 200)

$nCh1 = GUICtrlCreateCheckbox('Checkbox 1', 10, 10, 120, 20)

$nI = GUICtrlCreateInput('', 10, 40, -1, 20)
GUICtrlSetState(-1, $GUI_DISABLE)

HotKeySet('{F6}', '_cbc')
HotKeySet('{F7}', '_cbu')
GUIRegisterMsg( $WM_NOTIFY, "_WM_NOTIFY" )
GUISetState()

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
WEnd

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam) ; NMHDR?
    Local $hWndFrom = HWnd( DllStructGetData($tNMHDR, "hWndFrom") )
    Local $iCode = DllStructGetData($tNMHDR, "Code")
	; ---
	If $hWndFrom = GUICtrlGetHandle( $nCh1 ) Then
		ConsoleWrite( "checkbox_notify_" & $iCode & @LF )
	EndIf
	; ---
	Return $GUI_RUNDEFMSG
EndFunc

Func _cbc()
	GUICtrlSetState( $nCh1, $GUI_CHECKED )
EndFunc

Func _cbu()
	GUICtrlSetState( $nCh1, $GUI_UNCHECKED )
EndFunc


Присоединяюсь к вопросу.
 

erlik

Продвинутый
Сообщения
317
Репутация
84
и таких функций, как _ff() в примере, не одна, а несколько десятков
Никогда не понимал наличие в коде десятка однотипных функций - всегда можно сделать массив нужного формата и затем прогонять его в цикле в одной единственной функции.

Если приводить простой пример зависимости, то я всегда так делал
Код:
GUICtrlSetState($iInput, _IIf(GUICtrlRead(@GUI_CtrlId)=$GUI_CHECKED,$GUI_ENABLE,$GUI_DISABLE))
С тернарным оператором еще короче будет.
Чекбоксам соответственно ставятся каллбеки через GUICtrlSetOnEvent . В режиме MessageLoop можно в основном цикле проверять массив идентификаторов чекбоксов и далее чего-то делать в зависимости от их состояния.
 
Автор
W

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
Garrett
erlik

Про однотипные функции -
если конкретно, есть элемент Edit, пользователь программы вводит какое-то значение, и через $WM_COMMAND с помощью GUICtrlSetState() устанавливается галка в какой-то чекбокс, и разблокируюся те Input, которые связаны именно с этим чекбоксом.
Т.е. пользователь может и сам ставить\снимаеть галки, и также они автоматически устанавливаюся в зависимости от введенного в основной Edit значения.
Вариантов ввода, чекбоксов и Input много. Конечно, я могу описать все возможные через кучу GUICtrlSetState, но думаю, что есть вариант проще - каким-то способом установить связь между элементами и включать и выключать их группами.

firex
Вот с WM_NOTIFY уже ближе.
Я почему писал про $WM_COMMAND - если заменить GUICtrlSetState() на ControlCommand(), то реакция есть.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
WSWR [?]
если заменить GUICtrlSetState() на ControlCommand()
Код:
Func WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
  Switch BitAND($wParam, 0x0000FFFF)
    Case $nCh1
      Switch _SendMessage(GUICtrlGetHandle($nCh1), $BM_GETCHECK)
        Case $BST_CHECKED
          ConsoleWrite("Checked" & @LF)
        Case $BST_UNCHECKED
          ConsoleWrite("Unchecked" & @LF)
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc


Также см. обработку $BN_CLICKED в WM_COMMAND в примере к функции
Код:
_GUICtrlButton_Create()
 
Автор
W

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
InnI
А все-таки лучше бы GUICtrlSetState()
Но за пример спасибо, где-нибудь пригодиться)
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
WSWR
Для группы однотипных элементов примерно такой алгоритм с использованием массива и без цикла обработки. Клик на чекбоксе провоцирует событие, и не нужно там $WM_COMMAND. Если чекбоксы создавать последовательно, то ID тоже последовательно и его можно определить вычитанием первого из текущего. Если номер чекбокса получен и ID известно, остальное дело техники.
 
Автор
W

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
AZJIO
Как бы не совсем то
Мне требовалось отследить, что поставлена галка с помощью GUICtrlSetState(), а не нажатием мыши. Решение уже есть, но длиннее, чем мне хотелось бы.

Ну, а указание диапазона элементов тоже есть, раз 30)
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
WSWR
Ещё раз перечитал и пересмотрел примеры, не понял о чём ты говоришь. Если ты сам в коде пишешь установку галки с помощью GUICtrlSetState, то зачем отслеживать то, что ты сам сделал? Поставь триггер в 1 при этом вот и вся отслежка.
 
Верх