Using 24bit Bitmap images with CListCtrl's Virtual List

Posted on 2006-05-08
Last Modified: 2013-11-20

I was using a list control to show online data on it. The data comes very fast and i was showing Data as well as image of 24 bit. but it flickers the view since i was custom drawing for each data.

To minimize this flickering,  now i am using virtual list of list control for fast retreival of data. it has a tremendous improovment, but there is one problem, it does show the 24bit bitmap on it. it converts it into grey color.

can anybody help me to sort out this problem?

For more information i am using

CListCtrl::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult) [ for fill up the virtual list]
CListCtrl::SetItemCount(int nCount) [ for set the number of rows to display ]

Thanks in advance

Question by:devendersys
    LVL 4

    Expert Comment

    Can you post your code?


    Author Comment

    Here is the code

    // VirtualListDlg.cpp : implementation file

    #include "stdafx.h"
    #include "VirtualList.h"
    #include "VirtualListDlg.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;

    // CVirtualListDlg dialog

    CVirtualListDlg::CVirtualListDlg(CWnd* pParent /*=NULL*/)
          : CDialog(CVirtualListDlg::IDD, pParent)
                // NOTE: the ClassWizard will add member initialization here
          // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
          m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    void CVirtualListDlg::DoDataExchange(CDataExchange* pDX)
          DDX_Control(pDX, IDC_COMBO_STYLE, m_style);
          DDX_Control(pDX, IDC_LIST, m_list);

    BEGIN_MESSAGE_MAP(CVirtualListDlg, CDialog)
          ON_BN_CLICKED(IDC_BUTTON_ADDTEN, OnButtonAddten)
          ON_BN_CLICKED(IDC_BUTTON_CLEAR, OnButtonClear)
          ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST, OnGetdispinfoList)
          ON_NOTIFY(LVN_ODFINDITEM, IDC_LIST, OnOdfinditemList)
          ON_NOTIFY(LVN_ODCACHEHINT, IDC_LIST, OnOdcachehintList)
          ON_CBN_SELCHANGE(IDC_COMBO_STYLE, OnSelchangeComboStyle)
          ON_NOTIFY(NM_CLICK, IDC_LIST, OnClickList)
          ON_NOTIFY(LVN_KEYDOWN, IDC_LIST, OnKeydownList)

    // CVirtualListDlg message handlers

    BOOL CVirtualListDlg::OnInitDialog()

          // Set the icon for this dialog.  The framework does this automatically
          //  when the application's main window is not a dialog
          SetIcon(m_hIcon, TRUE);                  // Set big icon
          SetIcon(m_hIcon, FALSE);            // Set small icon

          ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES );

          //Create image list
          m_imagelist.Create(IDB_BITMAP, 16, ILC_COLOR24, RGB(255, 255, 255));
          m_imagelistLarge.Create(IDB_BITMAP_LARGE, 32, ILC_COLOR4, RGB(255, 255, 255));
          m_list.SetImageList(&m_imagelist, LVSIL_SMALL);
          m_list.SetImageList(&m_imagelistLarge, LVSIL_NORMAL);
          m_list.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 130);
          m_list.InsertColumn(1, _T("Address"), LVCFMT_LEFT, 200);

          return TRUE;  // return TRUE  unless you set the focus to a control

    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.

    void CVirtualListDlg::OnPaint()
          if (IsIconic())
                CPaintDC dc(this); // device context for painting

                SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

                // Center icon in client rectangle
                int cxIcon = GetSystemMetrics(SM_CXICON);
                int cyIcon = GetSystemMetrics(SM_CYICON);
                CRect rect;
                int x = (rect.Width() - cxIcon + 1) / 2;
                int y = (rect.Height() - cyIcon + 1) / 2;

                // Draw the icon
                dc.DrawIcon(x, y, m_hIcon);

    // The system calls this to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CVirtualListDlg::OnQueryDragIcon()
          return (HCURSOR) m_hIcon;

    void CVirtualListDlg::OnButtonAddten()
          //Add 10 elements to the database
          for(int i=0; i<10; i++)
                m_database.push_back( CSampleData() );

          //Resize the list to add the elements to the list
          m_list.SetItemCount( m_database.size() );


    void CVirtualListDlg::OnButtonClear()
          //Clear database and list.



    void CVirtualListDlg::UpdateCount()
          CString temp;
          temp.Format(_T("%d items."), m_database.size());


    void CVirtualListDlg::OnSelchangeComboStyle()
          //Change list view style
          DWORD style = 0;

          switch( m_style.GetCurSel() )
                case 0:
                      style = LVS_ICON;
                case 1:
                      style = LVS_SMALLICON;

                case 2:
                      style = LVS_LIST;

                      style = LVS_REPORT;

          //Remove old style, and add new
          m_list.ModifyStyle(LVS_TYPEMASK, style);
          //Turn on/off check box
          if(style == LVS_ICON || style == LVS_SMALLICON)
                ListView_SetExtendedListViewStyleEx(m_list.m_hWnd, LVS_EX_CHECKBOXES, 0);
                ListView_SetExtendedListViewStyleEx(m_list.m_hWnd, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);

    //This function is called when the list needs data. This is the most
    //critical function when working with virtual lists.
    void CVirtualListDlg::OnGetdispinfoList(NMHDR* pNMHDR, LRESULT* pResult)
          LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;

          //Create a pointer to the item
          LV_ITEM* pItem= &(pDispInfo)->item;

          //Which item number?
          int itemid = pItem->iItem;

          //Do the list need text information?
          if (pItem->mask & LVIF_TEXT)
                CString text;

                //Which column?
                if(pItem->iSubItem == 0)
                      //Text is name
                      text = m_database[itemid].m_name;
                else if (pItem->iSubItem == 1)
                      //Text is slogan
                      text = m_database[itemid].m_slogan;

                //Copy the text to the LV_ITEM structure
                //Maximum number of characters is in pItem->cchTextMax
                lstrcpyn(pItem->pszText, text, pItem->cchTextMax);

          //Do the list need image information?
          if( pItem->mask & LVIF_IMAGE )
                //Set which image to use
                //Show check box?
                      //To enable check box, we have to enable state mask...
                      pItem->mask |= LVIF_STATE;
                      pItem->stateMask = LVIS_STATEIMAGEMASK;

                            //Turn check box on..
                            pItem->state = INDEXTOSTATEIMAGEMASK(2);
                            //Turn check box off
                            pItem->state = INDEXTOSTATEIMAGEMASK(1);

          *pResult = 0;

    //This functions is called when the user "writes" in the list box to find an item.
    void CVirtualListDlg::OnOdfinditemList(NMHDR* pNMHDR, LRESULT* pResult)
          // pNMHDR has information about the item we should find
          // In pResult we should save which item that should be selected

          /* pFindInfo->iStart is from which item we should search.
             We search to bottom, and then restart at top and will stop
             at pFindInfo->iStart, unless we find an item that match

          // Set the default return value to -1
          // That means we didn't find any match.
          *pResult = -1;

          //Is search NOT based on string?
          if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
                //This will probably never happend...

                Let's look on a sample list;
                * Anna

                Anna is selected.
                If "A" is written, Annika should be selected.
                If "AND" is written, Anders should be selected.
                If "ANNK" is written, the selection should stay on Anna.
                If "E" is written, Emma should be selected.


          //This is the string we search for
          CString searchstr = pFindInfo->lvfi.psz;

    //      TRACE(_T("Find: %s\n"), searchstr);
          int startPos = pFindInfo->iStart;
          //Is startPos outside the list (happens if last item is selected)
          if(startPos >= m_list.GetItemCount())
                startPos = 0;

          int currentPos=startPos;
          //Let's search...
                //Do this word begins with all characters in searchstr?
                if( _tcsnicmp(m_database[currentPos].m_name, searchstr, searchstr.GetLength()) == 0)
                      //Select this item and stop search.
                      *pResult = currentPos;

                //Go to next item

                //Need to restart at top?
                if(currentPos >= m_list.GetItemCount())
                      currentPos = 0;

          //Stop if back to start
          }while(currentPos != startPos);            

    //This is called to give you a chance to catch data. Useless in most cases :-)
    void CVirtualListDlg::OnOdcachehintList(NMHDR* pNMHDR, LRESULT* pResult)

    /*      TRACE(      _T("Chache item %d to item %d\n"),
                      pCacheHint->iTo );*/

          //... cache the data pCacheHint->iFrom to pCacheHint->iTo ...

          *pResult = 0;

    void CVirtualListDlg::ToggleCheckBox(int item)
          //Change check box
          m_database[item].m_checked = !m_database[item].m_checked;

          //And redraw
          m_list.RedrawItems(item, item);

    //This is called when user clicks on the list.
    //If you had check box you have to write code to make them possible to toggle.
    void CVirtualListDlg::OnClickList(NMHDR* pNMHDR, LRESULT* pResult)

          LVHITTESTINFO hitinfo;
          //Copy click point
 = pNMListView->ptAction;

          //Make the hit test...
          int item = m_list.HitTest(&hitinfo);

          if(item != -1)
                //We hit one item... did we hit state image (check box)?
                //This test only works if we are in list or report mode.
                if( (hitinfo.flags & LVHT_ONITEMSTATEICON) != 0)

          *pResult = 0;

    //This is called when a key i pressed down
    void CVirtualListDlg::OnKeydownList(NMHDR* pNMHDR, LRESULT* pResult)
          LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR;

          //If user press space, toggle flag on selected item
          if( pLVKeyDown->wVKey == VK_SPACE )
                //Check if check boxes are visible
                if( IsCheckBoxesVisible() )
                      //Toggle if some item is selected
                      if(m_list.GetSelectionMark() != -1)
                            ToggleCheckBox( m_list.GetSelectionMark() );
          *pResult = 0;

    BOOL CVirtualListDlg::IsCheckBoxesVisible()
          DWORD style = m_list.GetStyle();

          if( ((style & LVS_TYPEMASK) == LVS_LIST) ||
                ((style & LVS_TYPEMASK) == LVS_REPORT) )
                      return TRUE;

          return FALSE;

    Author Comment

    Hi Amit,

    Is there any luck?

    LVL 22

    Expert Comment

    Have you referred this how its implemented ..

    Your code seems to be same as above.. Tried to change above for 24 bit images ?


    Author Comment

    This code snippet is from the link above, but even it does not work for 24Bit Bitmaps. I am using this code for testing. you can check it for by changing the defult bitmap to 24bit Bitmap, and you can see the difference. the icon will be shown in grey scale.

    LVL 4

    Accepted Solution

    Hi Devendar,

    this was your code

    //Create image list
    m_imagelist.Create(IDB_BITMAP2, 640, ILC_COLOR4, RGB(255, 255, 255));

    Why don't you use this code?

    load the 24 bitmap in the CBitmap object
          m_imagelist.Create(640, 480, ILC_COLOR24,0, 4);
          m_imagelist.Add(&m_bitmap, RGB(255, 255, 255));

    I tried and it worked


    Author Comment

    its works great.

    Thanks a lot amit.


    Featured Post

    Why You Should Analyze Threat Actor TTPs

    After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

    Join & Write a Comment

    Suggested Solutions

    Title # Comments Views Activity
    Question regarding Copy/Paste 16 83
    List out all word 7 190
    centeredAverage challenge 8 89
    FizzBuzz challenge 9 65
    Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
    Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
    This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
    This video discusses moving either the default database or any database to a new volume.

    734 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

    Need Help in Real-Time?

    Connect with top rated Experts

    21 Experts available now in Live!

    Get 1:1 Help Now