Что нового

ListView Double Click

vovsla

Осваивающий
Сообщения
607
Репутация
36
На данный момент реализована обработка Double Click реализована через
Код:
GUIRegisterMsg($WM_NOTIFY, "ListView1Click")

как здесь и рекомендовалось ранее.
Но при реализации таким способом при даблклике программа сначала обрабатывает то что повешано на один клик, а потом то, что повешано на двойной. Как можно сделать чтобы при двойном клике программа обрабатывала только то, что висит на двойном клике?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,726
В теле обработчика возвращать 0 на соответствующее сообщение - NM_CLICK.
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Но мне нужно обрабатывать 2 события, по одинарному и по даблклику, нужно их просто как-то разделить.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,487
Vovsla [?]
мне нужно обрабатывать 2 события, по одинарному и по даблклику
Можно сделать такой трюк:

Код:
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>

Global $iDblClck_Speed = RegRead('HKEY_CURRENT_USER\Control Panel\Mouse', 'DoubleClickSpeed')
Global $bDblClck_Event = False

GUICreate('Double Click VS Click Demo', 400, 300)

$iListView = GUICtrlCreateListView('List Column', 10, 20, 380, 250)

For $i = 1 To 10
	GUICtrlCreateListViewItem('Item ' & $i, $iListView)
Next

$iClick_Dummy = GUICtrlCreateDummy()
$iDblClick_Dummy = GUICtrlCreateDummy()

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

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
		Case $iClick_Dummy
			MsgBox(64, 'OK', 'Clicked: ' & GUICtrlRead(GUICtrlRead($iListView)))
		Case $iDblClick_Dummy
			MsgBox(64, 'OK', 'Double Clicked: ' & GUICtrlRead(GUICtrlRead($iListView)))
	EndSwitch
WEnd

Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
	Local $stNMHDR, $iCode
	
	$stNMHDR = DllStructCreate($tagNMHDR, $lParam)
	If @error Then Return 0
	
	$iCode = DllStructGetData($stNMHDR, 'Code')
	
	Switch $wParam
		Case $iListView
			Switch $iCode
				Case $NM_CLICK
					AdlibRegister('_Click_Proc', $iDblClck_Speed + 10)
				Case $NM_DBLCLK
					$bDblClck_Event = True
					GUICtrlSendToDummy($iDblClick_Dummy)
			EndSwitch
	EndSwitch
	
	Return $GUI_RUNDEFMSG
EndFunc

Func _Click_Proc()
	AdlibUnRegister('_Click_Proc')
	
	If Not $bDblClck_Event Then
		GUICtrlSendToDummy($iClick_Dummy)
	EndIf
	
	$bDblClck_Event = False
EndFunc


Правда в этом случае будет задержка в одиночном нажатии.
Можно конечно не читать задержку с реестра, и установить её, допустим, в 100 мс, таким образом задать в своём приложении собственную задержку для двойного нажатия.
 

InnI

AutoIT Гуру
Сообщения
4,986
Репутация
1,461
Вариант
Код:
#include <GUIConstantsEx.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>

Global $DClkTime = RegRead('HKEY_CURRENT_USER\Control Panel\Mouse', 'DoubleClickSpeed')
Global $DClk = False, $Clk = False

GUICreate('Double Click VS Click Demo', 400, 300)
$iListView = GUICtrlCreateListView('List Column', 10, 20, 380, 250)
For $i = 1 To 10
  GUICtrlCreateListViewItem('Item ' & $i, $iListView)
Next
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState()

While 1
  Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
      Exit
  EndSwitch
  If $Clk Then CheckDblClick()
WEnd

Func CheckDblClick()
  $DClk = False
  Local $Start = TimerInit()
  Do
    If TimerDiff($Start) >= $DClkTime Then ExitLoop
  Until $DClk
  If $DClk Then
    ConsoleWrite('Double Clicked: ' & GUICtrlRead(GUICtrlRead($iListView)) & @LF)
  Else
    ConsoleWrite('Clicked: ' & GUICtrlRead(GUICtrlRead($iListView)) & @LF)
  EndIf
  $Clk = False
EndFunc

Func WM_NOTIFY($hWnd, $MsgID, $wParam, $lParam)
  Local $stNMHDR, $iCode
  $stNMHDR = DllStructCreate($tagNMHDR, $lParam)
  If @error Then Return 0
  $iCode = DllStructGetData($stNMHDR, 'Code')
  Switch $wParam
    Case $iListView
      Switch $iCode
        Case $NM_CLICK
          $Clk = True
        Case $NM_DBLCLK
          $DClk = True
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc
 

Yashied

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

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,487
Yashied [?]
InnI предложил хороший вариант
Который имеет ту же задержку что я описал выше.
Тем более этот пример останавливает выполнение главного цикла, в моём примере такой остановки нет.
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Скорее всего автор неправильно организовал логику программы.
По одинарному клику производится выборка из базы данных, с разрастанием базы действие по одинарному клику стало занимать много времени и двойной клик стал работать со сбоями, а на медленных ПК программа почти не воспринимает даблклик.

В варианте от CreatoR даже при выставлении
Код:
AdlibRegister('_Click_Proc', 100)
если после нажатия "ОК" быстро сделать даблклик, то периодически программа воспринимает одинарный и даблклик, после этого программа однократно не реагирует на одинарный клик по любому пункту. В варианте от InnI такого нет.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,487
Vovsla [?]
По одинарному клику производится выборка из базы данных, с разрастанием базы действие по одинарному клику стало занимать много времени и двойной клик стал работать со сбоями, а на медленных ПК программа почти не воспринимает даблклик.
Мне кажется у тебя просто неправильная обработка.

если после нажатия "ОК" быстро сделать даблклик, то периодически программа воспринимает одинарный и даблклик, после этого программа однократно не реагирует на одинарный клик по любому пункту
Это исправляется добавлением $bDblClck_Event = False после Case $NM_CLICK.
 

Yashied

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

Opt('MustDeclareVars', 1)

Global $hForm, $hLV, $Dummy1, $Dummy2
Global $ID, $Item1, $Item2
Global $Exit = False

$hForm = GUICreate('MyGUI', 300, 300)
$hLV = GUICtrlGetHandle(GUICtrlCreateListView('Name', 0, 0, 300, 300, -1, 0))
For $i = 1 To 4
    _GUICtrlListView_AddItem($hLV, 'Item' & $i)
Next
_GUICtrlListView_SetItemSelected($hLV, 0, 1, 1)
$Item1 = 0
$Item2 =-1
$Dummy1 = GUICtrlCreateDummy()
$Dummy2 = GUICtrlCreateDummy()
GUISetOnEvent($GUI_EVENT_CLOSE, '_GUIEvents', $hForm)
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState()

While 1
    Switch GUIGetMsg()
        Case 0
            ContinueLoop
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Dummy1
			Opt('GUIOnEventMode', 1)
			Do
				$ID = $Item1
				_Something($ID)
			Until $ID = $Item1
			Opt('GUIOnEventMode', 0)
			If $Item1 = $Item2 Then
				ContinueCase
			EndIf
        Case $Dummy2
            MsgBox(0, '', 'Item' & ($Item2 + 1) & ' is activated.')
	EndSwitch
WEnd

Func _Something($Item)
	ConsoleWrite('Something is done with Item' & ($Item + 1))
	For $i = 1 To 10
		ConsoleWrite('.')
		If $Exit Then
			Exit
		EndIf
		Sleep(100)
	Next
	ConsoleWrite('OK' & @CR)
EndFunc   ;==>_Something

Func _GUIEvents()
	Switch @GUI_WinHandle
		Case $hForm
			Switch @GUI_CtrlId
				Case $GUI_EVENT_CLOSE
					$Exit = 1
			EndSwitch
	EndSwitch
EndFunc   ;==>_GUIEvents

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

	Local $tNMIA = DllStructCreate($tagNMITEMACTIVATE, $lParam)
	Local $hTarget = DllStructGetData($tNMIA, 'hWndFrom')
	Local $ID = DllStructGetData($tNMIA, 'Code')

	Switch $hWnd
		Case 0

		Case $hForm
			Switch $hTarget
				Case $hLV
					Switch $ID
						Case $LVN_BEGINDRAG
							Return 0
						Case $LVN_ITEMACTIVATE
							$Item2 = $Item1
							GUICtrlSendToDummy($Dummy2)
						Case $LVN_ITEMCHANGED
							If (BitAND(DllStructGetData($tNMIA, 'NewState'), $LVIS_SELECTED)) And (Not BitAND(DllStructGetData($tNMIA, 'OldState'), $LVIS_FOCUSED)) Then
								$Item1 = DllStructGetData($tNMIA, 'Index')
								$Item2 = -1
								GUICtrlSendToDummy($Dummy1)
							EndIf
						Case $NM_CLICK, $NM_DBLCLK, $NM_RCLICK, $NM_RDBLCLK
							Return 0
					EndSwitch
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Мне кажется у тебя просто неправильная обработка.
На всех элементах ListView обработка одинаковая и пока база была маленькой проблем не было.

Кусок кода отвечающий за обработку:
Код:
GUIRegisterMsg($WM_NOTIFY, "ListView1Click")

While 1
	Sleep(100)
	If $iOne_Click_Event_ListView1 Then
        $iOne_Click_Event_ListView1 = 0
        ListView1ItemClick()
    EndIf

    If $iDouble_Click_Event_ListView1 Then
        $iDouble_Click_Event_ListView1 = 0
        ListView1ItemDoubleClick()
    EndIf

	If $Click_On_Column_Head_Event_ListView1<>-1 Then
		$Click_On_Column_Head_Event_ListView1=-1
		ListView1HeadClick()
	EndIf


	If $iOne_Click_Event_ListView2 Then
        $iOne_Click_Event_ListView2 = 0
        ListView2ItemClick()
    EndIf

    If $iDouble_Click_Event_ListView2 Then
        $iDouble_Click_Event_ListView2 = 0
        ListView2ItemDoubleClick()
    EndIf

	If $Click_On_Column_Head_Event_ListView2<>-1 Then
		$Click_On_Column_Head_Event_ListView2=-1
		ListView2HeadClick()
	EndIf


	If $iOne_Click_Event_ListView3 Then
        $iOne_Click_Event_ListView3 = 0
        ListView3ItemClick()
    EndIf

    If $iDouble_Click_Event_ListView3 Then
        $iDouble_Click_Event_ListView3 = 0
        ListView3ItemDoubleClick()
    EndIf

	If $Click_On_Column_Head_Event_ListView3<>-1 Then
		$Click_On_Column_Head_Event_ListView3=-1
		ListView3HeadClick()
	EndIf
WEnd


;~ -----------------------------------------------------------------------------ListViewClick----------------------------------------------------------------------------
Func ListView1Click($hWnd, $iMsg, $iwParam, $ilParam)
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView

	Local $hListView=$ListView1
	If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

	Local $hListView2=$ListView2
	If Not IsHWnd($hListView2) Then $hWndListView2 = GUICtrlGetHandle($hListView2)

	Local $hListView3=$ListView3
	If Not IsHWnd($hListView3) Then $hWndListView3 = GUICtrlGetHandle($hListView3)



    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $hWndFrom
	    Case $hWndListView
            Switch $iCode
                Case $NM_CLICK
                    $iOne_Click_Event_ListView1 = True
                Case $NM_DBLCLK
                    $iDouble_Click_Event_ListView1 = True
				Case $LVN_COLUMNCLICK
					Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
					$Click_On_Column_Head_Event_ListView1=DllStructGetData($tInfo, "SubItem")
				EndSwitch

        Case $hWndListView2
			Switch $iCode
                Case $NM_CLICK
                    $iOne_Click_Event_ListView2 = True
                Case $NM_DBLCLK
                    $iDouble_Click_Event_ListView2 = True
				Case $LVN_COLUMNCLICK
					Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
					$Click_On_Column_Head_Event_ListView2=DllStructGetData($tInfo, "SubItem")
			EndSwitch

        Case $hWndListView3
			Switch $iCode
                Case $NM_CLICK
                    $iOne_Click_Event_ListView3 = True
                Case $NM_DBLCLK
                    $iDouble_Click_Event_ListView3 = True
				Case $LVN_COLUMNCLICK
					Local $tInfo = DllStructCreate($tagNMLISTVIEW, $ilParam)
					$Click_On_Column_Head_Event_ListView3=DllStructGetData($tInfo, "SubItem")
			EndSwitch

    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,487
Vovsla [?]
Кусок кода отвечающий за обработку:
В таком случае, обработку можно было бы повесить на внешний процесс.
Также можно отображать окошко ожидания загрузки списка, не позволяя другие операции со списком.

Но как я и написал, обработка имеет недостатки.
Можно при загрузке списка включить режим OnEvent, и обрабатывать другие события параллельно (естественно для этого нужен элемент Dummy, который будет задействован обработчиком - GUICtrlSendToDummy).
Ну или в самой функции загрузки списка проверять события (If GUIGetMsg() = ...), и прерывать загрузку если оно требуется новым событием в списке.
 
Автор
V

vovsla

Осваивающий
Сообщения
607
Репутация
36
Всем большое спасибо за помощь, нашел ошибку в логике программы, иногда функция ListView2ItemClick() вызывалась 2 раза после обработки одного одинарного клика.
 
Верх