Page 1 of 1

#PB_EventType_Change fires twice on BindEvent?

Posted: Sat Dec 24, 2016 5:20 pm
by Julian
Does anyone know why "CHANGE CALLBACK" and "CHANGE GADGET CALLBACK" fire twice when changing items but "Change EVENT" only fires once?

Thanks in advance.

Code: Select all

Procedure Changed()
  Debug "CHANGE CALLBACK"
EndProcedure

Procedure Changed_Gadget()
  Debug "CHANGE GADGET CALLBACK"
EndProcedure

OpenWindow(0,0,0,400,300,"void",$CC0001)
CreateGadgetList(WindowID(0))
ListIconGadget(101,0,0,400,300,"Name",300)

For i=1 To 50
  AddGadgetItem(101,-1,"List-View Item #" + Str(i))
Next

BindEvent(#PB_Event_Gadget, @Changed(), 0, 101, #PB_EventType_Change)
BindGadgetEvent(101, @Changed_Gadget(), #PB_EventType_Change) ;also testing this to make sure its not just a BindEvent problem

Repeat
   EventID = WaitWindowEvent()
   
   If EventID = #PB_Event_Gadget
      Select EventType()
         Case #PB_EventType_LeftClick
         Debug "LeftClick"
         Debug "Item ID = " + Str(GetGadgetState(EventGadget()))
         
         Case #PB_EventType_RightClick
         Debug "LeftClick"
         Debug "Item ID = " + Str(GetGadgetState(EventGadget()))
         
         Case #PB_EventType_LeftDoubleClick
         Debug "LeftClick"
         Debug "Item ID = " + Str(GetGadgetState(EventGadget()))
       Case #PB_EventType_Change
         Debug "Change EVENT"
         Debug "Item ID = " + Str(GetGadgetState(EventGadget()))
      EndSelect
   EndIf
Until EventID = #WM_CLOSE

Re: #PB_EventType_Change fires twice on BindEvent?

Posted: Sun Dec 25, 2016 6:07 am
by TI-994A
Julian wrote:Does anyone know why "CHANGE CALLBACK" and "CHANGE GADGET CALLBACK" fire twice when changing items but "Change EVENT" only fires once?
Notice that the callbacks fire twice only on subsequent calls but not on the first one. The reason for this is that it is being triggered for the select and deselect events in the list view. The same would not occur for a string gadget, for example.

PureBasic's event loop seems to have distilled these two list view events into one.

Re: #PB_EventType_Change fires twice on BindEvent?

Posted: Sun Dec 25, 2016 1:40 pm
by Axolotl
I thought you can get the old selection and in the second event the new selection. But I am wrong.
(On windows you can see the different behavior in your modified code below)
Click on different areas inside the Listview and you will see the different reaction in the debug window.

This is not the complete picture, there a tons of messages somewhere in the queues. :-)
I use https://msdn.microsoft.com a lot for gathering information about windows messaging, because I am on Windows only....

Code: Select all

Procedure Changed()
  Debug "CHANGE CALLBACK "+GetGadgetState(EventGadget())
EndProcedure

Procedure Changed_Gadget()
  Debug "CHANGE GADGET CALLBACK "+GetGadgetState(EventGadget())
EndProcedure

Define s_hOldWndProc       ;' store the old window procedure

Procedure WindowSubclassProc(hWnd, uMsg, wParam, lParam)
  Shared s_hOldWndProc

  Select uMsg
    Case #WM_NOTIFY                ;:Debug #PB_Compiler_Procedure+" WM_NOTIFY "
      *nmitem.NMITEMACTIVATE = lParam ;' set
      *nmlv.NMLISTVIEW       = lParam ;' set

      If *nmitem\hdr\idFrom = 101 
        Select *nmitem\hdr\code ;' NMHDR is always the first member
          Case #NM_CLICK
            Debug  #PB_Compiler_Procedure+" WM_NOTITY - NM_CLICK -- "+*nmitem\iItem

          Case #LVN_ITEMCHANGING
            Debug  #PB_Compiler_Procedure+" WM_NOTITY - LVN_ITEMCHANGING -- "+*nmlv\iItem

          Case #LVN_ITEMCHANGED
            Debug  #PB_Compiler_Procedure+" WM_NOTITY - LVN_ITEMCHANGED -- "+*nmlv\iItem
          
        EndSelect
      EndIf

    Case #WM_DESTROY                   ;:Debug #PB_Compiler_Procedure+"  #WM_DESTROY "
      SetWindowLongPtr_(WindowID(0), #GWL_WNDPROC, s_hOldWndProc) ;' should be called in here 

  EndSelect
  ProcedureReturn CallWindowProc_(s_hOldWndProc, hWnd, uMsg, wParam, lParam)
EndProcedure

OpenWindow(0,0,0,400,300,"void",$CC0001)
;CreateGadgetList(WindowID(0))                      ;' *** deprecated procedure 
ListIconGadget(101,0,0,400,300,"Name",300)

For i=1 To 50
  AddGadgetItem(101,-1,"List-View Item #" + Str(i))
Next

BindEvent(#PB_Event_Gadget, @Changed(), 0, 101, #PB_EventType_Change)
BindGadgetEvent(101, @Changed_Gadget(), #PB_EventType_Change) ;also testing this to make sure its not just a BindEvent problem

    s_hOldWndProc = SetWindowLongPtr_(WindowID(0), #GWL_WNDPROC, @WindowSubclassProc()) ;' receive most windows messages 

Repeat
   EventID = WaitWindowEvent()
   
   If EventID = #PB_Event_Gadget
      Select EventType()
         Case #PB_EventType_LeftClick
         Debug "LeftClick - ItemID=" + Str(GetGadgetState(EventGadget()))         :Debug ""
         Case #PB_EventType_RightClick
         Debug "LeftClick - ItemID=" + Str(GetGadgetState(EventGadget()))         :Debug ""
         Case #PB_EventType_LeftDoubleClick
         Debug "LeftClick - ItemID=" + Str(GetGadgetState(EventGadget()))         :Debug ""
       Case #PB_EventType_Change
         Debug "Change EVENT - ItemID=" + Str(GetGadgetState(EventGadget()))
      EndSelect
   EndIf
Until EventID = #WM_CLOSE Or EventID = #PB_Event_CloseWindow ;' not documented that WM_CLOSE is received by this loop... 
Take care and Merry Christmas to all.
Andreas

Re: #PB_EventType_Change fires twice on BindEvent?

Posted: Mon Dec 26, 2016 4:14 pm
by Julian
Ah yes, I had a feeling it was a de-select and re-select event but it seemed a bit odd that one method raised the one event and the other method raised two events.

I'm wondering if BindEvent just picks up the "real" events and WindowEvent/WaitWindowEvent is more of a "pseudo" event after some state management checks.

I'll put some state management in there to get around the double trigger.

Thanks and Happy Christmas/New Year.