Page 1 of 1

Microsoft : Working With Listboxes - Part II Owner drawn listboxes Rate Topic: -----

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 23 March 2010 - 11:39 PM

Microsoft : Working With Listboxes - Part II

Introduction

The second part of this tutorial looks at ownerdrawn listboxes. These listboxes can be simple listboxes with strings or can be some arbitary structure containing data.

Ownerdrawn string listboxes

If we specify an ownerdrawn listbox with strings, the memory for the strings is allocated and managed internally by the listbox, but the actual drawing of the string is not. There are two types of ownerdrawn listboxes, fixed height ownerdrawn and variable height ownerdrawn. To create a fixed height ownerdrawn listbox, we would use the following:

    listbox_handle = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
                                    WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                                    LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED |
                                    LBS_HASSTRINGS | LBS_SORT,   
                                    10, 10, width-20,
                                    height-20, window_handle, (HMENU)11,   
                                    instance_handle, NULL);



During the creation of the window, it will send a WM_MEASUREITEM message to the parent window requesting the height of the items in the listbox. Then when each item needs to be drawn, a WM_DRAWITEM message is sent to the parent window.

To create a variable height ownerdrawn listbox, we would use the following:

    listbox_handle = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
                                    WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                                    LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED |
                                    LBS_HASSTRINGS | LBS_SORT,   
                                    10, 10, width-20,
                                    height-20, window_handle, (HMENU)11,   
                                    instance_handle, NULL);



Each time a line in the listbox needs drawing, it will send a WM_MEASUREITEM message to the parent window requesting the height of the item in the listbox followed by a WM_DRAWITEM message to draw the line.

Strings are added, and deleted just as described in the tutorial Microsoft : Working With Listboxes - Part I.

Ownerdrawn listboxes without strings

If we specify an ownerdrawn listbox without strings, the memory for the strings is allocated and managed internally by our code, as is the actual drawing of the data. Again, there are two types of ownerdrawn listboxes, fixed height ownerdrawn and variable height ownerdrawn. To create a fixed height ownerdrawn listbox, we would use the following:

    listbox_handle = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
                                    WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                                    LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED,   
                                    10, 10, width-20,
                                    height-20, window_handle, (HMENU)11,   
                                    instance_handle, NULL);



During the creation of the window, it will send a WM_MEASUREITEM message to the parent window requesting the height of the items in the listbox. Then when each item needs to be drawn, a WM_DRAWITEM message is sent to the parent window.

To create a variable height ownerdrawn listbox, we would use the following:

    listbox_handle = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
                                    WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
                                    LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED,   
                                    10, 10, width-20,
                                    height-20, window_handle, (HMENU)11,   
                                    instance_handle, NULL);



Each time a line in the listbox needs drawing, it will send a WM_MEASUREITEM message to the parent window requesting the height of the item in the listbox followed by a WM_DRAWITEM message to draw the line.

Adding data to a non-string listbox

To add data to a non-string listbox, we use the LB_ADDSTRING or LB_INSERTSTRING messages, but instead of a string, we use a pointer to the data that will be used to draw the listbox line.

We can use the LB_GETITEMDATA and LB_SETITEMDATA messages to retrieve or set item data.

Example Code

The following code example displays a listbox with unsorted items that are owner drawn.

#include <windows.h>  
#include <CommCtrl.h> 
#include <ctime>  
#include <cstdlib>  
using namespace std;

#pragma comment(lib, "comctl32.lib")

class frame_window {  
    private:
        LPWSTR window_class_name;  
        HINSTANCE instance_handle;  
        HCURSOR cursor_arrow;  
        HWND window_handle;
        HWND listbox_handle;
        RECT client_rectangle;
        int pressed;
    public:
        frame_window(LPWSTR window_class_identity) : window_class_name(window_class_identity), pressed(-1) {  
            int screen_width = GetSystemMetrics(SM_CXFULLSCREEN);  
            int screen_height = GetSystemMetrics(SM_CYFULLSCREEN);  
            instance_handle = GetModuleHandle(NULL);  
               
            WNDCLASS window_class = { CS_OWNDC, main_window_proc, 0, 0,    
                                      instance_handle, NULL,    
                                      NULL, NULL, NULL,    
                                      window_class_name };   
            
            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
            // Create a standard frame window   
            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
            
            RegisterClass(&window_class);   
            window_handle = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,    
                                           window_class_name,    
                                           L"Listbox Example",   
                                           WS_OVERLAPPEDWINDOW | 
                                           WS_CLIPCHILDREN | WS_CLIPSIBLINGS,   
                                           300, 300, screen_width-600,    
                                           screen_height-600, NULL, NULL,   
                                           instance_handle, NULL);
            RECT client_rectangle;
            GetClientRect(window_handle, &client_rectangle);
            int width = client_rectangle.right - client_rectangle.left;
            int height = client_rectangle.bottom - client_rectangle.top;
            listbox_handle = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
                                            WS_CHILD | WS_VISIBLE | WS_VSCROLL | LBS_NOSEL |
                                            LBS_DISABLENOSCROLL | LBS_OWNERDRAWFIXED,   
                                            10, 10, width-20,
                                            height-20, window_handle, (HMENU)11,   
                                            instance_handle, NULL);
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"mark.bottomley");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"megamu");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Bench");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Cerolobo");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"CyanBlue");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"DilutedImage");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"g00se");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"gregoryH");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"ajwsurfer");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"baavgai");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"CTphpnwb");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Dogstopper");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"eclipsed4utoo");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Gloin");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"gregwhitworth");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"GWatt");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"KevinADC");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"mostyfriedman");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"n8wxs");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"perfectly.insane");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"letthecolorsrumble");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"lockdown");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Martyn.Rae");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Martyr2");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"pbl");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"PennyBoki");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Programmist");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"macosxnerd101");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"mocker");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"MorphiusFaydal");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"thava");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Ancient Dragon");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"EdwinNameless");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"erik.price");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"wildgoose");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"FlashM");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Fuzzyness");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Arbitrator");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"malkiri");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"red01");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"MentalFloss");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"japanir");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"joeyadms");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"mikeblas");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"reyco1");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"RodgerB");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"runtime error");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"ScottAdams");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"ShaneK");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"SwiftStriker00");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"horace");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"janotte");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"akozlik");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"Voodoo Doll");
            SendMessage(listbox_handle, LB_ADDSTRING, 0, (LPARAM)L"WolfCoder");
            int index = SendMessage(listbox_handle, LB_FINDSTRING, 0, (LPARAM)L"Martyn.Rae");
            SendMessage(listbox_handle, LB_SETCURSEL, index, 0);
            SetCursor(LoadCursor(NULL, IDC_ARROW)); 
            SetWindowLongPtr(window_handle, GWL_USERDATA, (LONG)this);  
            ShowWindow(window_handle, SW_SHOW);   
            UpdateWindow(window_handle); 
        }  
        ~frame_window() {  
            UnregisterClass(window_class_name, instance_handle);   
        }  
        
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
        // Windows message processing function   
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
        static LRESULT WINAPI main_window_proc(HWND window_handle, UINT message,    
                                               WPARAM wparam, LPARAM lparam) {  
            frame_window *This = (frame_window *)GetWindowLongPtr(window_handle, GWL_USERDATA);  
            switch ( message ) {  
                case WM_PAINT:   
                {   
                    PAINTSTRUCT paint_structure;   
                    RECT client_rect;   
                    HDC paint_device_context, paint_dc;   
                    HBITMAP bitmap;   
  
                    paint_device_context = BeginPaint(window_handle, &paint_structure);   
                    paint_dc = CreateCompatibleDC(paint_device_context);   
                    GetClientRect(window_handle, &client_rect);   
                    int window_width = client_rect.right - client_rect.left;  
                    int window_height = client_rect.bottom - client_rect.top;  
                    bitmap = CreateBitmap(window_width, window_height, 1, 32, NULL);  
                    HGDIOBJ old_bitmap = SelectObject(paint_dc, bitmap);  
  
                    // Fill the client aread with the user selected face colour  
                    HBRUSH light_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));  
                    FillRect(paint_dc, &paint_structure.rcPaint, light_brush);  
                    DeleteObject(light_brush);  
                                                                            
                    BitBlt(paint_device_context, 0, 0,    
                           client_rect.right-client_rect.left,   
                           client_rect.bottom-client_rect.top,   
                           paint_dc, 0, 0, SRCCOPY);   
                    SelectObject(paint_dc, old_bitmap);   
                    DeleteObject(bitmap);   
                    DeleteDC(paint_dc);   
                    EndPaint(window_handle, &paint_structure);   
                    return 0;   
                }   
                case WM_ERASEBKGND:   
                {   
                    return TRUE;   
                }
                case WM_MEASUREITEM:
                {
                    LPMEASUREITEMSTRUCT measure_item = (LPMEASUREITEMSTRUCT)lparam;
                    RECT client_rectangle;
                    GetClientRect(window_handle, &client_rectangle);
                    int width = client_rectangle.right - client_rectangle.left;
                    measure_item->itemHeight = 20;
                    measure_item->itemWidth = width;
                    return true;
                }
                case WM_DRAWITEM:
                {
                    LPDRAWITEMSTRUCT draw_item = (LPDRAWITEMSTRUCT)lparam;
                    DrawText(draw_item->hDC, (LPWSTR)draw_item->itemData, 
                             wcslen((LPWSTR)draw_item->itemData), &draw_item->rcItem, 
                             DT_CENTER);
                    return TRUE;
                }
                case WM_SIZE:   
                {
                    RECT client_rectangle;
                    GetClientRect(window_handle, &client_rectangle);
                    int width = client_rectangle.right - client_rectangle.left;
                    int height = client_rectangle.bottom - client_rectangle.top;
                    InvalidateRect(window_handle, NULL, TRUE);   
                    return 0;   
                }
                case WM_COMMAND:
                {
                    return 0;
                }
                case WM_CLOSE:   
                {   
                    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                    // The user wants to close the window   
                    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
           
                    PostQuitMessage(0);   
                    return 0;   
                }   
            }   
            return DefWindowProc(window_handle, message, wparam, lparam);   
        }   
          
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
        // Windows message loop   
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        void run() {  
            MSG window_message;   
            while ( GetMessage(&window_message, NULL, 0, 0) ) {   
                TranslateMessage(&window_message);   
                DispatchMessage(&window_message);   
            }   
        }  
};  
   
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
// Windows main entry point   
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++   
   
int WINAPI wWinMain(HINSTANCE instance_handle, HINSTANCE, LPWSTR, INT) {  
    frame_window main_window(L"my base window");  
    main_window.run();  
    return 0;   
}



Is This A Good Question/Topic? 2
  • +

Replies To: Microsoft : Working With Listboxes - Part II

#2 Aphex19  Icon User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 614
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Posted 23 July 2010 - 09:31 PM

Thanks, this was very helpful :bigsmile:

Great work!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1