Что нового

[Элементы GUI] Обработка события при изменении чекбокса в ListView

TIgor

Новичок
Сообщения
10
Репутация
0
Подскажите пожалуйста, как сделать, чтобы при изменении чекбокса в ListView обрабатывалось какое нибудь событие?
Сначала хотел из этой http://autoit-script.ru/index.php?topic=455.msg3098#msg3098 темы прикрутить, но там просто клик мышью. Может проще как-то можно?
 

edyapd

Осваивающий
Сообщения
380
Репутация
30
На сколько я понимаю обычно при обработки какого-либо события читают чекбокс и выполняют условие, в зависимости от его установки.
Но это чисто моё мнение.
 
Автор
T

TIgor

Новичок
Сообщения
10
Репутация
0
Допустим есть ListView, мне нужно, чтобы при установке чекбокса, цвет картинки менялся на зеленый.
[box title=Код]
Код:
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
#include <GuiImageList.au3>

Opt("GuiOnEventMode", 1)
Opt('MustDeclareVars', 1)

Global $hListView, $hImage, $Main_GUI, $Blue_Context_Item, $LV_Context_Menu

$Main_GUI = GUICreate("ListView Insert Column", 400, 300)
GUISetOnEvent(-3, "ExitScript")

$hListView = GUICtrlCreateListView("", 2, 2, 394, 268, $GUI_SS_DEFAULT_LISTVIEW, $LVS_EX_FULLROWSELECT+$LVS_EX_CHECKBOXES+$LVS_EX_GRIDLINES+$WS_EX_CLIENTEDGE)

$LV_Context_Menu = GUICtrlCreateContextMenu($hListView)
$Blue_Context_Item = GUICtrlCreateMenuItem("Blue", $LV_Context_Menu)
GUICtrlSetOnEvent(-1, "ContextMenuEvents")

GUISetState()

; Load images
$hImage = _GUIImageList_Create()
_GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap(GUICtrlGetHandle($hListView), 0xFF0000, 16, 16))
_GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap(GUICtrlGetHandle($hListView), 0x00FF00, 16, 16))
_GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap(GUICtrlGetHandle($hListView), 0x0000FF, 16, 16))
_GUICtrlListView_SetImageList($hListView, $hImage, 1)

	; Insert columns
_GUICtrlListView_InsertColumn($hListView, 0, "Column 1", 100)
_GUICtrlListView_InsertColumn($hListView, 1, "Column 2", 100)
_GUICtrlListView_InsertColumn($hListView, 2, "Column 3", 100)

_GUICtrlListView_AddItem($hListView, "Raw 1 Col 1", 0)
_GUICtrlListView_AddItem($hListView, "Raw 2 Col 1", 0)
_GUICtrlListView_AddItem($hListView, "Raw 3 Col 1", 0)

_GUICtrlListView_AddSubItem($hListView, 0, "Raw 1 Col 2", 1, 1)
_GUICtrlListView_AddSubItem($hListView, 1, "Raw 2 Col 2", 1, 1)
_GUICtrlListView_AddSubItem($hListView, 2, "Raw 3 Col 2", 1, 1)

; Loop until user exits
While 1
    Sleep(10)
WEnd

Func ContextMenuEvents()
	Local $SelectedIndex = _GUICtrlListView_GetSelectedIndices($hListView, 0)

	Switch @GUI_CtrlId
		Case $Blue_Context_Item
				If @error Then Return
				If _GUICtrlListView_GetItemChecked ($hListView, $SelectedIndex) Then _GUICtrlListView_SetItemChecked($hListView, $SelectedIndex, False)
				_GUICtrlListView_SetItemImage($hListView, $SelectedIndex, 2)
	EndSwitch
EndFunc

Func ExitScript()
	GUIDelete()
	Exit
EndFunc
[/box]
 

gregaz

AutoIT Гуру
Сообщения
1 166
Репутация
299
TIgor [?]
Допустим есть ListView, мне нужно, чтобы при установке чекбокса, цвет картинки менялся на зеленый.
Можно так :
Код:
If _GUICtrlListView_GetItemChecked($hListView,$hLVItem) Then 
	  MsgBox(0,'$Check','Чекбокс был отмечен',1)
	  ; ..................... меняем цвет и т.д.
   Else
	    MsgBox(0,'$Check','Чекбокс не был отмечен',1)
	  ; .....................
   EndIf




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

$hLVItem я бы определял с помощью обычной WM_NOTIFY
 
Автор
T

TIgor

Новичок
Сообщения
10
Репутация
0
Да, если через WM_NOTIFY то получается, мне надо определить предыдущее состояние чекбокса, потом определить выделенную строку и выполнить действие если состояние чекбокса изменилось, так?
 

gregaz

AutoIT Гуру
Сообщения
1 166
Репутация
299
Еще раз повтори задачу
Если я правильно понял ее надо просто изменить условие If так :
Код:
;............
If @error Then Return
If _GUICtrlListView_GetItemChecked ($hListView, $SelectedIndex) Then
   ; _GUICtrlListView_SetItemChecked($hListView, $SelectedIndex, False)
    _GUICtrlListView_SetItemImage($hListView, $SelectedIndex, 2)
EndIf

или после упрощения :
Код:
;............
If @error Then Return
If _GUICtrlListView_GetItemChecked ($hListView, $SelectedIndex) Then   _GUICtrlListView_SetItemImage($hListView, $SelectedIndex, 2)

Цвет меняется

То ли тебе надо или изменение надо сразу при изменении Чекбокса (без клика меню ) ?
 
Автор
T

TIgor

Новичок
Сообщения
10
Репутация
0
...надо или изменение надо сразу при изменении Чекбокса (без клика меню )
Изменение надо сразу и именно при изменении чекбокса, а не просто по клику на строку или еще куда-то.

gregaz
Спасибо, что откликнулся.
 
Автор
T

TIgor

Новичок
Сообщения
10
Репутация
0
Спасибо, классная UDF, обязательно возьму на вооружение :smile:

Вот такую фигню хочу:
Код:
#include <GUIConstantsEx.au3>

Opt('MustDeclareVars', 1)

Example()

Func Example()
	Local $checkCN, $msg
	GUICreate("My GUI Checkbox") 
	$checkCN = GUICtrlCreateCheckbox("CHECKBOX 1", 10, 10, 120, 20)
	GUISetState()
	While 1
		$msg = GUIGetMsg()
		If $msg = $checkCN Then MsgBox(0,'$Check','Чекбокс был изменен')
		If $msg = $GUI_EVENT_CLOSE Then ExitLoop
	WEnd
EndFunc   ;


Только чтобы в ListView с чекбоксами.
Эх... Я правильно понимаю, что самый оптимальный вариант, менять состояние чекбокса при клике на строку, тогда как раз можно и какое нибудь событие повесить на это?
 

gregaz

AutoIT Гуру
Сообщения
1 166
Репутация
299
Может это подойдет:
Код:
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
#include <GuiImageList.au3>

$Main_GUI = GUICreate("ListView Insert Column", 400, 300)

$hListView = GUICtrlCreateListView("", 2, 2, 394, 268, $GUI_SS_DEFAULT_LISTVIEW, $LVS_EX_FULLROWSELECT+$LVS_EX_CHECKBOXES+$LVS_EX_GRIDLINES+$WS_EX_CLIENTEDGE)

; Load images
$hImage = _GUIImageList_Create()
_GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap(GUICtrlGetHandle($hListView), 0xFF0000, 16, 16))
_GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap(GUICtrlGetHandle($hListView), 0x00FF00, 16, 16))
_GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap(GUICtrlGetHandle($hListView), 0x0000FF, 16, 16))
_GUICtrlListView_SetImageList($hListView, $hImage, 1)

; Insert columns
_GUICtrlListView_InsertColumn($hListView, 0, "Column 1", 100)
_GUICtrlListView_InsertColumn($hListView, 1, "Column 2", 100)
_GUICtrlListView_InsertColumn($hListView, 2, "Column 3", 100)

_GUICtrlListView_AddItem($hListView, "Raw 1 Col 1", 0)
_GUICtrlListView_AddItem($hListView, "Raw 2 Col 1", 0)
_GUICtrlListView_AddItem($hListView, "Raw 3 Col 1", 0)

_GUICtrlListView_AddSubItem($hListView, 0, "Raw 1 Col 2", 1, 1)
_GUICtrlListView_AddSubItem($hListView, 1, "Raw 2 Col 2", 1, 1)
_GUICtrlListView_AddSubItem($hListView, 2, "Raw 3 Col 2", 1, 1)

Dim $aArray[3]

GUISetState()

While 1
   $Msg = GUIGetMsg()
   Switch $Msg
	  Case $GUI_EVENT_CLOSE
		 Exit
	  Case $GUI_EVENT_PRIMARYDOWN ; 
		 Sleep(500)
		 For $i=0 To UBound($aArray,1)-1
			$Check=_GUICtrlListView_GetItemChecked ($hListView, $i)
			If  $Check    <>   $aArray[$i] Then 
			    MsgBox(0,'$Check','Чекбокс был изменен для элемента : ' & $i ,1)
			   _GUICtrlListView_SetItemSelected($hListView, $i)
			EndIf
			$aArray[$i]=$Check
		 Next   
   EndSwitch
WEnd
 
Автор
T

TIgor

Новичок
Сообщения
10
Репутация
0
По идее для этого примера работает все отлично!
Просто у меня прога, она считывает службы Windows и их бывает за 100... думаю, постоянно весь список перечитывать не совсем рационально.
А можно запретить изменение чекбокса в ListView?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
TIgor [?]
...мне надо определить предыдущее состояние чекбокса...
TIgor, ты сам ответил на свой вопрос. Заведи переменную (массив), где будут храниться текущие состояния чекбоксов. Исходя из своего опыта работы с ListView (например 3D Axis, Font Viewer и многие другие), могу сказать, что удобнее всего все данные для ListView хранить в отдельном массиве, а в ListView отображать его... Вообщем смотри пример.

Код:
#Include <GUIConstantsEx.au3>
#Include <GUIListView.au3>
#Include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)

Global $Button, $ListView, $hListView

Dim $Data[6][2] = [[5, 0], ['Item1', 0], ['Item2', 1], ['Item3', 1], ['Item4', 0], ['Item5', 1]]

GUICreate('MyGUI', 280, 391)
$ListView = GUICtrlCreateListView('', 10, 10, 260, 344, BitOR($LVS_DEFAULT, $LVS_NOCOLUMNHEADER), $WS_EX_CLIENTEDGE)
$hListView = GUICtrlGetHandle(-1)
_GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_DOUBLEBUFFER, $LVS_EX_INFOTIP))
_GUICtrlListView_InsertColumn($hListView, 0, '', 234)
$Button = GUICtrlCreateButton('OK', 105, 361, 70, 23)

For $i = 1 To $Data[0][0]
	_GUICtrlListView_AddItem($hListView, $Data[$i][0])
	_GUICtrlListView_SetItemChecked($hListView, $i - 1, $Data[$i][1])
Next

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')

GUISetState()

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

	Local $tNMITEMACTIVATE = DllStructCreate($tagNMITEMACTIVATE, $lParam)
	Local $hWndFrom = DllStructGetData($tNMITEMACTIVATE, 'hWndFrom')
	Local $Index = DllStructGetData($tNMITEMACTIVATE, 'Index')
	Local $Code = DllStructGetData($tNMITEMACTIVATE, 'Code')

	Switch $hWndFrom
		Case $hListView
			Switch $Code
				Case $LVN_ITEMCHANGED
					If BitXOR(_GUICtrlListView_GetItemChecked($hListView, $Index), $Data[$Index + 1][1]) Then
						$Data[$Index + 1][1] = Not $Data[$Index + 1][1]
						ConsoleWrite('Item' & ($Index + 1) & ' - ' & $Data[$Index + 1][1] & @CR)
					EndIf
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
 
Автор
T

TIgor

Новичок
Сообщения
10
Репутация
0
Yashied
Да, я нечто подобное и хотел сделать. Сомневался, будет ли это корректно.

Спасибо огромное всем за помощь.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
Кстати, если не хочешь заводить массив, то можешь воспользоваться парой сообщений - $LVN_ITEMCHANGING и $LVN_ITEMCHANGED. Они идут одно за другим. При приходе первого запоминаешь состояние чекбокса (оно еще не изменилось), второе сообщение приходит уже при изменившемся чекбоксе. Тебе останется только сравнить его с запомненным ранее состоянием, и при несовпадении...

:smile:

Код:
#Include <GUIConstantsEx.au3>
#Include <GUIListView.au3>
#Include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)

Global $State, $Button, $ListView, $hListView

GUICreate('MyGUI', 280, 391)
$ListView = GUICtrlCreateListView('', 10, 10, 260, 344, BitOR($LVS_DEFAULT, $LVS_NOCOLUMNHEADER), $WS_EX_CLIENTEDGE)
$hListView = GUICtrlGetHandle(-1)
_GUICtrlListView_SetExtendedListViewStyle($hListView, BitOR($LVS_EX_CHECKBOXES, $LVS_EX_DOUBLEBUFFER, $LVS_EX_INFOTIP))
_GUICtrlListView_InsertColumn($hListView, 0, '', 234)
$Button = GUICtrlCreateButton('OK', 105, 361, 70, 23)

For $i = 1 To 5
	_GUICtrlListView_AddItem($hListView, 'Item' & $i)
Next

_GUICtrlListView_SetItemChecked($hListView, 1, 1)
_GUICtrlListView_SetItemChecked($hListView, 2, 1)
_GUICtrlListView_SetItemChecked($hListView, 4, 1)

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')

GUISetState()

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

	Local $tNMITEMACTIVATE = DllStructCreate($tagNMITEMACTIVATE, $lParam)
	Local $hWndFrom = DllStructGetData($tNMITEMACTIVATE, 'hWndFrom')
	Local $Index = DllStructGetData($tNMITEMACTIVATE, 'Index')
	Local $Code = DllStructGetData($tNMITEMACTIVATE, 'Code')

	Switch $hWndFrom
		Case $hListView
			Switch $Code
				Case $LVN_ITEMCHANGING
					$State = _GUICtrlListView_GetItemChecked($hListView, $Index)
				Case $LVN_ITEMCHANGED
					If $State <> _GUICtrlListView_GetItemChecked($hListView, $Index) Then
						ConsoleWrite('Item' & ($Index + 1) & ' - ' & (Not $State) & @CR)
					EndIf
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY


Но я все же рекомендую использовать массив, его по любому проще обрабатывать чем ListView.



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

И еще одно замечание. Если будешь в процессе выполнения скрипта, после вызова GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY'), программно изменять состояние чекбокса _GUICtrlListView_SetItemChecked(), то рекомендую завести флаг (переменную) для блокировки WM_NOTIFY, чтобы избежать ненужных срабатываний...

Код:
Global $Flag = False

...

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')

...

$Flag = 1
_GUICtrlListView_SetItemChecked(...)
$Flag = 0

...

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	If $Flag Then
		Return $GUI_RUNDEFMSG
	EndIf

...

EndFunc   ;==>WM_NOTIFY
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
Я смотрел в ListViewConstants.au3.
 

ShuNaher

Новичок
Сообщения
2
Репутация
0
Yashied
можешь воспользоваться парой сообщений - $LVN_ITEMCHANGING и $LVN_ITEMCHANGED. Они идут одно за другим. При приходе первого запоминаешь состояние чекбокса (оно еще не изменилось), второе сообщение приходит уже при изменившемся чекбоксе
Странная ситуация... Копирую Ваш пример из этого поста (ответ #13 этого топика), запускаю у себя и получаю вывод строки
Код:
ConsoleWrite('Item' & ($Index + 1) & ' - ' & (Not $State) & @CR)
только в одном случае - если кликаю по чекбоксу первой строки ListView.
Ставлю сразу после
Код:
Switch $Code
вывод значений $Index и $Code и вижу, что на чекбоксе какой-бы строки (любая из пяти) я не кликал $Index всегда равен нулю !!
Вообще любые события приходят в обработчик с $Index=0
Неужели у меня одного такая ерунда ??
Может какие-либо опции надо в AutoIt "подкрутить" ?

З.Ы. AutoIt 3.3.6.1 x86 на Windows 7 x64

Update: Удалил свою "AutoIt 3.3.6.1" и установил "комбайн AutoIt3 v3.3.6.1 от AZJIO 22.08.2011. (шестая редакция)". Ситуация точно такая же. На другом компьютере - все замечательно (Windows XP x86)
Попробовал на своем компьютере запустить скрипт "вручную принудительно" x86 и все заработало отлично.
Выходит это какой-то "баг" именно 64-битной версии (уж не знаю кто "чудит" autoit3_x64.exe или сама Windows 7).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
Это баг во всех $tagNMHDR-содержащих структурах. Будет исправлено в следующей версии AutoIt, или качайте сейчас Beta.
 
Верх