Что нового

[Элементы GUI] Как предотвратить выделение первого пункта в группе у ListView?

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Вот не могу понять, почему первый пункт в группе ListView сам произвольно выделяется при нажатии на группу?

Пример:
Код:
#include <GUIConstantsEx.au3>
#include <GUIListView.au3>

$hGUI = GUICreate("Test Script", 300, 200)

$iLV = GUICtrlCreateListView('Column', 20, 20, 260, 160)
$iLV_Item = GUICtrlCreateListViewItem('Item 1', $iLV)

_GUICtrlListView_EnableGroupView($iLV)
_GUICtrlListView_InsertGroup($iLV, 0, 1, 'Group 1')
_GUICtrlListView_SetItemGroupID($iLV, 0, 1)
_GUICtrlListView_SetGroupInfo($iLV, 1, 'Group 1', 1, $LVGS_COLLAPSIBLE)

GUISetState(@SW_SHOW, $hGUI)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd


Есть подозрение что это поведение Windows (7), и если мне не изменяет память, то в Win XP такого не было.

Но самое главное это конечно как от этого “эффекта” избавиться?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR сказал(а):
Вот не могу понять, почему первый пункт в группе ListView сам произвольно выделяется при нажатии на группу?

При нажатии на группу выделяются все элементы в группе (Windows 7). Просто у тебе стоит $LVS_SINGLESEL по умолчанию.

CreatoR сказал(а):
Но самое главное это конечно как от этого “эффекта” избавиться?

Код:
#include <APIConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUIListView.au3>
#include <WinAPIEx.au3>

Global Const $LVHT_EX_GROUP_BACKGROUND = 0x80000000
Global Const $LVHT_EX_GROUP_COLLAPSE = 0x40000000
Global Const $LVHT_EX_GROUP_FOOTER = 0x20000000
Global Const $LVHT_EX_GROUP_HEADER = 0x10000000
Global Const $LVHT_EX_GROUP_STATEICON = 0x01000000
Global Const $LVHT_EX_GROUP_SUBSETLINK = 0x02000000
Global Const $LVHT_EX_GROUP = BitOR($LVHT_EX_GROUP_BACKGROUND, $LVHT_EX_GROUP_COLLAPSE, $LVHT_EX_GROUP_FOOTER, $LVHT_EX_GROUP_HEADER, $LVHT_EX_GROUP_STATEICON, $LVHT_EX_GROUP_SUBSETLINK)

$hGUI = GUICreate("Test Script", 300, 200)

$iLV = GUICtrlCreateListView('Column', 20, 20, 260, 160)
$iLV_Item = GUICtrlCreateListViewItem('Item 1', $iLV)

_GUICtrlListView_EnableGroupView($iLV)
_GUICtrlListView_InsertGroup($iLV, 0, 1, 'Group 1')
_GUICtrlListView_SetItemGroupID($iLV, 0, 1)
_GUICtrlListView_SetGroupInfo($iLV, 1, 'Group 1', 1, $LVGS_COLLAPSIBLE)

$hDll = DllCallbackRegister('_LVSubclassProc', 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
_WinAPI_SetWindowSubclass(GUICtrlGetHandle($iLV), DllCallbackGetPtr($hDll), 1000, 0)

GUISetState(@SW_SHOW, $hGUI)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			ExitLoop
	EndSwitch
WEnd

_WinAPI_RemoveWindowSubclass(GUICtrlGetHandle($iLV), DllCallbackGetPtr($hDll), 1000)
DllCallbackFree($hDll)

Func _LVSubclassProc($hWnd, $iMsg, $wParam, $lParam, $ID, $pData)
	Switch $iMsg
		Case $WM_LBUTTONDOWN, $WM_LBUTTONUP, $WM_RBUTTONDOWN, $WM_RBUTTONUP, $WM_RBUTTONDBLCLK
			$tLVHTI = DllStructCreate('long X;long Y;uint Flags;int Item;int SubItem;int Group')
			$pLVHTI = DllStructGetPtr($tLVHTI)
			DllStructSetData($tLVHTI, 'X', _WinAPI_LoWord($lParam))
			DllStructSetData($tLVHTI, 'Y', _WinAPI_HiWord($lParam))
			If _SendMessage($hWnd, $LVM_HITTEST, -1, $pLVHTI) <> -1 Then
				If BitAND(DllStructGetData($tLVHTI, 'Flags'), BitOR($LVHT_EX_GROUP_HEADER, $LVHT_EX_GROUP_COLLAPSE)) = $LVHT_EX_GROUP_HEADER Then
					Return 0
				EndIf
			EndIf
	EndSwitch
	Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_SubclassProc


Но лучше сделать это через DLL.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Yashied
Спасибо, интересное решение.
Но проблема в том, что теперь сам элемент группы не фокусируется, а для меня это критично, мне нужно использовать _GUICtrlListView_GetFocusedGroup чтобы иметь возможность работать с выделенной/текущей группой.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Код:
#Include <APIConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <GUIListView.au3>
#Include <WinAPIEx.au3>

Global Const $LVHT_EX_GROUP_BACKGROUND = 0x80000000
Global Const $LVHT_EX_GROUP_COLLAPSE = 0x40000000
Global Const $LVHT_EX_GROUP_FOOTER = 0x20000000
Global Const $LVHT_EX_GROUP_HEADER = 0x10000000
Global Const $LVHT_EX_GROUP_STATEICON = 0x01000000
Global Const $LVHT_EX_GROUP_SUBSETLINK = 0x02000000
Global Const $LVHT_EX_GROUP = BitOR($LVHT_EX_GROUP_BACKGROUND, $LVHT_EX_GROUP_COLLAPSE, $LVHT_EX_GROUP_FOOTER, $LVHT_EX_GROUP_HEADER, $LVHT_EX_GROUP_STATEICON, $LVHT_EX_GROUP_SUBSETLINK)

Global $Item = -1

$hForm = GUICreate('Test Script', 300, 200)

$LV = GUICtrlCreateListView('Column', 20, 20, 260, 160)
$hLV = GUICtrlGetHandle(-1)

GUICtrlCreateListViewItem('Item 1', $LV)
GUICtrlCreateListViewItem('Item 2', $LV)

_GUICtrlListView_EnableGroupView($LV)

_GUICtrlListView_InsertGroup($LV, -1, 1, 'Group 1')
_GUICtrlListView_SetGroupInfo($LV, 1, 'Group 1', 1, $LVGS_COLLAPSIBLE)
_GUICtrlListView_SetItemGroupID($LV, 0, 1)

_GUICtrlListView_InsertGroup($LV, -1, 2, 'Group 2')
_GUICtrlListView_SetGroupInfo($LV, 2, 'Group 2', 1, $LVGS_COLLAPSIBLE)
_GUICtrlListView_SetItemGroupID($LV, 1, 2)

$hDll = DllCallbackRegister('_LVSubclassProc', 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
$pDll = DllCallbackGetPtr($hDll)

_WinAPI_SetWindowSubclass($hLV, $pDll, 1000, 0)

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

_WinAPI_RemoveWindowSubclass($hLV, $pDll, 1000)

DllCallbackFree($hDll)

Func _LVSubclassProc($hWnd, $iMsg, $wParam, $lParam, $ID, $pData)
    Switch $iMsg
        Case $WM_LBUTTONDOWN, $WM_LBUTTONUP, $WM_RBUTTONDOWN, $WM_RBUTTONUP, $WM_RBUTTONDBLCLK
            Local $tLVHTI = DllStructCreate('long X;long Y;uint Flags;int Item;int SubItem;int Group')
            Local $pLVHTI = DllStructGetPtr($tLVHTI)
            DllStructSetData($tLVHTI, 'X', _WinAPI_LoWord($lParam))
            DllStructSetData($tLVHTI, 'Y', _WinAPI_HiWord($lParam))
            If _SendMessage($hWnd, $LVM_HITTEST, -1, $pLVHTI) <> -1 Then
                If BitAND(DllStructGetData($tLVHTI, 'Flags'), BitOR($LVHT_EX_GROUP_HEADER, $LVHT_EX_GROUP_COLLAPSE)) = $LVHT_EX_GROUP_HEADER Then
					Local $tLVG = DllStructCreate('uint Size;uint Mask;ptr Header;int HeaderLength;ptr Footer;int FooterLength;int GroupId;uint StateMask;uint State;uint Align')
					Local $pLVG = DllStructGetPtr($tLVG)
					DllStructSetData($tLVG, 'Size', DllStructGetSize($tLVG))
					DllStructSetData($tLVG, 'Mask', $LVGF_STATE)
					DllStructSetData($tLVG, 'StateMask', $LVGS_FOCUSED)
					DllStructSetData($tLVG, 'State', $LVGS_FOCUSED)
					_SendMessage($hWnd, $LVM_SETGROUPINFO, DllStructGetData($tLVHTI, 'Item'), $pLVG)
					Switch $iMsg
						Case $WM_LBUTTONDOWN, $WM_RBUTTONDOWN
							If $Item <> -1 Then
								_GUICtrlListView_SetItemState($hWnd, $Item, 0, BitOR($LVIS_FOCUSED, $LVIS_SELECTED))
							EndIf
						Case Else

					EndSwitch
                    Return 0
                EndIf
            EndIf
    EndSwitch
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_SubclassProc

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	Local $hTarget = DllStructGetData($tNMHDR, 'hWndFrom')
	Local $ID = DllStructGetData($tNMHDR, 'Code')
	Static $Flag = False
	Switch $hWnd
		Case 0

		Case $hForm
			Switch $hTarget
				Case $hLV
					Switch $ID
						Case $LVN_BEGINDRAG
							Return 0
						Case $LVN_ITEMACTIVATE
							Return 0
						Case $LVN_ITEMCHANGED
							Local $tNMIA = DllStructCreate($tagNMITEMACTIVATE, $lParam)
							If (BitAND(DllStructGetData($tNMIA, 'Changed'), $LVIF_STATE)) And (BitXOR(DllStructGetData($tNMIA, 'NewState'), DllStructGetData($tNMIA, 'OldState'))) Then
								If BitAND(DllStructGetData($tNMIA, 'NewState'), $LVIS_SELECTED) Then
									$Item = DllStructGetData($tNMIA, 'Index')
									$Flag = 0
								Else
									If BitAND(DllStructGetData($tNMIA, 'OldState'), $LVIS_FOCUSED) Then
										$Flag = 1
									Else
										If Not $Flag Then
;~											$Item = -1
										EndIf
										$Flag = 0
									EndIf
								EndIf
							EndIf
						Case $NM_CLICK, $NM_DBLCLK, $NM_RCLICK, $NM_RDBLCLK
							Return 0
					EndSwitch
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Yashied
Спасибо, вопрос решён.

Правда странно что для решения, казалось бы столь простой задачи, нужно использовать Subclass.
 
Верх