Click here to Skip to main content
Click here to Skip to main content

Win32 Listview Class

By , 23 Apr 2012
Rate this:
Please Sign up or sign in to vote.

Introduction

This article is designed to introduce a developer to the Win32 Listview control object and how to create a small simple class for control over it. It is the hope of the author to help developers alleviate certain pains taken when creating a Listview object. While intended for the Win32 beginner, this article can not only be a nice suggestion for, but also a refresher for intermediate and advanced programmers. This article expects that the user is familiar with the Windows message pump and knows how to handle messages sent to the window. 

Background 

In my beginner phase of programming (specifically Win32), I found it rather difficult to learn some of the coding procedures/Win32 control objects when they should be all too simple. It is my philosophy that the simpler, the better. Even if the design is totally complex, once you have a proper understanding, it should be all too simple. Yet, even with a proper understanding of the object, I still found myself spending hours on programming one object when it should have taken an hour, if not a half-hour. So with that, I decided to create a class object to handle a Listview control and will be presenting it here.

Using the code

Here I will present a Win32 Listview class. This class is designed to help a developer not only speed up the development time spent on a program but to also alleviate certain pains taken when dealing with Listview controls. 

While my Listview class encompasses a little more than what is presented, below is the basis of my Listview class declaration. Additionally, I have defined this code in a separate .h and .cpp file for modability - so it can be used by more than one program. I suggest you do the same.
class listview //for creating, drawing, and overall control over a listview control
{
    private:
        HWND handle; //handle to the listview object (where all sendmessage cmds go)
        LVCOLUMN lvc; //for manipulating the columns in the control
        LVITEM lvi; //for manipulating the items in the control
    public:
        HWND create(int x, int y, int width, int height, char* styles, HWND pwnd);
        HWND createfromresource(HWND pwnd, UINT id);
        void setexstyles(char* styles);
        bool addcolumn(int index, int width, char* title);
        bool additem(int index, int subindex, char* value);
        void clear(void);
        bool isselected(int index, int subindex);
        int getselectedcount(void);
};

The variables and routines declared should be easy enough to understand but I shall delve a bit more into them for clarification. If you're not familiar with it, I'll point it out here: the private call tells the program to restrict access of the following vars and routines to only the class's code access - meaning if you try to reference it outside of class definitions, you'll get errors; the public call tells the program to allow access everywhere, so long as the code is referencing it correctly.

In the private declaration of the class we have a HWND, LVCOLUMN, and LVITEM.

  • The HWND is a handle to the ListView control and provides us a way to communicate our desires to the ListView control. In this way we can talk to it regardless if it is a dialog item or a window created with CreateWindowEx. We return the handle from create and createfromresource so if this class doesn't provide a certain kind of function, it can still be performed if you create a local or global HWND and pass it to it.
  • The LVCOLUMN is a typedef struct created for us by Windows and basically handles all the properties a column would need in a Listview control. Note that you don't have to have one LVCOLUMN struct per column in the Listview control (meaning no arrays).
  • The LVITEM is a typedef struct also created for us by Windows which handles all the properties of an item set up on the list. Note that you don't have to have one LVITEM struct per item in the Listview control (meaning no arrays).

In the puplic declaration of the class the following routines (I'll provide a quick intro to them here too) are as follows:

  • HWND create(int x, int y, int width, int height, char* styles, HWND pwnd); -- This function will create the ListView control using CreateWindowEx. This enables us to create a Listview control in our program which won't require a DialogBox interface, should it be that is what is desired.  
  • HWND createfromresource(HWND pwnd, UINT id); -- I hope this one is obvious. This routine will return the handle to a DialogBox Listview control item so we can use it. 
  • void setexstyles(char* styles); -- This one might not be as obvious. If we can specify our styles when we use CreateWindowEx or during design time on the DialogBox resource in our environment, why do we need a setexstyles routine? Firstly, when we call our create routine, it does not set the extended styles. Secondly, during design time we cannot (for some unknown reason) set the extended styles on the Listview control. So, as a programmer who uses his brain, I created this function for simplisity's sake: regardless the handle (whether created from create or createfromresource) we can set the extended styles. This function is mainly directed at the DialogBox Listview control dysfunctionality but to save myself the headache of creating the extended styles in the create routine and for brevity of my code, this line serves perfectly for both kinds of Listveiw controls. 
  • bool addcolumn(int index, int width, char* title); -- I hope this is another easy one. This will create a column for us with the specified title and width at the specified index (0-based).
  • bool additem(int index, int subindex, char* value); -- This will create an item at the specified position with the specified text. Index is the row position, subindex the column position (again, 0-based).
  • void clear(void); -- What are we clearing here? The entire Listview control. This function will use the LVM_DELETEALLITEMS message to do the job. 
  • bool isselected(int index, int subindex); -- This will ask the Listview control if the specified object is highlighted. This works excellently for multiselect Listview controls; simply put it in a for loop and with the help of a LVM_GETITEMCOUNT message and you can get the indexes of all selected items.  
  • int getselectedcount(void); -- returns to us the number of selected (highlighted) items on the Listview control. 

 Now we get into the code. Here we will define your class routines, and then we'll move on to the window procedure we'll use to control the Listview object. 

HWND listview::create(int x, int y, int width, int height, char* styles, HWND pwnd)
{
    DWORD flags = WS_VISIBLE | WS_CHILD;

    //find the normal styles
    if(strstr(styles, "report"))
    {
        flags |= LVS_REPORT;
    }

    if(strstr(styles, "showsel") || strstr(styles, "show sel"))
    {
        flags |= LVS_SHOWSELALWAYS;
    }

    if(strstr(styles, "border"))
    {
        flags |= WS_BORDER;
    }

    if(strstr(styles, "tab"))
    {
        flags |= WS_TABSTOP;
    }

        //todo - look for more styles to set

    handle = CreateWindowEx(0, WC_LISTVIEW, "", flags, x, y, 
                            width, height, pwnd, NULL, hinst, NULL);
    return(handle);
}

HWND listview::createfromresource(HWND pwnd, UINT id)
{
    handle = GetDlgItem(pwnd, id);
    return(handle);
}

void listview::setexstyles(char* styles)
{
    DWORD exflags=WS_EX_LEFT;

    //find the extended styles
    if(strstr(styles, "fullrow") || strstr(styles, "fullrowsel") || 
       strstr(styles, "full row") || strstr(styles, "full sel"))
    {
        exflags |= LVS_EX_FULLROWSELECT;
    }

    if(strstr(styles, "header"))
    {
        exflags |= LVS_EX_HEADERINALLVIEWS;
    }

    if(strstr(styles, "overflow"))
    {
        exflags |= LVS_EX_COLUMNOVERFLOW;
    }

        //todo - find more extended styles

    if(handle)
    {
        SendMessage(handle, LVM_SETEXTENDEDLISTVIEWSTYLE, exflags, exflags);
        //set the extended styles here because it doesn't work in the CreateWindowEx
    }
}

bool listview::addcolumn(int index, int width, char* title)
{
    bool success = FALSE;

    lvc.mask = LVCF_WIDTH | LVCF_TEXT;
    lvc.cx = width;
    lvc.cchTextMax = strlen(title);
    lvc.pszText = title;

    if(SendMessage(handle, LVM_INSERTCOLUMN, index, (LPARAM)&lvc) != -1)
    {
        success = TRUE;
    }

    return(success);
}

bool listview::additem(int index, int subindex, char* value)
{
    bool success=FALSE;

    lvi.mask = LVIF_TEXT;
    lvi.iItem = index;
    lvi.iSubItem = subindex;
    lvi.cchTextMax = strlen(value);
    lvi.pszText = value;

    if(subindex != 0)
    {
        success = (bool)SendMessage(handle, LVM_SETITEM, 0, (LPARAM)&lvi);
    }else{
        if(SendMessage(handle, LVM_INSERTITEM, 0, (LPARAM)&lvi) != -1)
        {
            success = TRUE;
        }
    }

    return(success);
}

void listview::clear(void)
{
    SendMessage(handle, LVM_DELETEALLITEMS, 0, 0);
}

bool listview::isselected(int index, int subindex)
{
    bool ishigh=FALSE;

    lvi.mask = LVIF_STATE;
    lvi.iItem = index;
    lvi.iSubItem = subindex;
    lvi.stateMask = LVIS_SELECTED;
    SendMessage(handle, LVM_GETITEM, 0, (LPARAM)&lvi);

    if(lvi.state == LVIS_SELECTED)
    {
        ishigh = TRUE;
    }
    return(ishigh);
}

int listview::getselectedcount(void)
{
    return(SendMessage(handle, LVM_GETSELECTEDCOUNT, 0, 0));
}
 

Now the window proc. Under your main window procedure (we are assuming you are designing a Win32 program using CreateWindowEx), you'll want to initialize the Listview control, set up the columns, and start adding items. Additionally, although I do not manipulate them, I will show you how to get to the Listview control notification messages for your window so you can manipulate them as you see fit.

//first define some globals
int index=0, itemnum=0, colnum=0;
char af[100]="";
/////////////////////////////////////////////////////////////////////////
//MAIN WINDOW PROCEDURE
/////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    int rval=DefWindowProc(hwnd, msg, wp, lp);

    switch(msg)
    {
        case WM_CREATE:
            list.create(5, 5, 0, 0, "tab border report showsel", parent);
            list.setexstyles("fullrow header overflow");
            list.addcolumn(0, 140, "Column One");
            list.addcolumn(1, 140, "Column Two");
            break;
        case WM_NOTIFY:
            switch( (((NMHDR*)lp)->code) )
            {
                case NM_DBLCLK: //add item
                                        sprintf(af, "Item %d", index);
                                        list.additem(index, 0, af);
                                        list.additem(index++, 1, "Subitem 1");
                                        //++ puts it at the index location and then increments
                    break;
                case NM_RCLICK: //todo
                    break;
                case LVN_COLUMNCLICK: //user clicked a column - get the column number
                    colnum = ((LPNMLISTVIEW)lp)->iSubItem;
                    break;
                case LVN_ITEMCHANGED: //user clicked a different item
                    itemnum = ((LPNMLISTVIEW)lp)->iItem;
                    break;
            }
            break;
        case WM_CLOSE:
            PostQuitMessage(WM_QUIT);
            break;
    }

    return(rval);
}

And that's it! Now you should have a very flexible piece of code with which to work. You can add routines and specifics to it (do try to ensure it remains as flexible as possible) and you now can have full control over Listview Control items! Congratulations!

The Challenge

Something I think you might be interested in which I know I did not cover here: ImageLists. I know I did not cover them and I did it because I did not want the beginner programmer to become overwhelmed by it. I might later add another article with improvements to the Listview class we've created here, but I am sometimes of the opinion that when learning it online, everything's just copy-paste and the programmer learns nothing. In this way I present a challenge to all beginner programmers to add the ImageList functionality to the class for their programs.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

suendisra
Software Developer
United States United States
I have been programming in C since 2004. Even with what I know now, I find that I am continually learning very rewarding stuff every single day.

Comments and Discussions

 
Questionhi,about listview sort! Pinmemberforcj92813-Nov-13 15:11 
AnswerRe: hi,about listview sort! Pinmembersuendisra17-Nov-13 13:37 
Question[My vote of 2] A lot of problems in this "class" implementation PinmemberVictor Nijegorodov18-Apr-12 6:35 
AnswerRe: [My vote of 2] A lot of problems in this "class" implementation Pinmembersuendisra23-Apr-12 7:40 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation PinmemberVictor Nijegorodov23-Apr-12 8:05 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation Pinmembersuendisra23-Apr-12 8:53 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation PinmemberJohnWallis4223-Apr-12 17:39 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation Pinmembersuendisra23-Apr-12 18:10 
AnswerRe: [My vote of 2] A lot of problems in this "class" implementation PinmemberJohnWallis4224-Apr-12 1:23 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation Pinmembersuendisra24-Apr-12 7:20 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation PinmemberVictor Nijegorodov23-Apr-12 21:38 
GeneralRe: [My vote of 2] A lot of problems in this "class" implementation Pinmembersuendisra24-Apr-12 4:43 
SuggestionRe: [My vote of 2] A lot of problems in this "class" implementation PinmemberDaniele Rota Nodari9-Oct-12 9:48 
QuestionNice article on writing C classes Pinmemberbitterskittles17-Apr-12 0:00 
AnswerRe: Nice article on writing C classes PinmemberVictor Nijegorodov18-Apr-12 4:37 
GeneralRe: Nice article on writing C classes Pinmemberbitterskittles18-Apr-12 4:46 
GeneralRe: Nice article on writing C classes PinmemberVictor Nijegorodov18-Apr-12 4:51 
GeneralRe: Nice article on writing C classes Pinmemberbitterskittles18-Apr-12 6:03 
QuestionWhy on earth... Pinmemberwaleri15-Apr-12 19:44 
AnswerRe: Why on earth... Pinmembersuendisra16-Apr-12 7:33 
GeneralRe: Why on earth... Pinmemberbitterskittles16-Apr-12 23:56 
GeneralRe: Why on earth... Pinmembersuendisra17-Apr-12 7:54 
GeneralRe: Why on earth... Pinmemberwaleri17-Apr-12 19:05 
GeneralRe: Why on earth... [modified] Pinmembersuendisra18-Apr-12 6:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 23 Apr 2012
Article Copyright 2012 by suendisra
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid