Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Keeping Checkbox Style for Owner Drawn Listbox Control with Color Changing Items

Posted on 2004-09-09
3
Medium Priority
?
284 Views
Last Modified: 2013-12-25
I have the code downloaded and working that allows color changes within a listbox control (see below).  The problem that I have is that I need to KEEP the checkboxes to the left of the items added within the control (the code changes the color of the string to the color number listed in the text portion).  If you run the code, then the checkboxes go away.  Is there a way to do this?

The code is listed below

create a project with a listbox control.  Set the listbox style to Checkbox

Option Explicit

Private Sub Form_Load()
Dim I As Integer

For I = 0 To 15
   'Load a List of 0 to 15 with the Item Data
   'Set to the QBColors 0 - 15
   List1.AddItem "Color " & I
   List1.itemData(List1.NewIndex) = QBColor(I)
Next
'Subclass the "Form", to Capture the Listbox Notification Messages
SubLists hwnd
End Sub

Private Sub Form_Unload(Cancel As Integer)
'Release the SubClassing, Very Import to Prevent Crashing!
RemoveSubLists hwnd
End Sub

Place the following code in a module:
Option Explicit

Public Type RECT
   Left As Long
   Top As Long
   Right As Long
   Bottom As Long
End Type

Public Type DRAWITEMSTRUCT
   CtlType As Long
   CtlID As Long
   itemID As Long
   itemAction As Long
   itemState As Long
   hwndItem As Long
   hdc As Long
   rcItem As RECT
   itemData As Long
End Type

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Public Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Public Declare Function SetBkColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
Public Declare Function SetTextColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
Public Declare Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal lpString As String, ByVal nCount As Long) As Long
Public Declare Function DrawFocusRect Lib "user32" (ByVal hdc As Long, lpRect As RECT) As Long
Public Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long

Public Const COLOR_HIGHLIGHT = 13
Public Const COLOR_HIGHLIGHTTEXT = 14
Public Const COLOR_WINDOW = 5
Public Const COLOR_WINDOWTEXT = 8
Public Const LB_GETTEXT = &H189
Public Const LB_GETITEMHEIGHT = &H1A1
Public Const LB_GETITEMRECT = &H198
Public Const WM_DRAWITEM = &H2B
Public Const GWL_WNDPROC = (-4)

Public lPrevWndProc As Long

Public Function SubClassedList(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim tItem As DRAWITEMSTRUCT
Dim sBuff As String * 255
Dim sItem As String
Dim lBack As Long

If Msg = WM_DRAWITEM Then

   'Redraw the listbox
   'This function only passes the Address of the DrawItem Structure, so we need to
   'use the CopyMemory API to Get a Copy into the Variable we setup:
   Call CopyMemory(tItem, ByVal lParam, Len(tItem))
   
   'Make sure we're dealing with a Listbox
   If tItem.CtlType = ODT_LISTBOX Then
   
       'Get the Item Text
       Call SendMessage(tItem.hwndItem, LB_GETTEXT, tItem.itemID, ByVal sBuff)
       
       sItem = Left(sBuff, InStr(sBuff, Chr(0)) - 1)
       If (tItem.itemState And ODS_FOCUS) Then
       
           'Item has Focus, Highlight it, I'm using the Default Focus
           'Colors for this example.
           lBack = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT))
           Call FillRect(tItem.hdc, tItem.rcItem, lBack)
           Call SetBkColor(tItem.hdc, GetSysColor(COLOR_HIGHLIGHT))
           Call SetTextColor(tItem.hdc, GetSysColor(COLOR_HIGHLIGHTTEXT))
           TextOut tItem.hdc, tItem.rcItem.Left, tItem.rcItem.Top, ByVal sItem, Len(sItem)
           DrawFocusRect tItem.hdc, tItem.rcItem
Else
       
           'Item Doesn't Have Focus
           'Create a Brush using the Color of the Listbox Window
           lBack = CreateSolidBrush(tItem.itemData)
           
           'Paint the Item Area
           Call FillRect(tItem.hdc, tItem.rcItem, lBack)
           
           'Set the Text Colors, using the ForeColor specified in the ItemData of the Item
           Call SetBkColor(tItem.hdc, tItem.itemData)
           Call SetTextColor(tItem.hdc, GetSysColor(COLOR_WINDOWTEXT))
           
           'Display the Item Text (this loses the check box to the left of the item)
           TextOut tItem.hdc, tItem.rcItem.Left, tItem.rcItem.Top, ByVal sItem, Len(sItem)
       End If
       Call DeleteObject(lBack)
       
       'Don't Need to Pass a Value on as we've just handled the Message ourselves
       SubClassedList = 0
       Exit Function
               
   End If
       
End If
SubClassedList = CallWindowProc(lPrevWndProc, hwnd, Msg, wParam, lParam)
End Function

Public Sub SubLists(ByVal hwnd As Long)
lPrevWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf SubClassedList)
End Sub

Public Sub RemoveSubLists(ByVal hwnd As Long)
Call SetWindowLong(hwnd, GWL_WNDPROC, lPrevWndProc)
End Sub

0
Comment
Question by:Dalexan
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 22

Accepted Solution

by:
danaseaman earned 2000 total points
ID: 12031305
A 3rd party control that does this(US$25) is available at http://www.zealsoftstudio.com/checklistbox/index.html 
Because you are using OwnerDraw you will need to draw the checkbox yourself using API DrawFrameControl.
Here are some snippets to get you started.


Enum FrameType
   DFC_BUTTON = 4&
   DFC_SCROLL = 3&
   DFC_MENU = 2&
   DFC_CAPTION = 1&
End Enum

Enum Buttons
   DFCS_BUTTONCHECK = &H0&
   DFCS_BUTTONPUSH = &H10&
   DFCS_BUTTONRADIOIMAGE = &H1&
   DFCS_BUTTONRADIOMASK = &H2&
End Enum

'possible states for the frame
Private Const DFCS_CHECKED = &H400&
Private Const DFCS_FLAT = &H4000&
Private Const DFCS_HOT = &H1000&
Private Const DFCS_MONO = &H8000&
Private Const DFCS_PUSHED = &H200&
Private Const DFCS_INACTIVE = &H100&

Dim bChecked As Boolean
'Add code here to retrieve CheckBox status.
DrawFrameControl tItem.hdc, tItem.rcItem, DFC_BUTTON, DFCS_BUTTONCHECK Or IIf(bChecked, DFCS_CHECKED, 0) Or DFCS_FLAT
'Adjust tItem.rcItem.Left to account for checkbox.
TextOut tItem.hdc, tItem.rcItem.Left + 15, tItem.rcItem.Top, ByVal sItem, Len(sItem)
0
 
LVL 22

Expert Comment

by:danaseaman
ID: 12036361
Retreive checkbox status:
Private Const ODS_SELECTED = &H1
bChecked = ((tItem.ItemState And ODS_SELECTED) = ODS_SELECTED)
0
 

Author Comment

by:Dalexan
ID: 12077587
This worked fine, We only needed to figure out how to draw the checkbox. We did have to find the code to retreive the status of the item selected.

Thank you,
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Suggested Courses

609 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question