Page 1 of 1
Colouring ListIconGadget headers
Posted: Thu Jun 07, 2007 4:19 pm
by Fangbeast
I found the following code in the forum to subclass a listicongadget so that I can colour the heading area but after I managed to modify it to colour 3 gadgets, it appeared that I was doing something wrong ans any gadgets after 3 wouldn't colour.
Code: Select all
; Subclass ListIcon so we can customdraw the header text and colour the header area
;============================================================================================================================
Procedure SubclassedListIcon(hwnd, msg, wparam, lparam)
Protected hdi.hd_item
result = CallWindowProc_(form\oldListIconCallback, hwnd, msg, wparam, lparam)
Select msg
Case #WM_NOTIFY
*pnmh.NMHDR = lparam ;--> Get handle to ListIcon header control
If *pnmh\code = #NM_CUSTOMDRAW
*pnmcd.NMCUSTOMDRAW = lparam ;--> Determine drawing stage
Select *pnmcd\dwDrawStage
Case #CDDS_PREPAINT
result = #CDRF_NOTIFYITEMDRAW
Case #CDDS_ITEMPREPAINT ; Get header text.
text$ = Space(100)
hdi\mask = #HDI_TEXT
hdi\psztext = @text$
hdi\cchtextmax = Len(text$)
SendMessage_(form\hHeader, #HDM_GETITEM, *pnmcd\dwItemSpec, hdi) ; Check button state.
If *pnmcd\uItemState & #CDIS_SELECTED
DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH | #DFCS_PUSHED) ; Offset text because of the selected button.
InflateRect_(*pnmcd\rc, -1, -1)
Else
DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH)
EndIf ; Draw background. ; Here we alternate red text on blue background.
InflateRect_(*pnmcd\rc, -1, -1)
SetBkMode_(*pnmcd\hdc, #TRANSPARENT)
;If *pnmcd\dwItemSpec & 1
FillRect_(*pnmcd\hdc, *pnmcd\rc, form\brush)
SetTextColor_(*pnmcd\hdc, $000000)
;Else
; FillRect_(*pnmcd\hdc, *pnmcd\rc, Colour)
; SetTextColor_(*pnmcd\hdc, $000000)
;EndIf
DrawText_(*pnmcd\hdc, @text$, Len(text$), *pnmcd\rc, #DT_CENTER | #DT_VCENTER | #DT_END_ELLIPSIS)
result = #CDRF_SKIPDEFAULT
EndSelect
EndIf
EndSelect
ProcedureReturn result
EndProcedure
These are the two lines to invoke the colouring of a single gadget and I was wondering if there is a simple way to use a linked list to subclass and colour as many gadget headings that I want without resorting to a library with features I don't need?
Code: Select all
;------------------------------------------------------------------------------------------------
; Sublcass ListIconGadget to allow header to be painted
;------------------------------------------------------------------------------------------------
form\hHeader = SendMessage_(GadgetID(#Gadget_ebackup_items), #LVM_GETHEADER, 0, 0) ; Subclass ListIcon so we can customdraw the header text
form\oldListIconCallback = SetWindowLong_(GadgetID(#Gadget_ebackup_items), #GWL_WNDPROC, @SubclassedListIcon())
Give me 30 years and I' might get betetr with the API but I doubt it

Posted: Thu Jun 07, 2007 6:26 pm
by srod
fangles, I reckon the problem is your 'form' structure variable which I presume is global.
The thing is, that the code you're using was written for PB 3.94. With PB 4, we can easily get the header text and so there is no need to store the handle of the header control etc. In fact, we never needed to store it anyhow ... but that's another story!
The following is very rough and ready (but is all I have time for!) with the colouring routine being simplified over the version you're currently using:
Code: Select all
;Coloured header control.
;By srod.
;Purebasic 4.
;Windows.
#LVM_GETHEADER = #LVM_FIRST + 31
; Globals
Global oldListIconCallback, redbrush, bluebrush
redbrush=CreateSolidBrush_(#Yellow)
bluebrush=CreateSolidBrush_(#Yellow)
; Proc for subclassed ListIconGadget
Procedure SubclassedListIcon(hwnd, msg, wparam, lparam)
Protected hdi.hd_item
result = CallWindowProc_(oldListIconCallback, hwnd, msg, wparam, lparam)
Select msg
Case #WM_NOTIFY
*pnmh.NMHDR = lparam
;--> Get handle to ListIcon header control
If *pnmh\code = #NM_CUSTOMDRAW
*pnmcd.NMCUSTOMDRAW = lparam
;--> Determine drawing stage
Select *pnmcd\dwDrawStage
Case #CDDS_PREPAINT
result = #CDRF_NOTIFYITEMDRAW
Case #CDDS_ITEMPREPAINT
;Get header text.
text$=GetGadgetItemText(GetDlgCtrlID_(hWnd),-1,*pnmcd\dwItemSpec)
;Check button state.
If *pnmcd\uItemState & #CDIS_SELECTED
DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH|#DFCS_PUSHED)
;Offset text because of the selected button.
InflateRect_(*pnmcd\rc,-1,-1)
Else
DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH)
EndIf
;Draw background.
*pnmcd\rc\bottom-2 : *pnmcd\rc\right-2
SetBkMode_(*pnmcd\hdc,#TRANSPARENT)
If *pnmcd\dwItemSpec&1
FillRect_(*pnmcd\hdc, *pnmcd\rc, redbrush)
SetTextColor_(*pnmcd\hdc, #Blue)
Else
FillRect_(*pnmcd\hdc, *pnmcd\rc, bluebrush)
SetTextColor_(*pnmcd\hdc, #Red)
EndIf
*pnmcd\rc\top+2
InflateRect_(*pnmcd\rc,-5,0)
If *pnmcd\rc\right>*pnmcd\rc\left
DrawText_(*pnmcd\hdc, @text$, Len(text$), *pnmcd\rc, #DT_CENTER|#DT_VCENTER|#DT_END_ELLIPSIS)
EndIf
result = #CDRF_SKIPDEFAULT
EndSelect
EndIf
EndSelect
ProcedureReturn result
EndProcedure
; ************************************************
; Main Window
; ************************************************
If OpenWindow(0, 100, 100, 415, 400, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0))
ListIconGadget(0, 5, 5, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
ListIconGadget(1, 5, 90, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
ListIconGadget(2, 5, 175, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
ListIconGadget(3, 5, 250, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
;Subclass ListIcon so we can customdraw the header text
oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())
oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())
oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())
oldListIconCallback = SetWindowLong_(GadgetID(3), #GWL_WNDPROC, @SubclassedListIcon())
;Add 10 more columns.
For j = 0 To 3
For i = 1 To 10
AddGadgetColumn(j, i, "col "+Str(i), 50)
Next
next
;Add some data
For b=0 To 99; Add 100 rows.
AddGadgetItem(0,-1,"")
Next
For i = 0 To 99
For j = 0 To 50
SetGadgetItemText(0,i,Str(i+j),j)
Next j
Next i
Repeat
EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
DeleteObject_(redbrush)
DeleteObject_(bluebrush)
EndIf
End
I see no need for linked lists etc. If you really need to store info on each listicon then consider using a Window's property to store a pointer to whatever data you need to store.
Thank you
Posted: Fri Jun 08, 2007 1:06 am
by Fangbeast
I can see that I am going to have to sell my children to pay you. I still don't know bugger alla bout manipulating the api which is why I can't figure these things out myself. Normal pb code I can bugger up and hopefully fix but this stuff???
Thanks for that.. Hope things are going okay for you.
Re: Colouring ListIconGadget headers
Posted: Sat Apr 28, 2012 2:50 pm
by Fangbeast
Really old post but as this question is related, I'll put it here.
The above code works fine if I do this for every code in the main openwindow statement
oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())
(oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())
oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())
However, if I do this inside a PROCEDURE that opens another window on top of the main one, my program will either crash at the opening of that window when encountering that statement or when I exit that window.
I can reproduce it at will. Simply commenting out that statement fixes my problem immediately.
Re: Colouring ListIconGadget headers
Posted: Sat Apr 28, 2012 3:40 pm
by MachineCode
In one of the PureBasic blog posts, they said to change all SetWindowLong_() to SetWindowLongPtr_() now. Try that. And the same for GetWindowLong_() to GetWindowLongPtr_().
Re: Colouring ListIconGadget headers
Posted: Sat Apr 28, 2012 11:40 pm
by Fangbeast
Thanks for that MachineCode, fingers crossed.
**EDIT** Just did it in 8 places in my program, tested, works like a charm. I'll go read the blog post, not that i'll understand it but I'll read it:):)
Thanks again.
Re: Colouring ListIconGadget headers
Posted: Sat Apr 28, 2012 11:56 pm
by srod
If you are using PB x64 (or writing code to compile on both x86 and x64) then yes you want to be using SetWindowLongPtr_() etc. fangles.
Re: Colouring ListIconGadget headers
Posted: Sun Apr 29, 2012 2:56 am
by Fangbeast
srod wrote:If you are using PB x64 (or writing code to compile on both x86 and x64) then yes you want to be using SetWindowLongPtr_() etc. fangles.
No, I'm not. Could not shell out the buckaroonies for the x64 version of win7, especially when I could not get x64 versions of all my needed hardware drivers so I never bothered.
Just used PSPad text editor to do a search and replace on ALL my code and no more problems.
So glad it was an easy fix, too many other dramas going on around here

:):)
Re: Colouring ListIconGadget headers
Posted: Sun Apr 29, 2012 4:43 am
by idle
Fangbeast wrote:Really old post but as this question is related, I'll put it here.
The above code works fine if I do this for every code in the main openwindow statement
oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())
(oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())
oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())
However, if I do this inside a PROCEDURE that opens another window on top of the main one, my program will either crash at the opening of that window when encountering that statement or when I exit that window.
I can reproduce it at will. Simply commenting out that statement fixes my problem immediately.
I don't think you can't use it like that, not with multiple windows since the address stored in OldListIconCallBack
will always refer to the last opened windows procedure resulting in an IMA in your callback
Re: Colouring ListIconGadget headers
Posted: Sun Apr 29, 2012 8:21 am
by Fangbeast
idle wrote:Fangbeast wrote:Really old post but as this question is related, I'll put it here.
The above code works fine if I do this for every code in the main openwindow statement
oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())
(oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())
oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())
However, if I do this inside a PROCEDURE that opens another window on top of the main one, my program will either crash at the opening of that window when encountering that statement or when I exit that window.
I can reproduce it at will. Simply commenting out that statement fixes my problem immediately.
I don't think you can't use it like that, not with multiple windows since the address stored in OldListIconCallBack
will always refer to the last opened windows procedure resulting in an IMA in your callback
Seems to work at the moment. Since I changed Get/SetWindowLong to Get/SetWindowLongPtr, it's no longer crashing, which it was before, all the time.
So much to do, I need a holiday!
Re: Colouring ListIconGadget headers
Posted: Sun Apr 29, 2012 9:37 am
by srod
If you are not using PB x64 then SetWindowLongPtr_() will make no difference.
Re: Colouring ListIconGadget headers
Posted: Sun Apr 29, 2012 11:35 am
by Fangbeast
srod wrote:If you are not using PB x64 then SetWindowLongPtr_() will make no difference.
Well, it made a difference here, apparently. Whether that's due to something else is decidedly unclear to me. Once I had changed from Get/SetWindowLong to Get/SetWindowLongPtr, no more crashes at all.
If that change is not the reason, I don't know why. As you well know, API isn't my forte.