Announcement

Collapse
No announcement yet.

Control the background and foreground color for each row in a listbox?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Control the background and foreground color for each row in a listbox?

    I have been looking over code samples for listboxes and Borjes' list control. I am still wondering if every row can have its own background and foreground color?

    I am thinking something like a virtual listbox where we keep a per row RGB value for background and foreground?

    So as each row is displayed it would be formatted, painted?

    Anyone done this? From WireShark:
    Attached Files

  • #2
    Easy to do with ownerdrawn listbox under %WM_DRAWITEM, but why not use a ListView so you get headers too? Small example:
    Click image for larger version

Name:	ListViewColors.jpg
Views:	135
Size:	29.1 KB
ID:	782865
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "WIN32API.INC"
    #INCLUDE "COMMCTRL.INC"
    %IDC_LISTVIEW1 = 221
    
    '====================================================================
    FUNCTION PBMAIN() AS LONG
      LOCAL hDlg, c AS LONG
       DIALOG NEW PIXELS, 0, "ListView Line Colors",,, 320, 220, %WS_CAPTION OR %WS_SYSMENU, 0 TO hDlg
    
       CONTROL ADD LISTVIEW, hDlg, %IDC_LISTVIEW1,"", 5,5,310,210, _
                            %WS_TABSTOP OR %LVS_REPORT OR %LVS_SHOWSELALWAYS OR _
                            %LVS_SINGLESEL, %WS_EX_CLIENTEDGE
       LISTVIEW SET STYLEXX hDlg, %IDC_LISTVIEW1, %LVS_EX_GRIDLINES OR %LVS_EX_FULLROWSELECT
    
       LISTVIEW INSERT COLUMN hDlg, %IDC_LISTVIEW1, 1, "Number", 60, 0
       LISTVIEW INSERT COLUMN hDlg, %IDC_LISTVIEW1, 2, "Time", 230, 0
    
      FOR c = 1 TO 15
         LISTVIEW INSERT ITEM hDlg, %IDC_LISTVIEW1, c, 0, FORMAT$(c)
         LISTVIEW SET TEXT hDlg, %IDC_LISTVIEW1, c, 2, "Col2    " + "Row " + FORMAT$(c)
      NEXT
    
       DIALOG SHOW MODAL hDlg CALL DlgProc
    END FUNCTION
    
    '====================================================================
    CALLBACK FUNCTION DlgProc() AS LONG
      LOCAL pLVDI AS LV_DISPINFO PTR, lplvcd AS NMLVCUSTOMDRAW PTR
    
      SELECT CASE CB.MSG
      CASE %WM_NOTIFY
          SELECT CASE CB.NMID
          CASE %IDC_LISTVIEW1
              SELECT CASE CB.NMCODE
              CASE %NM_CUSTOMDRAW
                  lplvcd = CB.LPARAM
                  SELECT CASE @lplvcd.nmcd.dwDrawStage
                  CASE %CDDS_PREPAINT, %CDDS_ITEMPREPAINT
                      FUNCTION = %CDRF_NOTIFYITEMDRAW
    
                  CASE %CDDS_ITEMPREPAINT OR %CDDS_SUBITEM
                      SELECT CASE @lplvcd.nmcd.dwItemSpec  ' = line number
                      CASE 3, 4, 5, 9, 10  ' ways to change item BG color
                          @lplvcd.clrTextBk = RGB(196, 255, 255)
                      CASE 6, 7, 8
                          @lplvcd.clrTextBk = %RGB_LIGHTBLUE
                      CASE ELSE
                          @lplvcd.clrTextBk = GetSysColor(%COLOR_INFOBK)
                          @lplvcd.clrText   = %RED  ' just for fun - change text color
                      END SELECT
                      FUNCTION = %CDRF_NEWFONT
                  END SELECT
              END SELECT
          END SELECT
      END SELECT
    END FUNCTION

    Comment


    • #3
      Originally posted by David Clarke View Post
      I have been looking over code samples for listboxes and Borjes' list control. I am still wondering if every row can have its own background and foreground color?

      I am thinking something like a virtual listbox where we keep a per row RGB value for background and foreground?

      So as each row is displayed it would be formatted, painted?

      Anyone done this? From WireShark:
      I would think that wireshark is coloring the lines based on content, since the LV keeps changing. I do that all the time for programs at work. I think some of the sample code on the forum shows how to do that. I trick that I often pull is to add a zero width column, then put content in it to drive the color selection.

      My current challenge is to set up editing on a listview. Lots of DDT samples of that here, but not as many for Win32/Firefly. But probably good practice for me to adapt one.
      Real programmers use a magnetized needle and a steady hand

      Comment


      • #4
        Thanks Borje! Super helpful example. Now I have to make that virtual listview! I will look a some examples on here.

        Comment


        • #5
          Bud - I will post if I find anything that would help you.

          Comment


          • #6
            What structures (TYPE) have the clrText and clrTextBk members for a list box?

            Comment


            • #7
              I found for TreeView and ListView, not for ListBox by searching WinAPI subdirectory of PB install directory with File Explorer's search.

              Cheers,
              Dale

              Comment


              • #8
                Borje, is it possible to do something similar as in your example (#2) with a LISTBOX, or must all the drawing be made under %WM_DRAWITEM for that?

                /Mikael

                Comment


                • #9
                  In ListBox, use WM_DRAWITEM, yes.
                  Click image for larger version

Name:	ListBoxColors.jpg
Views:	49
Size:	27.9 KB
ID:	786361
                  Example:
                  Code:
                  #COMPILE EXE
                  #DIM ALL
                  #INCLUDE "WIN32API.INC"
                  
                  %IDC_LISTBOX1 = 141
                  
                  '====================================================================
                  FUNCTION PBMAIN
                    LOCAL hDlg AS DWORD
                  
                    DIALOG NEW 0, "Ownerdrawn ListBox", , , 220, 180, %WS_CAPTION OR %WS_SYSMENU TO hDlg
                  
                    CONTROL ADD LISTBOX, hDlg, %IDC_LISTBOX1, , 5, 5, 210, 154, _
                                         %WS_CHILD OR %LBS_OWNERDRAWFIXED OR %LBS_HASSTRINGS OR _
                                         %WS_TABSTOP OR %WS_VSCROLL, %WS_EX_CLIENTEDGE
                  
                    CONTROL ADD BUTTON, hDlg, %IDCANCEL, "&Close", 164, 161, 50, 14
                  
                    DIALOG SHOW MODAL hDlg, CALL DlgProc
                  END FUNCTION
                  
                  '====================================================================
                  CALLBACK FUNCTION DlgProc
                    LOCAL c, hBrush, hPen AS LONG, sText AS STRING, _
                          lpdis AS DRAWITEMSTRUCT PTR, _
                          zTxt AS ASCIIZ * 300 ' is 300 bytes/item text enough..?
                  
                    SELECT CASE CBMSG
                    CASE %WM_INITDIALOG
                        FOR c = 1 TO 25 'fill list with some data to show
                           LISTBOX ADD CBHNDL, %IDC_LISTBOX1, "This is item " + FORMAT$(c)
                        NEXT
                        LISTBOX SELECT CBHNDL, %IDC_LISTBOX1, 1
                  
                    CASE %WM_COMMAND
                        SELECT CASE CBCTL
                        CASE %IDCANCEL
                            IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                DIALOG END CBHNDL
                            END IF
                  
                        CASE %IDC_LISTBOX1
                            SELECT CASE CBCTLMSG
                            CASE %LBN_DBLCLK
                                LISTBOX GET TEXT CBHNDL, %IDC_LISTBOX1 TO sText
                                MSGBOX sText
                  
                            CASE %LBN_SELCHANGE
                                 LISTBOX GET TEXT CBHNDL, %IDC_LISTBOX1 TO sText
                                 DIALOG SET TEXT CB.HNDL, sText
                            END SELECT
                        END SELECT
                  
                    CASE %WM_DRAWITEM
                        IF CBWPARAM = %IDC_LISTBOX1 THEN 'make sure it's our list (if several exists)
                            lpdis = CBLPARAM
                            IF @lpdis.itemID = &HFFFFFFFF THEN EXIT FUNCTION 'if empty list, jump out..
                  
                            SELECT CASE @lpdis.itemAction
                            CASE %ODA_DRAWENTIRE, %ODA_SELECT 'DRAW BACKGROUND
                                IF (@lpdis.itemState AND %ODS_SELECTED) = 0 THEN 'if not selected, use these colors
                                    SELECT CASE @lpdis.itemID  ' = line number
                                    CASE 3, 4, 5, 9, 10  ' ways to change item BG color
                                        hBrush = CreateSolidBrush(RGB(196, 255, 255)) 'Create a brush with proper color
                                        SetBkColor @lpdis.hDC, RGB(196, 255, 255)     'set text background to same color
                                    CASE 6, 7, 8
                                        hBrush = CreateSolidBrush(%RGB_LIGHTBLUE)
                                        SetBkColor @lpdis.hDC, %RGB_LIGHTBLUE
                                    CASE ELSE
                                        hBrush = CreateSolidBrush(GetSysColor(%COLOR_INFOBK))
                                        SetBkColor @lpdis.hDC, GetSysColor(%COLOR_INFOBK)
                                        SetTextColor @lpdis.hDC, %RED  ' just for fun - change text color
                                    END SELECT
                                    FillRect @lpdis.hDC, @lpdis.rcItem, hBrush
                                    IF hBrush THEN DeleteObject(hBrush) 'Select original brush back and delete created
                                ELSE  ' selected item
                                   FillRect @lpdis.hDC, @lpdis.rcItem, GetSysColorBrush(%COLOR_HIGHLIGHT)
                                   SetBkColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHT)
                                   SetTextColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHTTEXT)
                                END IF
                  
                                'DRAW TEXT
                                CONTROL SEND CBHNDL, %IDC_LISTBOX1, %LB_GETTEXT, @lpdis.itemID, VARPTR(zTxt)  'Get item text
                                DrawText @lpdis.hDC, zTxt, -1, @lpdis.rcItem, %DT_LEFT OR %DT_SINGLELINE OR %DT_VCENTER ' draw item text
                  
                  '             DRAW GRID LINES
                                hPen = CreatePen(%PS_SOLID, 1, GetSysColor(%COLOR_3DFACE))
                                hPen = SelectObject(@lpdis.hDC, hPen)
                                MoveToEx @lpdis.hDC, 0, @lpdis.rcItem.nBottom - 1, BYVAL %NULL
                                LineTo @lpdis.hDC, @lpdis.rcItem.nRight, @lpdis.rcItem.nBottom - 1
                                MoveToEx @lpdis.hDC, @lpdis.rcItem.nRight - 1, @lpdis.rcItem.nTop, BYVAL %NULL
                                LineTo @lpdis.hDC, @lpdis.rcItem.nRight - 1, @lpdis.rcItem.nBottom
                                DeleteObject SelectObject(@lpdis.hDC, hPen)
                  
                                FUNCTION = %TRUE
                            END SELECT
                        END IF
                  
                    END SELECT
                  
                  END FUNCTION

                  Comment


                  • #10
                    Hi Börje, and thanks for the sample code.

                    I first tried to subclass the LISTBOX control and capture only one row by its contents, where I wanted to set the background color. But I couldn't make it work. Couldn't really figure out why it didnt work either.

                    I will try some more, but in the end I will probably be using parts of your example instead.

                    /Mikael

                    Comment

                    Working...
                    X