Page 1 of 1

[Solved] PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sat May 06, 2023 2:13 pm
by Axolotl
With PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work proberly.
The same code works on PureBaisc 6.00 LTS (x64) like a charm.

The Error occurs if the ListViewGadget is placed in a PanelGadget.
See the following code...
The Events "press a button" and "resize the window" are added to both ListViewGadgets.
But only the first one is displaying the items...

Code: Select all


EnableExplicit 

Enumeration EWindow 1	
#WINDOW_Main 
EndEnumeration 

Enumeration EGadget 1
#GADGET_lblInfo 
#GADGET_btnAdd 
#GADGET_lvOutput 

#GADGET_pnlMain
#GADGET_lvOutput2 
EndEnumeration 


; ---------------------------------------------------------------------------------------------------------------------

Procedure AddOutput(Message.s, State=#False) 
  Protected count, count2  

  AddGadgetItem(#GADGET_lvOutput, -1, Message) 
	count = CountGadgetItems(#GADGET_lvOutput) 
  SetGadgetItemData(#GADGET_lvOutput, count-1, State) 
  SetGadgetState(#GADGET_lvOutput, count-1) 

  AddGadgetItem(#GADGET_lvOutput2, -1, Message) 
	count2 = CountGadgetItems(#GADGET_lvOutput2) 
  SetGadgetItemData(#GADGET_lvOutput2, count2-1, State) 
  SetGadgetState(#GADGET_lvOutput2, count2-1) 
  
  SetGadgetText(#GADGET_lblInfo, "Counts = " + count + " | " + count2) 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure OnCallback(hWnd, uMsg, wParam, lParam) 
	Protected *drawItem.DRAWITEMSTRUCT 
	Protected text.s, field.s, state  
	Protected textColor, brush  ; for background 

	Select uMsg 
		Case #WM_DRAWITEM
			*drawItem = lParam 

			If wParam = #GADGET_lvOutput Or wParam = #GADGET_lvOutput2 ; exact this listview 
				If *drawItem\itemID <> -1 
					text  = GetGadgetItemText(wParam, *drawItem\itemID) 
					state = GetGadgetItemData(wParam, *drawItem\itemID) 

					; make it look special 

					If *drawItem\itemState & #ODS_SELECTED                                         ;:Debug "DRAWITEM SELECTED " + Str(*drawItem\itemID ) 
            brush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
            textColor = GetSysColor_(#COLOR_HIGHLIGHTTEXT) 
          Else                                                                        ;:Debug "DRAWITEM  ELSE    " + Str(*drawItem\itemID ) 
            brush = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW)) 
            textColor = GetSysColor_(#COLOR_WINDOWTEXT) 
          EndIf

          FillRect_(*drawItem\hdc, *drawItem\rcItem, brush) 
          DeleteObject_(brush)  ; no longer needed 
          SetTextColor_(*drawItem\hdc, textColor) 

					SetBkMode_(*drawItem\hdc, #TRANSPARENT)  

					; first column [30] is check mark for ... 
	 				If state 
		 				field = "✔" 
	 				Else 
		 				field = "✘" 
		 			EndIf 
	 				TextOut_(*drawItem\hdc, *drawItem\rcItem\left+2, *drawItem\rcItem\top, @field, Len(field)) 

					; second column [all] is entire item text 
					field = text 
					TextOut_(*drawItem\hdc, *drawItem\rcItem\left+32, *drawItem\rcItem\top, @field, Len(field)) 

					ProcedureReturn 0 
				EndIf 
			EndIf ; *drawitem\CtlType 
	EndSelect
 
	ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure OnSizeEvent() 
  AddOutput("Size Window Event ") 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure CreateMainWindow(WndW = 800, WndH = 600)  
  If OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "Tester", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget) 
    ButtonGadget(#GADGET_btnAdd, 4, 4, 96, 24, "Add New Line") 
    TextGadget(#GADGET_lblInfo, 320, 4, WndW-124, 20, "Counts = 0 | 0 ") 
    ListViewGadget(#GADGET_lvOutput, 4, 32, 600, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 

		PanelGadget(#GADGET_pnlMain, 0, 240, 600, 220) 
			AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #1") 
  		  ListViewGadget(#GADGET_lvOutput2, 0, 0, 560, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 
				AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #2") 
	    	TextGadget(#PB_Any, 0, 0, 240, 20, "Empty Tab Sheet ") 
		CloseGadgetList() 

    BindEvent(#PB_Event_SizeWindow, @OnSizeEvent()) 
    SetWindowCallback(@OnCallback(), #WINDOW_Main) 
  EndIf 
  ProcedureReturn IsWindow(#WINDOW_Main) 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure main() 
  Protected state 

  If CreateMainWindow() 
    Repeat  ; main loop 
      Select WaitWindowEvent(250)  
        Case #PB_Event_None 

        Case #PB_Event_CloseWindow 
          If EventWindow() = #WINDOW_Main : Break : EndIf  ; close button on main window --> close application 

        Case #PB_Event_MoveWindow 
          AddOutput("Move Window") 

        Case #PB_Event_SizeWindow 
          AddOutput("Size Window") 

        Case #PB_Event_MinimizeWindow, #PB_Event_MaximizeWindow 
            AddOutput("Minimize or Maximize Window") 

        Case #PB_Event_Gadget 
          Select EventGadget()
            Case #GADGET_btnAdd 
	            AddOutput("Added a new Line to lvOutput ... ", 1) 
          EndSelect 
      EndSelect
    ForEver ; main loop 
  EndIf ; OpenWindow 
EndProcedure 

End main() 

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sat May 06, 2023 2:24 pm
by Axolotl
The problem exists not only with ListviewGadget(), but also with ComboboxGadget().
Testet on ListIconGadget() as well.
Seems to be a general problem.

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work proberly.

Posted: Sat May 06, 2023 6:14 pm
by Fred
Probably the same error than this: viewtopic.php?t=81568

Code: Select all

EnableExplicit 

Enumeration EWindow 1	
#WINDOW_Main 
EndEnumeration 

Enumeration EGadget 1
#GADGET_lblInfo 
#GADGET_btnAdd 
#GADGET_lvOutput 

#GADGET_pnlMain
#GADGET_lvOutput2 
EndEnumeration 


Global OldListViewCallback

; ---------------------------------------------------------------------------------------------------------------------

Procedure AddOutput(Message.s, State=#False) 
  Protected count, count2  

  AddGadgetItem(#GADGET_lvOutput, -1, Message) 
	count = CountGadgetItems(#GADGET_lvOutput) 
  SetGadgetItemData(#GADGET_lvOutput, count-1, State) 
  SetGadgetState(#GADGET_lvOutput, count-1) 

  AddGadgetItem(#GADGET_lvOutput2, -1, Message) 
	count2 = CountGadgetItems(#GADGET_lvOutput2) 
  SetGadgetItemData(#GADGET_lvOutput2, count2-1, State) 
  SetGadgetState(#GADGET_lvOutput2, count2-1) 
  
  SetGadgetText(#GADGET_lblInfo, "Counts = " + count + " | " + count2) 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure OnCallback(hWnd, uMsg, wParam, lParam) 
	Protected *drawItem.DRAWITEMSTRUCT 
	Protected text.s, field.s, state  
	Protected textColor, brush  ; for background 

	Select uMsg 
		Case #WM_DRAWITEM
			*drawItem = lParam 

			If wParam = #GADGET_lvOutput Or wParam = #GADGET_lvOutput2 ; exact this listview 
				If *drawItem\itemID <> -1 
					text  = GetGadgetItemText(wParam, *drawItem\itemID) 
					state = GetGadgetItemData(wParam, *drawItem\itemID) 

					; make it look special 

					If *drawItem\itemState & #ODS_SELECTED                                         ;:Debug "DRAWITEM SELECTED " + Str(*drawItem\itemID ) 
            brush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
            textColor = GetSysColor_(#COLOR_HIGHLIGHTTEXT) 
          Else                                                                        ;:Debug "DRAWITEM  ELSE    " + Str(*drawItem\itemID ) 
            brush = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW)) 
            textColor = GetSysColor_(#COLOR_WINDOWTEXT) 
          EndIf

          FillRect_(*drawItem\hdc, *drawItem\rcItem, brush) 
          DeleteObject_(brush)  ; no longer needed 
          SetTextColor_(*drawItem\hdc, textColor) 

					SetBkMode_(*drawItem\hdc, #TRANSPARENT)  

					; first column [30] is check mark for ... 
	 				If state 
		 				field = "✔" 
	 				Else 
		 				field = "✘" 
		 			EndIf 
	 				TextOut_(*drawItem\hdc, *drawItem\rcItem\left+2, *drawItem\rcItem\top, @field, Len(field)) 

					; second column [all] is entire item text 
					field = text 
					TextOut_(*drawItem\hdc, *drawItem\rcItem\left+32, *drawItem\rcItem\top, @field, Len(field)) 

					ProcedureReturn 0 
				EndIf 
			EndIf ; *drawitem\CtlType 
	EndSelect
 
	ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure OnSizeEvent() 
  AddOutput("Size Window Event ") 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure CreateMainWindow(WndW = 800, WndH = 600)  
  If OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "Tester", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget) 
    ButtonGadget(#GADGET_btnAdd, 4, 4, 96, 24, "Add New Line") 
    TextGadget(#GADGET_lblInfo, 320, 4, WndW-124, 20, "Counts = 0 | 0 ") 
    ListViewGadget(#GADGET_lvOutput, 4, 32, 600, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 

		PanelGadget(#GADGET_pnlMain, 0, 240, 600, 220) 
			AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #1") 
  		  ListViewGadget(#GADGET_lvOutput2, 0, 0, 560, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 
				AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #2") 
	    	TextGadget(#PB_Any, 0, 0, 240, 20, "Empty Tab Sheet ") 
	    	CloseGadgetList() 
	    	
    ; Get the Panel Item handle
    ;
    Define Item.TC_ITEM\mask = #TCIF_PARAM;
    SendMessage_(GadgetID(#GADGET_pnlMain), #TCM_GETITEM, 0, @Item)
    Define PanelItemHandle = Item\lParam
    
    ; Attach the callback to it
    OldListViewCallback = SetWindowLongPtr_(PanelItemHandle, #GWLP_WNDPROC, @OnCallback())	    	

    BindEvent(#PB_Event_SizeWindow, @OnSizeEvent()) 
    SetWindowCallback(@OnCallback(), #WINDOW_Main) 
  EndIf 
  ProcedureReturn IsWindow(#WINDOW_Main) 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure main() 
  Protected state 

  If CreateMainWindow() 
    Repeat  ; main loop 
      Select WaitWindowEvent(250)  
        Case #PB_Event_None 

        Case #PB_Event_CloseWindow 
          If EventWindow() = #WINDOW_Main : Break : EndIf  ; close button on main window --> close application 

        Case #PB_Event_MoveWindow 
          AddOutput("Move Window") 

        Case #PB_Event_SizeWindow 
          AddOutput("Size Window") 

        Case #PB_Event_MinimizeWindow, #PB_Event_MaximizeWindow 
            AddOutput("Minimize or Maximize Window") 

        Case #PB_Event_Gadget 
          Select EventGadget()
            Case #GADGET_btnAdd 
	            AddOutput("Added a new Line to lvOutput ... ", 1) 
          EndSelect 
      EndSelect
    ForEver ; main loop 
  EndIf ; OpenWindow 
EndProcedure 

End main()

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 3:08 pm
by Axolotl
Sorry Fred,
that does not work.
First impression: Changing the Tab clears the list.
Second check: You have to click twice on the Tab to see the child control (ListViewGadget()) or new added item shows the list...
And more incorrect display of the ListViewGadget() elements...
Unfortunately not nice from my point of view.

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 3:15 pm
by Fred
Well you will have to tweak the code then, as it's API

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 3:36 pm
by Axolotl
Sorry for bothering you and thanks for the replies.
I am still not understanding why it works with 6.00.
Anyway, I guess I had to be more careful before moving to the next pb version with my current projects.
So far so good, I can stay with 6.00 by now.

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 4:06 pm
by RASHAD
Hi Axolotl
Try the distinguish between the different ListViews and let us know the result

Code: Select all

	Select uMsg 
		Case #WM_DRAWITEM
			If hWnd = GadgetID(#GADGET_lvOutput2)
			  .............
			 Elseif hWnd = GadgetID(#GADGET_lvOutput)
			 ..............

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 4:28 pm
by Axolotl
Hi RASHAD,
what I have is Messages on hWnd of WindowID(#WINDOW_Main) and PanelItemHandle after ButtonClick.
BTW hWnd is not the GadgetID() of any of the ListViews, but the parent (?)

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 4:35 pm
by RASHAD
Use only

Code: Select all

SetWindowCallback(@OnCallback())

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 5:00 pm
by Axolotl
receives only messages from main window.
Changed the callback like this

Code: Select all

	Select uMsg 
		Case #WM_DRAWITEM 
			*drawItem = lParam 
Debug "#WM_DRAWITEM ... " + hWnd 

			If hWnd = GadgetID(#GADGET_lvOutput2)
Debug "#WM_DRAWITEM 2 "
			ElseIf hWnd = GadgetID(#GADGET_lvOutput)
Debug "#WM_DRAWITEM "
			EndIf 

			If wParam = #GADGET_lvOutput Or wParam = #GADGET_lvOutput2 ; exact this listview 
				If *drawItem\itemID <> -1 
Debug "#WM_DRAWITEM  wParam = " + wParam + ", Index = " + *drawItem\itemID
received this results after button clicks

Code: Select all

hwndMain = 3277948	; <- after OpenWindow() 
#GADGET_lvOutput = 3     ; <- see wParam 
#GADGET_lvOutput2 = 5  ;  <-  never seen in the debug output, because of inside a panel or container 
#WM_DRAWITEM ... 3277948
#WM_DRAWITEM  wParam = 3, Index = 0
#WM_DRAWITEM ... 3277948
#WM_DRAWITEM  wParam = 3, Index = 0
#WM_DRAWITEM ... 3277948
#WM_DRAWITEM  wParam = 3, Index = 0
#WM_DRAWITEM ... 3277948
#WM_DRAWITEM  wParam = 3, Index = 1
#WM_DRAWITEM ... 3277948
#WM_DRAWITEM  wParam = 3, Index = 0
#WM_DRAWITEM ... 3277948
#WM_DRAWITEM  wParam = 3, Index = 1

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 5:07 pm
by RASHAD
Did you changed
SetWindowCallback(@OnCallback(), #WINDOW_Main)
to
SetWindowCallback(@OnCallback())

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun May 07, 2023 11:42 pm
by Axolotl
Yes, l did and l removed bindEvent() as well.

Re: PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Mon May 08, 2023 3:57 pm
by Axolotl
To all who are interested.
This is a working example of how to deal with ListViewGadget owner drawing if it is placed inside a PanelGadget.
Thanks Fred, for the push in the right direction.
Edit: Thanks to the new Purebasic Ver. 6.03 we do not need the subclassing anymore.
I added the following lines as an educational guess to the code example:

Code: Select all

CompilerIf #PB_Compiler_Version > 600 And #PB_Compiler_Version < 603      	
CompilerEndif

Code: Select all

EnableExplicit 

Enumeration EWindow 1	
#WINDOW_Main 
EndEnumeration 

Enumeration EGadget 1
#GADGET_lblInfo 
#GADGET_btnAdd 
#GADGET_pnlMain
#GADGET_lvOutput1 
#GADGET_lvOutput2 
#GADGET_lvOutput3 
EndEnumeration 

Global OldPanelGadgetSubclassProc 	; PanelGadget needs a subclass procedure 


; ---------------------------------------------------------------------------------------------------------------------

Procedure AddOutput(Message.s, State=#False) 
  Protected count, text.s 

	; ListviewGadget on Window 
  AddGadgetItem(#GADGET_lvOutput1, -1, Message) 
	count = CountGadgetItems(#GADGET_lvOutput1) 
  SetGadgetItemData(#GADGET_lvOutput1, count-1, State) 
  SetGadgetState(#GADGET_lvOutput1, count-1) 
	text = "Counts = " + count 

	; ListviewGadget on PanelGadget Tab.0 on Window 
  AddGadgetItem(#GADGET_lvOutput2, -1, Message) 
	count = CountGadgetItems(#GADGET_lvOutput2) 
  SetGadgetItemData(#GADGET_lvOutput2, count-1, State) 
  SetGadgetState(#GADGET_lvOutput2, count-1) 
	text + " | " + count 

	; ListviewGadget on PanelGadget Tab.2 on Window 
  AddGadgetItem(#GADGET_lvOutput3, -1, Message) 
	count = CountGadgetItems(#GADGET_lvOutput3) 
  SetGadgetItemData(#GADGET_lvOutput3, count-1, State) 
  SetGadgetState(#GADGET_lvOutput3, count-1) 
	text + " | " + count 

	; show that both items are added 
  SetGadgetText(#GADGET_lblInfo, text) 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

; same code is used in three callback procedures (one callback and two subclass) 
Macro Macro_DRAWITEM 
	*drawItem = lParam 

	If wParam = #GADGET_lvOutput1 Or 
		 wParam = #GADGET_lvOutput2 Or 
		 wParam = #GADGET_lvOutput3     ; exact one of this listviews  
		If *drawItem\itemID <> -1 
			text  = GetGadgetItemText(wParam, *drawItem\itemID) 
			state = GetGadgetItemData(wParam, *drawItem\itemID) 

			; make it look special 

			If *drawItem\itemState & #ODS_SELECTED 
        brush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
        textColor = GetSysColor_(#COLOR_HIGHLIGHTTEXT) 
      Else 
        brush = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW)) 
        textColor = GetSysColor_(#COLOR_WINDOWTEXT) 
      EndIf

      FillRect_(*drawItem\hdc, *drawItem\rcItem, brush) 
      DeleteObject_(brush)  ; no longer needed 
      SetTextColor_(*drawItem\hdc, textColor) 

			SetBkMode_(*drawItem\hdc, #TRANSPARENT)  

			; first column [30] is check mark for ... 
			If state : field = "✔" 
			Else     : field = "✘" 
 			EndIf 
			TextOut_(*drawItem\hdc, *drawItem\rcItem\left+2, *drawItem\rcItem\top, @field, Len(field)) 

			; second column [all] is entire item text 
			field = text 
			TextOut_(*drawItem\hdc, *drawItem\rcItem\left+32, *drawItem\rcItem\top, @field, Len(field)) 

			ProcedureReturn 0 	; we dont want the default procedure to work on this message 
		EndIf 
	EndIf 
EndMacro 

; ---------------------------------------------------------------------------------------------------------------------

Procedure OnCallback(hWnd, uMsg, wParam, lParam) 
	Protected *drawItem.DRAWITEMSTRUCT 
	Protected text.s, field.s, state  
	Protected textColor, brush  ; for background 

	Select uMsg 
		Case #WM_DRAWITEM 
			Macro_DRAWITEM 
	EndSelect

	ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure MyPanelGadgetSubclassProc(hwnd, Msg, wParam, lParam)  
	Protected *drawItem.DRAWITEMSTRUCT 
	Protected text.s, field.s, state  
	Protected textColor, brush  ; for background 

  Select Msg
    Case #WM_DRAWITEM 
			Macro_DRAWITEM 
  EndSelect

  ProcedureReturn CallWindowProc_(OldPanelGadgetSubclassProc, hwnd, Msg, wParam, lParam) 
EndProcedure  

; ---------------------------------------------------------------------------------------------------------------------

Procedure OnSizeEvent() 
  AddOutput("Size Window Event ") 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure CreateMainWindow(WndW = 800, WndH = 600)  
  Protected item.TC_ITEM, hPanelItem  
  
  If OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "Tester", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget) 
    ButtonGadget(#GADGET_btnAdd, 4, 4, 96, 24, "Add New Line") 
    TextGadget(#GADGET_lblInfo, 320, 4, WndW-124, 20, "Counts = 0 | 0 ") 
    ListViewGadget(#GADGET_lvOutput1, 4, 32, 600, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 

		PanelGadget(#GADGET_pnlMain, 0, 240, 600, 240) 
			AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #1") 
  		  ListViewGadget(#GADGET_lvOutput2, 8, 8, 560, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 
			AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #2") 
	    	TextGadget(#PB_Any, 8, 24, 240, 56, "Empty Tab Sheet ") 
			AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #3") 
  		  ListViewGadget(#GADGET_lvOutput3, 8, 8, 560, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 
		CloseGadgetList() 

CompilerIf #PB_Compiler_Version > 600 And #PB_Compiler_Version < 603   	
  ; Thanks to the new Purebasic Ver. 6.03 we do not need this anymore. 
  
    ; Get the Panel Item handle for TabSheet #0 
    item.TC_ITEM\mask = #TCIF_PARAM  
    SendMessage_(GadgetID(#GADGET_pnlMain), #TCM_GETITEM, 0, @item) 
    hPanelItem = item\lParam 
 		OldPanelGadgetSubclassProc = SetWindowLongPtr_(hPanelItem, #GWLP_WNDPROC, @MyPanelGadgetSubclassProc()) 

    ; Get the Panel Item handle for TabSheet #2 
    item.TC_ITEM\mask = #TCIF_PARAM  
    SendMessage_(GadgetID(#GADGET_pnlMain), #TCM_GETITEM, 2, @item) 
    hPanelItem = item\lParam 
		OldPanelGadgetSubclassProc = SetWindowLongPtr_(hPanelItem, #GWLP_WNDPROC, @MyPanelGadgetSubclassProc()) 
		; HINT: OldPanelGadgetSubclassProc is always the same 
CompilerEndIf 

    BindEvent(#PB_Event_SizeWindow, @OnSizeEvent()) 
    SetWindowCallback(@OnCallback(), #WINDOW_Main) 
  EndIf 
  ProcedureReturn IsWindow(#WINDOW_Main) 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure main() 
  Protected state 

  If CreateMainWindow() 
    Repeat  ; main loop 
      Select WaitWindowEvent(500)  
        Case #PB_Event_None 	; just for action ... 
          AddOutput("Nothing happens, only a stupid idle message (" + state + ")") 
          state + 1 

        Case #PB_Event_CloseWindow 
          If EventWindow() = #WINDOW_Main : Break : EndIf  ; close button on main window --> close application 

        Case #PB_Event_MoveWindow 
          AddOutput("Move Window") 

        Case #PB_Event_SizeWindow 
          AddOutput("Size Window") 

        Case #PB_Event_MinimizeWindow, #PB_Event_MaximizeWindow 
            AddOutput("Minimize or Maximize Window") 

        Case #PB_Event_Gadget 
          Select EventGadget()
            Case #GADGET_btnAdd 
	            AddOutput("Added a new Line to lvOutput ... ", 1) 
          EndSelect 
      EndSelect
    ForEver ; main loop 
  EndIf ; OpenWindow 
EndProcedure 

End main()

[Solved] PureBasic 6.02 beta 3 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Tue May 23, 2023 2:59 pm
by Axolotl
Because of the new module of mk-soft, I decided to rewrite my last example with his code...
The use of the new function "SetGadgetCallback()" is in my opinion very logical.
But compare yourself with my previous example.

You need the module code from mk-soft, you can find the last version here.

Code: Select all

;
; Example with ListviewGadget() and #LBS_OWNERDRAWFIXED inside a PanelGadget 
;  using mk-soft's Module SetGadgetCallback (Windows Only) 
; 

EnableExplicit 

Enumeration EWindow 1	
  #WINDOW_Main 
EndEnumeration 

Enumeration EGadget 1 
  #GADGET_lblInfo     ; TextGadget() 
  #GADGET_btnAdd      ; ButtonGadget() 
  #GADGET_pnlMain     ; PanelGadget()  
  #GADGET_lvOutput1   ; ListviewGadget() 
  #GADGET_lvOutput2   ; ListviewGadget() 
  #GADGET_lvOutput3   ; ListviewGadget() 
EndEnumeration 

;  LINK: https://www.purebasic.fr/english/viewtopic.php?t=70842 
XIncludeFile "Module_SetGadgetCallback.pbi"  ; current version == v0.04.1 


UseModule GadgetCallback  ; make the public functions available here 

; ---------------------------------------------------------------------------------------------------------------------

Procedure AddOutput(Message.s, State=#False)  ; add the message to all three #GADGET_lvOutputX gadgets 
  Protected count, text.s 

  ; ListviewGadget on Window 
  ; 
  AddGadgetItem(#GADGET_lvOutput1, -1, Message) 
  count = CountGadgetItems(#GADGET_lvOutput1) 
  SetGadgetItemData(#GADGET_lvOutput1, count-1, State) 
  SetGadgetState(#GADGET_lvOutput1, count-1) 
  text = "Counts = " + count 

  ; ListviewGadget on PanelGadget Tab.0 on Window 
  ; 
  AddGadgetItem(#GADGET_lvOutput2, -1, Message) 
  count = CountGadgetItems(#GADGET_lvOutput2) 
  SetGadgetItemData(#GADGET_lvOutput2, count-1, State) 
  SetGadgetState(#GADGET_lvOutput2, count-1) 
  text + " | " + count 

  ; ListviewGadget on PanelGadget Tab.2 on Window 
  ;
  AddGadgetItem(#GADGET_lvOutput3, -1, Message) 
  count = CountGadgetItems(#GADGET_lvOutput3) 
  SetGadgetItemData(#GADGET_lvOutput3, count-1, State) 
  SetGadgetState(#GADGET_lvOutput3, count-1) 
  text + " | " + count 

  ; show that both items are added 
  ; 
  SetGadgetText(#GADGET_lblInfo, text) 
EndProcedure 

; --- same code is used in three callback procedures (one callback and two subclass) ----------------------------------
;
Procedure.i OnMessage_DRAWITEM(wParam, lParam)  ; returns #False or #True 
  Protected *drawItem.DRAWITEMSTRUCT 
  Protected text.s, field.s, state  
  Protected textColor, brush  ; for background 
    
  *drawItem = lParam 

  If wParam = #GADGET_lvOutput1 Or 
     wParam = #GADGET_lvOutput2 Or 
     wParam = #GADGET_lvOutput3     ; exact one of this listviews  

    If *drawItem\itemID <> -1 
      text  = GetGadgetItemText(wParam, *drawItem\itemID) 
      state = GetGadgetItemData(wParam, *drawItem\itemID) 

    ; make it look special 

      If *drawItem\itemState & #ODS_SELECTED 
        brush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
        textColor = GetSysColor_(#COLOR_HIGHLIGHTTEXT) 
      Else 
        brush = CreateSolidBrush_(GetSysColor_(#COLOR_WINDOW)) 
        textColor = GetSysColor_(#COLOR_WINDOWTEXT) 
      EndIf

      FillRect_(*drawItem\hdc, *drawItem\rcItem, brush) 
      DeleteObject_(brush)  ; no longer needed 
      SetTextColor_(*drawItem\hdc, textColor) 

      SetBkMode_(*drawItem\hdc, #TRANSPARENT)  

        ; first column [30] is check mark for ... 
        If state : field = Chr($2713) ; check mark 
        Else     : field = Chr($2717) ; cross 
        EndIf 
        TextOut_(*drawItem\hdc, *drawItem\rcItem\left+2, *drawItem\rcItem\top, @field, Len(field)) 

        ; second column [all] is entire item text 
        field = text 
        TextOut_(*drawItem\hdc, *drawItem\rcItem\left+32, *drawItem\rcItem\top, @field, Len(field)) 

        ProcedureReturn #True   ; we don't want the default procedure to work on this message 
    EndIf 
  EndIf 
  ProcedureReturn #False    ; let the default procedure do the work on this message 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure PanelMain_OnCallback(hWnd, uMsg, wParam, lParam)  
  Select uMsg
    Case #WM_DRAWITEM 
      If OnMessage_DRAWITEM(wParam, lParam) 
        ProcedureReturn 0  ; return the info, that the job has been done. (acc. to MSDN for WM_DRAWITEM) 
      EndIf  
  EndSelect
  ProcedureReturn CallGadgetProc(hWnd, uMsg, wParam, lParam) 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure WindowMain_OnEventSizeWindow() 
  Protected ww, wh 

  ww = WindowWidth(#WINDOW_Main) : wh = WindowHeight(#WINDOW_Main) 

  ResizeGadget(#GADGET_lvOutput1, #PB_Ignore, #PB_Ignore, ww-8, #PB_Ignore) 
  ResizeGadget(#GADGET_pnlMain, #PB_Ignore, #PB_Ignore, ww, wh-240) 

  ; do some output 
  AddOutput("Event: SizeWindow " + ww + ", " + wh) 
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure WindowMain_OnEventGadgetSize() 
  Protected gw, gh 
  
  gw = GetGadgetAttribute(#GADGET_pnlMain, #PB_Panel_ItemWidth) 
  gh = GetGadgetAttribute(#GADGET_pnlMain, #PB_Panel_ItemHeight) 

  ResizeGadget(#GADGET_lvOutput2, #PB_Ignore, #PB_Ignore, gw-16, gh-16) 
  ResizeGadget(#GADGET_lvOutput3, #PB_Ignore, #PB_Ignore, gw-16, gh-16) 
  
EndProcedure

; ---------------------------------------------------------------------------------------------------------------------

Procedure WindowMain_CreateWindow(WndW = 800, WndH = 600)  
  Protected item.TC_ITEM, hPanelItem  
  
  If OpenWindow(#WINDOW_Main, 0, 0, WndW, WndH, "Tester", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_Invisible) 
    StickyWindow(#WINDOW_Main, 1)  ; want this window on top 

    ButtonGadget(#GADGET_btnAdd, 4, 4, 96, 24, "Add New Line") 
    TextGadget(#GADGET_lblInfo, 320, 4, WndW-124, 20, "Counts = 0 | 0 ") 

    ; first output gadget, parent is window 
    ; 
    ListViewGadget(#GADGET_lvOutput1, 4, 32, 600, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 

    PanelGadget(#GADGET_pnlMain, 0, 240, 600, 240) 
      AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #1") 
        ; second output gadget, parent is PanelGadget, Tab-Item 1  
        ;
        ListViewGadget(#GADGET_lvOutput2, 8, 8, 560, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 

      AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #2") 
        ; this Tab-Sheet is empty :) 
        ; 
        TextGadget(#PB_Any, 8, 24, 240, 56, "Empty Tab Sheet ") 

      AddGadgetItem(#GADGET_pnlMain, -1, "Tab Sheet #3") 
        ; third output gadget, parent is PanelGadget, Tab-Item 3  
  		  ;
        ListViewGadget(#GADGET_lvOutput3, 8, 8, 560, 200, #LBS_OWNERDRAWFIXED|#LBS_HASSTRINGS) 
    CloseGadgetList() 

    SetGadgetCallback(#GADGET_lvOutput1, @PanelMain_OnCallback(), #True) ; Parent of lvOutput is Window 
    SetGadgetCallback(#GADGET_lvOutput2, @PanelMain_OnCallback(), #True) ; Parent of lvOutput is Tab-Item 1 from PanelGadget 
    SetGadgetCallback(#GADGET_lvOutput3, @PanelMain_OnCallback(), #True) ; Parent of lvOutput is Tab-Item 1 from PanelGadget 

    BindEvent(#PB_Event_SizeWindow, @WindowMain_OnEventSizeWindow()) 
    BindGadgetEvent(#GADGET_pnlMain, @WindowMain_OnEventGadgetSize(), #PB_EventType_Resize) 

    HideWindow(#WINDOW_Main, 0) ; show the window 
  EndIf 
  ProcedureReturn IsWindow(#WINDOW_Main) 
EndProcedure 

; ---------------------------------------------------------------------------------------------------------------------

Procedure main() 
  Protected state 

  If WindowMain_CreateWindow() 
    Repeat  ; main loop 
      Select WaitWindowEvent(500)  
        Case #PB_Event_None 	; just for action ... 
          AddOutput("Nothing happens, only a stupid idle message (" + state + ")") 
          state + 1 

        Case #PB_Event_CloseWindow 
          If EventWindow() = #WINDOW_Main : Break : EndIf  ; close button on main window --> close application 

        Case #PB_Event_MoveWindow 
          AddOutput("Move Window") 

        Case #PB_Event_SizeWindow 
          AddOutput("Size Window") 

        Case #PB_Event_MinimizeWindow, #PB_Event_MaximizeWindow 
            AddOutput("Minimize or Maximize Window") 

        Case #PB_Event_Gadget 
          Select EventGadget()
            Case #GADGET_btnAdd 
	            AddOutput("Added a new Line to lvOutput ... ", 1) 
          EndSelect 
      EndSelect
    ForEver ; main loop 
  EndIf ; OpenWindow 
EndProcedure 

End main() 

Re: [Solved] PureBasic 6.03 beta 1 LTS (x64) #WM_DRAWITEM does not work properly.

Posted: Sun Jun 11, 2023 2:28 pm
by Axolotl
Hi there,
small update on my example code above....
With the new PureBasic 6.03 beta 1 the SetWindowCallback() is working with default mode parameter. No extra subclassing is needed for a proper function.
I edited the above code .