ListBox items with different color

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

ListBox items with different color

Postby mark_c » Tue Oct 31, 2017 5:10 am

Hello,
this is my very trivial example that should color differently the items in a ListBox when a directory exists or does not exist. Is there a better way without using the ListBox1DrawItem event and keeping the lbStandard Style?

thank you

Code: Select all
void __fastcall TForm1::Button3Click(TObject *Sender)
{

        TRect TheRect;
        //Rect(int ALeft, int ATop, int ARight, int ABottom);

        for(int i=0; i<ListBox1->Items->Count; i++)
        {
                TheRect = Rect(0,20*i,200,20*i);
                // eliminate artifacts
                ListBox1->Canvas->FillRect(TheRect);

                DWORD dwAttr = GetFileAttributes(ListBox1->Items->Strings[i].c_str());
                if(dwAttr == FILE_ATTRIBUTE_DIRECTORY)
                {
                        // color the line
                        ListBox1->Canvas->Brush->Color = clRed;
                        ListBox1->Canvas->FillRect(TheRect);
                }
                else
                {
                        ListBox1->Canvas->Brush->Color = clGreen;
                        ListBox1->Canvas->FillRect(TheRect);
                }

                // render the text
                ListBox1->Canvas->TextOut( TheRect.Left + 1, TheRect.Top, ListBox1->Items->Strings[i]);
        }
}
//---------------------------------------------------------------------------
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: ListBox items with different color

Postby mark_c » Tue Oct 31, 2017 8:34 am

another version using the DrwaItem event

Code: Select all
void __fastcall TForm1::ListBox1DrawItem(TWinControl *Control, int Index,
      TRect &Rect, TOwnerDrawState State)
{
        TRect TheRect = ::Rect(0,22,300,22);
        //Rect(int ALeft, int ATop, int ARight, int ABottom);

                ListBox1->Canvas->Font->Size=12;

                // eliminate artifacts
                ListBox1->Canvas->FillRect(TheRect);

                DWORD dwAttr = GetFileAttributes(ListBox1->Items->Strings[Index].c_str());
                if(dwAttr == FILE_ATTRIBUTE_DIRECTORY)
                {
                        // color the line
                        ListBox1->Canvas->Brush->Color = clRed;
                        ListBox1->Canvas->FillRect(TheRect);
                }
                else
                {
                        ListBox1->Canvas->Brush->Color = clGreen;
                        ListBox1->Canvas->FillRect(TheRect);
                }

                // render the text
                ListBox1->Canvas->TextOut( TheRect.Left, TheRect.Top, ListBox1->Items->Strings[Index]);
}
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: ListBox items with different color

Postby mark_c » Tue Oct 31, 2017 9:38 am

final version

Code: Select all
void __fastcall TForm1::ListBox1DrawItem(TWinControl *Control, int Index,
      TRect &Rect, TOwnerDrawState State)
{
                ListBox1->Canvas->Font->Size=12;
                ListBox1->Canvas->Font->Color=clBlack;

                // eliminate artifacts
                ListBox1->Canvas->FillRect(Rect);

                DWORD dwAttr = GetFileAttributes(ListBox1->Items->Strings[Index].c_str());
                if(dwAttr == FILE_ATTRIBUTE_DIRECTORY)
                {
                        // color the line
                        ListBox1->Canvas->Brush->Color = clRed;
                        ListBox1->Canvas->FillRect(Rect);
                }
                // check for selection rectangle
                else if (State.Contains(odSelected))
                {
                        ListBox1->Canvas->Font->Color = clHighlightText;
                }
                else
                {
                        ListBox1->Canvas->Brush->Color = clGreen;
                        //ListBox1->Canvas->FillRect(TheRect);
                }

                // render the text
                ListBox1->Canvas->TextOut( Rect.Left, Rect.Top, ListBox1->Items->Strings[Index]);
}
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am

Re: ListBox items with different color

Postby rlebeau » Tue Oct 31, 2017 1:45 pm

mark_c wrote:Is there a better way without using the ListBox1DrawItem event and keeping the lbStandard Style?


No, you need to use owner-drawing for what you are attempting.

mark_c wrote:
Code: Select all
DWORD dwAttr = GetFileAttributes(ListBox1->Items->Strings[Index].c_str());
if(dwAttr == FILE_ATTRIBUTE_DIRECTORY)



That is not the correct way to check the flag. The return value is a bitmask, and folders (and files) can have multiple flags enabled, so you must use the bitwise AND (&) operator to test individual bits.

Also, GetFileAttributes() returns INVALID_FILE_ATTRIBUTES when it can't retrieve the attributes (like, say, when the directory is not found), so you have to account for that, too.

You should be doing something more like this instead:

Code: Select all
void __fastcall TForm1::ListBox1DrawItem(TWinControl *Control, int Index,
    TRect &Rect, TOwnerDrawState State)
{
    if (State.Contains(odSelected))
    {
        ListBox1->Canvas->Brush->Color = clHighlight;
        ListBox1->Canvas->Font->Color = clHighlightText;
    }
    else
    {
        DWORD dwAttr = GetFileAttributes(ListBox1->Items->Strings[Index].c_str());
        if ((dwAttr != INVALID_FILE_ATTRIBUTES) &&
            (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
        {
            ListBox1->Canvas->Brush->Color = clRed;
        }
        else
        {
            ListBox1->Canvas->Brush->Color = clGreen;
        }
        ListBox1->Canvas->Font->Color = clBlack;
    }

    ListBox1->Canvas->FillRect(Rect);

    ListBox1->Canvas->Font->Size = 12;
    ListBox1->Canvas->TextRect( Rect, Rect.Left, Rect.Top, ListBox1->Items->Strings[Index] );
}


Alternatively, the RTL has a DirectoryExists() function in the SysUtils unit:

Code: Select all
#include <SysUtils.hpp>

void __fastcall TForm1::ListBox1DrawItem(TWinControl *Control, int Index,
    TRect &Rect, TOwnerDrawState State)
{
    if (State.Contains(odSelected))
    {
        ListBox1->Canvas->Brush->Color = clHighlight;
        ListBox1->Canvas->Font->Color = clHighlightText;
    }
    else
    {
        if( DirectoryExists(ListBox1->Items->Strings[Index]) )
            ListBox1->Canvas->Brush->Color = clRed;
        else
            ListBox1->Canvas->Brush->Color = clGreen;
        ListBox1->Canvas->Font->Color = clBlack;
    }

    ListBox1->Canvas->FillRect(Rect);

    ListBox1->Canvas->Font->Size = 12;
    ListBox1->Canvas->TextRect( Rect, Rect.Left, Rect.Top, ListBox1->Items->Strings[Index] );
}
Last edited by rlebeau on Wed Nov 01, 2017 6:44 pm, edited 1 time in total.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: ListBox items with different color

Postby mark_c » Tue Oct 31, 2017 2:02 pm

Thank you Remy Lebeau
mark_c
BCBJ Veteran
BCBJ Veteran
 
Posts: 86
Joined: Thu Jun 21, 2012 1:13 am


Return to Technical

Who is online

Users browsing this forum: No registered users and 20 guests