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

Just starting out? Need help? Post your questions and find answers here.
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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() 
Last edited by Axolotl on Tue May 23, 2023 3:00 pm, edited 2 times in total.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post by Axolotl »

The problem exists not only with ListviewGadget(), but also with ComboboxGadget().
Testet on ListIconGadget() as well.
Seems to be a general problem.
Last edited by Axolotl on Sun May 07, 2023 3:09 pm, edited 1 time in total.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

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

Post 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()
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

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

Post by Fred »

Well you will have to tweak the code then, as it's API
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

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

Post 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)
			 ..............
Egypt my love
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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 (?)
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

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

Post by RASHAD »

Use only

Code: Select all

SetWindowCallback(@OnCallback())
Egypt my love
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

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

Post by RASHAD »

Did you changed
SetWindowCallback(@OnCallback(), #WINDOW_Main)
to
SetWindowCallback(@OnCallback())
Egypt my love
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post by Axolotl »

Yes, l did and l removed bindEvent() as well.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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()
Last edited by Axolotl on Sun Jun 11, 2023 2:34 pm, edited 1 time in total.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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() 
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Axolotl
Addict
Addict
Posts: 802
Joined: Wed Dec 31, 2008 3:36 pm

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

Post 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 .
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Post Reply