The Wayback Machine - https://web.archive.org/web/20100512061605/http://www.codeguru.com:80/cpp/controls/treeview/misc-advanced/article.php/c3993/Using-TreeControl-TreeView-under-Win32-API-No-MFC.htm

    Using TreeControl (TreeView) under Win32 API (No MFC)

    • 1

    Environment: Win32 API (non-MFC code), Visual C++ 6

    Introduction

    Hi, all you Win32 Coders, and happy new year to you all! This article is for those who did not find any useful code examples and information regarding TreeControl (TreeView).

    This time, I wanted to add a simple Tree Control into my application, and whaa!! NO SOURCE CODE!!... <== ?? "Hey, what do mean by that?", Well, let me rephrase: Go to your all-time fancy programming Web page, such as www.codeguru.com, and try to find a single article that explains how to add a simple tree control and its data, you guessed - there are none!! Ahh, this really helps us, no?

    As you can see, this is what makes me so mad about programmers; they add only part of the code and the code itself mainly doesn't really fit our needs because they didn't even bother to explan the basics. Well, here I am; I will teach/show you how FINALLY we can do some real coding. I want to say a really huge thanx to Icezelion. His Win32ASM site is really cool, and helpful of course. His examples really showed me how to add a tree control into Visual C, even if he is doing it under Assembly, because APIs are APIs!!

    Enough talk. Let's start.

    #include <commctrl.h>

    Add it into your c/cpp file so we can use its functions/#define's. We add a TreeControl to our dialog (you can also create it via the CreateWindowEx API!). Once we've named it, IDC_TREE1, we will add properties to our TreeControl that will define the way the tree is shown in visual terms.

    Properties

       -- Resource --        -- CreateWindow/EX --
            |                          |
    1. Has Buttons          - TVS_HASBUTTONS       ; we can see the
                                                   ; lines [-]/[+]
                                                   ; of the tree.
    2. Has Lines            - TVS_HASLINES         ; we see the
                                                   ; ---- of the tree.
    3. Lines at Root        - TVS_LINESATROOT      ; root can have
                                                   ; lines attaching
                                                   ; them.
    4. Disable Drag&Drop    - TVS_DISABLEDRAGDROP  ; no need to drag &
                                                   ; drop now [unless
                                                   ; you need it]
    5. Track Select         - TVS_TRACKSELECT      ; nice blue effect
                                                   ; when mouse is
                                                   ; over
    6. Single Expand        - TVS_SINGLEEXPAND     ; expand tree at
                                                   ; one time
    7. Full Row Select      - TVS_FULLROWSELECT    ; select the whole
                                                   ; row [text..etc]
    8. Border               - WS_BORDER            ; heh..border
    9. Scroll                                      ; scrollbars...

    We now have our TreeControl placed in our dialog. Try to compile it. All's fine, but try to run the exe. Whoopps!!! No load?!? Well, because I am using Windows 2000, it doesn't work. I haven't checked it under Windows 98. But anyway, it doesn't run because our control isn't intialized. Let's intialize it:

    case WM_INITDIALOG:
    {
       InitCommonControls();     // make our tree control work
       .....
       .....
    }
    

    To make sure we're using this function (above), we need to add a lib file called:

    comctl32.lib

    We add this lib file in the project settings -> link tab -> object/library modules. Try to compile and run. It should work now!!. If not, hm, try to look at MSDN!

    Tree Pictures

    Ahh, this is very neat and nice looking. Look at the WorkSpace tab. It has a tree view with nice folders attached to it, right? The picture has two states: 1. closed folder and 2. opened folder. This is what we want when out tree is expanded/closed, a nice folder pic. For this, we use a bitmap with a drawing of the two states. In the source code, you can have a look on how it looks. For adding the pictures, we need to know how it will work. Basically, it is very easy. We draw the states of the folder near each other, and this will be like an array. Neat, eh? To convert the picture into an array to be used, we use three functions:

    ImageList_Create();    // function creates a new image list.
    ImageList_Add();       // function adds an image or images
                           // to an image list
    LoadBitmap();          // function loads the specified
                           // bitmap resource
    

    A quick look at Win32.hlp/MSDN will give us all the necessary info we need to use it.

    Starting with the first function, we first need to know that it is returning a handle. The return value is the type of HIMAGELIST struct.

        HIMAGELIST hImageList;

    Now we can use our first function, like this:

    hImageList=ImageList_Create(16,16,ILC_COLOR16,2,10);
        // 16x16:16bit with 2 pics [array]
    
    // Return Value:
    // If the function succeeds, the return value is the handle
    // to the image list.
    // If the function fails, the return value is NULL
    

    Okay, so we created an image list of two pictures with a size of 16x16 pixels, in a quality of 16-bit, and returns the handle to the new image list! Now, we need to actually load the image [bmp] to the resource.

    Loading a BMP into the Resource

    1. From the main menu bar, choose Insert.
    2. Choose Resource (or just click Ctrl+R).
    3. Select Bitmap and press Import
    4. Choose the bmp and click OK.
    5. Rename it to fit your needs.

    That wasn't a problem. now we need to load via code: for every bitmap [bmp] loading, we need a handle, such a struct that can identify/recognize the bitmap's file header. For that we use the HBITMAP struct. The loading is done like this:

      HBITMAP hBitMap;    // bitmap handler
      hBitMap=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_TREE));
      // load the picture from the resource
    
    Note: MAKEINTRESOURCE will make sure to convert the picture to the resource type. Once it is loaded (check return value; if NULL, it has failed!), we now can add the picture to our image list by using the last function:
    ImageList_Add(hImageList,hBitMap,NULL);    // Attach the image
                                               // to the image list
    

    We can safely delete the bitmap handle because it is an object and it takes memory space:

    DeleteObject(hBitMap);                     // free memory!
    

    The last thing we have to do is to send it all to the tree control via the SendMessage() or the SendDlgItemMessage(). I usually use the second option, but there is no difference at all except that the first is shorter.

    SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SETIMAGELIST,0,
                      (LPARAM)hImageList);
    

    All the theoritical info has been said. Now, it's more code demostrations with side remarks.

    The TV_INSERTSTRUCT Struct

    This struct will help us insert parent/child items into the tree control. Treating tree controls is the same as list controls, just with different members. Let us make a new handler:

    TV_INSERTSTRUCT tvinsert;    // struct to config out the
                                 // tree control
    
    // Now, we need to intialize this struct:
    // Global Vars:
    HTREEITEM Parent;    // Tree item handle
    HTREEITEM Before;    // .......
    HTREEITEM Root;      // .......
    // .....
    // .....
    // Code:
    tvinsert.hParent=NULL;               // top-most level Item
    tvinsert.hInsertAfter=TVI_ROOT;      // root level item attribute
    tvinsert.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
                                         // attributes
    tvinsert.item.pszText="Parent";      // item text
    tvinsert.item.iImage=0;              // not pressed pic
    tvinsert.item.iSelectedImage=1;      // pressed pic
    Parent=(HTREEITEM)SendDlgItemMessage
           (hWnd,IDC_TREE1,TVM_INSERTITEM,0,(LPARAM)&tvinsert);
    

    Note the global variables. We declaired three variables with the type of HTREEITEM. To use items, we must have the last/first inserted items, so those will be our root level handlers. Okay, the intialization part is really straightforward, but the interesting parts are:

    tvinsert.hParent=NULL;  // because it's a root item, we don't
                            // specify Parent [handle]
    
    tvinsert.hInsertAfter=TVI_ROOT;
                            // this will make the item appear as a
                            // root item
    HTREEITEM Parent=(HTREEITEM)SendDlgItemMessage
              (hWnd,IDC_TREE1,TVM_INSERTITEM,0,(LPARAM)&tvinsert);
    

    In the last code section, we send the struct address to the tree control via the TVM_INSERTITEM message. To insert a new item to the tree control, the Parent=(HTREEITEM) is the return type of the Parent handle. This means that now that we have the parent of the first root, we can make a child item! To add a child item, it is really the same idea, but with few new code items:

    tvinsert.hParent=Parent;           // create a child for our parent
    tvinsert.hInsertAfter=TVI_LAST;    // put it under [ last item ]
    tvinsert.item.pszText="Child 1";   // name it whatever you want
    Parent=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
            TVM_INSERTITEM,0,(LPARAM)&tvinsert);
    // draw it, and save the parent for more child making
    

    Now, because it is a hierarchy, I have used two more HTREEITEM valiables named Root/Before. This will help us really well because if we want to add a new child under the root, or under the Last root level, for example, it really suits us (but it's not a necessary thing to do). Now, all we need to do is to design a nice hierarchy (manually...so far). Because I did it, I will show you it to you guys:

    case WM_INITDIALOG:
    {
       InitCommonControls();                // make our tree control
                                            // work
       hTree=GetDlgItem(hWnd,IDC_TREE1);    // save the handle
                                            // (window) of the tree
       // create image list and put it into the tree control
       //====================================================//
       hImageList=ImageList_Create(16,16,ILC_COLOR16,2,10);
       hBitMap=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_TREE));
       ImageList_Add(hImageList,hBitMap,NULL);
       DeleteObject(hBitMap);
       SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SETIMAGELIST,0,
                         (LPARAM)hImageList);
       tvinsert.hParent=NULL;
       tvinsert.hInsertAfter=TVI_ROOT;
       tvinsert.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
       tvinsert.item.pszText="Parent";
       tvinsert.item.iImage=0;
       tvinsert.item.iSelectedImage=1;
    // [+]
    // |
    /* |--*/Parent=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
                              TVM_INSERTITEM,0,(LPARAM)&tvinsert);
    /* | */Root=Parent;
    /* | */Before=Parent;                    // handle of the previous
                                             // root
    /* | */tvinsert.hParent=Parent;          // parent's
    /* | */tvinsert.hInsertAfter=TVI_LAST;   // below parent
    /* | */tvinsert.item.pszText="Child 1";
    /* |    |--[+] */
    /* |    |   |  */
    /* |    |   |  */Parent=(HTREEITEM)SendDlgItemMessage
                            (hWnd,IDC_TREE1,TVM_INSERTITEM,0,
                            (LPARAM)&tvinsert);
    /* |    |   |*/ tvinsert.hParent=Parent;
    /* |    |   |*/ tvinsert.item.pszText="Child of Child1";
    /* |    |   |*/Parent=(HTREEITEM)SendDlgItemMessage
                          (hWnd,IDC_TREE1,TVM_INSERTITEM,0,
                          (LPARAM)&tvinsert);
    /* |    |   |-[+]*/
    /* |    |     */
    /* |    |     */
    /* |    |     */ tvinsert.hParent=Parent;
    /* |    |     */ tvinsert.hInsertAfter=TVI_LAST;
    /* |    |     */ tvinsert.item.pszText="Double Click Me!";
    /* |    |     */ tvinsert.item.mask=TVIF_TEXT;
    /* |    |     */ SendDlgItemMessage(hWnd,IDC_TREE1,TVM_INSERTITEM,
                                        0,(LPARAM)&tvinsert);
    /* |    */tvinsert.hParent=Before;           // handle of the
                                                 // above data
    /* |    */tvinsert.hInsertAfter=TVI_LAST;    // below parent
    /* |    */tvinsert.item.pszText="Child 2";
    /* |    */Parent=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
                      TVM_INSERTITEM,0,(LPARAM)&tvinsert);
       tvinsert.hParent=NULL;             // top-most level doesn't
                                          // need a handle
       tvinsert.hInsertAfter=TVI_LAST;    // work as root level
       tvinsert.item.pszText="Parent2";
       Parent=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
               TVM_INSERTITEM,0,(LPARAM)&tvinsert);
    }
    break;
    

    Feww!! that was rough. Well, since we passed this one, we now will have more fun.

    Clicking on Items: Control Messages

    This is the same as the list view control (you can read my tutorial); the item messaging is the same!! It is done via the WM_NOTIFY message that Windows ends when a control [depend which], is being notified [being used]. As usual, I will show the basic code form for the WM_NOTIFY:

      case WM_NOTIFY:
      {
        case IDC_TREE1:
        if(((LPNMHDR)lParam)->code == <NM_xxxxx>)
        {
          // Add Code here
        }
      }
      break;
    

    This is the basic skeleton for using the WM_NOTIFY on controls that use this Windows message. Underneath, we have the "case IDC_TREE1". This ensures that we are using the right control. The ((LPNMHDR)lParam)->code == NM_xxxxx is the type of event that has been processed while we have been doing something on the control.

    Examples:

    • Double-click on an item
    • Single-click
    • Left-click
    • And many more...

    As you can see, the NM_xxxxx stands for "Notification Message." There quite few that we can use:

    ...
    ...
    NM_CLICK
    NM_DBLCLK
    NM_RCLICK
    NM_RDBLCLK
    TVN_BEGINLABELEDIT ; also sent as notification
    TVN_BEGINLABELEDIT ; "                 "
    ...
    ...
    

    To click on an item, we have a few messages: Using the TVM_GETNEXTITEM is the same as in the list control; however, in the tree control the return value is NOT the index of the item. Rather, it is the HANDLE to the item! Here's an example on getting the selected item:

    Selected=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
              TVM_GETNEXTITEM,TVGN_CARET,(LPARAM)Selected);
    if(Selected==NULL)
    {
      MessageBox(hWnd,"No Items in TreeView","Error",
                 MB_OK|MB_ICONINFORMATION);
      break;
    }
    

    Check the new message: TVGN_CARET. There is a description of each message:

    Message Description
    TVGN_CARET Retrieves the currently selected item
    TVGN_CHILD Retrieves the first child item of the item specified by the hitem parameter
    TVGN_DROPHILITE Retrieves the item that is the target of a drag-and-drop operation
    TVGN_FIRSTVISIBLE Retrieves the first visible item
    TVGN_NEXT Retrieves the next sibling item
    TVGN_NEXTVISIBLE Retrieves the next visible item that follows the specified item
    TVGN_PAREN Retrieves the parent of the specified item
    TVGN_PREVIOUS Retrieves the previous sibling item
    TVGN_PREVIOUSVISIBLE Retrieves the first visible item that precedes the specified item
    TVGN_ROOT Retrieves the topmost or very first item of the tree-view control

    For more detailed information, read MSDN/win32.hlp. So, To use this, we need to use the TVGN_CARET as a selected item.

    Note: Selected is a HTREEITEM type, because we retrieve an handle, and not an index.

    The next thing to use is a new struct called TV_ITEM.

    The TV_ITEM structure specifies or receives attributes of
    a tree-view item.
    

    Yup, now that we have the handle of the item we have selected, we can fill this struct with the item's info, and use it for our own purpose!

    char Text[255]="";          // retrieve text from item to here
    memset(&tvi,0,sizeof(tvi)); // set all items to 0
    ...
    ...
    ...
    TreeView_EnsureVisible(hWnd,Selected);
        // ensure we clicked on the right item!!
    SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SELECTITEM,TVGN_CARET,
                      (LPARAM)Selected);
        // select the item
    flagSelected=true;
        // use a bool flag; this helps to see whether we have
        // selected an item or not
    tvi.mask=TVIF_TEXT;    // item text attribute
    tvi.pszText=Text;      // text is the pointer to the text
    tvi.cchTextMax=256;    // size of text to retrieve
    tvi.hItem=Selected;    // the selected item
    SendDlgItemMessage(hWnd,IDC_TREE1,TVM_GETITEM,TVGN_CARET,
                      (LPARAM)&tvi);
        // get the data!!
    

    Here is the complete code for when a user double-clicks an item and retrieves its data:

    case WM_NOTIFY:
    {
      case IDC_TREE1:
      if(((LPNMHDR)lParam)->code == NM_DBLCLK)
        // if code == NM_CLICK - single-click an item
      {
        char Text[255]="";
        memset(&tvi,0,sizeof(tvi));
        Selected=(HTREEITEM)SendDlgItemMessage
                 (hWnd,IDC_TREE1,TVM_GETNEXTITEM,TVGN_CARET,
                 (LPARAM)Selected);
    
        if(Selected==NULL)
        {
          MessageBox(hWnd,"No Items in TreeView","Error",
                     MB_OK|MB_ICONINFORMATION);
          break;
        }
        TreeView_EnsureVisible(hWnd,Selected);
        SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SELECTITEM,
                           TVGN_CARET,(LPARAM)Selected);
        flagSelected=true;
        tvi.mask=TVIF_TEXT;
        tvi.pszText=Text;
        tvi.cchTextMax=256;
        tvi.hItem=Selected;
    
        if(SendDlgItemMessage(hWnd,IDC_TREE1,TVM_GETITEM,TVGN_CARET,
                             (LPARAM)&tvi))
        {
          if(tvi.cChildren==0 && strcmp
            (tvi.pszText,"Double Click Me!")==0)
          {
            MessageBox(hWnd,"Press OK to delete me!","Example",
                       MB_OK|MB_ICONINFORMATION);
            SendDlgItemMessage(hWnd,IDC_TREE1,TVM_DELETEITEM,
                               TVGN_CARET,(LPARAM)tvi.hItem);
            flagSelected=false;
            break;
          }
        }
      }
    }
    break;
    
    Note: tvi.cChildren means: Flag that indicates whether the item has associated child items,

    Deleting an Item

    This is fairly easy. From the code above, we can see that we have a flag called "flagSelected". It tells us whether a user has doubled-clicked an item or not [true/false]. From this, we also have the item handler because we have set the "Selected" variable as a global member. So, deleting is easy:

    case IDC_DELETE:    // Delete Button is pressed
    {
      if(flagSelected==true)
      {
        if(tvi.cChildren==0)
          SendDlgItemMessage(hWnd,IDC_TREE1,TVM_DELETEITEM,TVGN_CARET,
                            (LPARAM)tvi.hItem);
    
         flagSelected=false;
      }
      else
      {
        MessageBox(hWnd,"Double Click Item to Delete","Message",
                   MB_OK|MB_ICONINFORMATION);
      }
    }
    break;
    

    Deleting ALL items in the tree control:

      case IDC_DELALL:
      {
        int TreeCount=TreeView_GetCount(GetDlgItem(hWnd,IDC_TREE1));
        for(int i=0;i<=TreeCount;i++)
        TreeView_DeleteAllItems(GetDlgItem(hWnd,IDC_TREE1));
      }
      break;
    

    Adding a new root to our tree view;

      case IDC_ADDROOT:
      {
        tvinsert.hParent=NULL;           // top-most level doesn't
                                         // need a handle
        tvinsert.hInsertAfter=TVI_ROOT;  // work as root level
        tvinsert.item.pszText="Parent Added";
        Parent=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
                TVM_INSERTITEM,0,(LPARAM)&tvinsert);
        UpdateWindow(hWnd);
      }
      break;
    

    Adding a new child to a selected root:

      case IDC_CHILD:
      {
        tvinsert.hParent=Selected;
        tvinsert.hInsertAfter=TVI_LAST;
        tvinsert.item.pszText="Child Added";
        Parent=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
                TVM_INSERTITEM,0,(LPARAM)&tvinsert);
        TreeView_SelectDropTarget(GetDlgItem(hWnd,IDC_TREE1),Parent);
      }
      break;
    
    Note: The TreeView_SelectDropTarget macro selects the specified tree-view item, scrolls the item into view, or redraws the item. If we don't specify this macro, after adding a new child, we won't be able to see it until our mouse is over its root.

    Drag and Drop Effect

    Okay, I have noticed that I missed something. So, there we go, a nice drag & drop effect to use in our tree control example. We begin with trapping the TVN_BEGINDRAG notification!

    Note: make sure that the "Disable Drag And Drop" property is NOT set!! Also, note that we are using new global variables, which are as follows:
    // for drag and drop
    HWND hTree;
    TVHITTESTINFO tvht;
    HTREEITEM hitTarget;
    POINTS Pos;
    bool Dragging;
    

    At the WM_INITDIALOG, add: hTree=GetDlgItem(hWnd,IDC_TREE1);. That way, we will have our hWnd global to use, and you don't have to!! Now, we are ready to begin the notify trap:

    case WM_NOTIFY:
    {
      if(((LPNMHDR)lParam)->code == TVN_BEGINDRAG)
      {
        HIMAGELIST hImg;        // image list for the dragging effect
        LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW) lParam;
                                // tree view message info
        hImg=TreeView_CreateDragImage(hTree, lpnmtv->itemNew.hItem);
                                // create img
        ImageList_BeginDrag(hImg, 0, 0, 0);
                                // start drag effect
        ImageList_DragEnter(hTree,lpnmtv->ptDrag.x,lpnmtv->ptDrag.y);
                                // where to start
        ShowCursor(FALSE);      // no mouse cursor needed
        SetCapture(hWnd);       // snap mouse & window
        Dragging = TRUE;        // we are dragging
      }
    }
    break;
    

    When we finished trapping and everything is set, we need to handle the Mouse Move message : WM_MOUSEMOVE.

    case WM_MOUSEMOVE:
    {
      if (Dragging)
      {
        Pos = MAKEPOINTS(lParam);
        ImageList_DragMove(Pos.x-32, Pos.y-25);   // where to draw
                                                  // the drag from
        ImageList_DragShowNolock(FALSE);
        tvht.pt.x = Pos.x-20;                     // the highlight
                                                  // items should be
                                                  // as the same
                                                  // points as the
                                                  // drag
        tvht.pt.y = Pos.y-20;
        if(hitTarget=(HTREEITEM)SendMessage(hTree,TVM_HITTEST,NULL,
                     (LPARAM)&tvht))              // if there is a hit
        SendMessage(hTree,TVM_SELECTITEM,TVGN_DROPHILITE,
                   (LPARAM)hitTarget);            // highlight it
    
      ImageList_DragShowNolock(TRUE);
      }
    }
    break;
    

    We also need to handle the final message of drag finishing. The message we use is WM_LBUTTONUP; this will tell when the user has finished his dragging mode.

    case WM_LBUTTONUP:
    {
      if (Dragging)
      {
        ImageList_DragLeave(hTree);
        ImageList_EndDrag();
        Selected=(HTREEITEM)SendDlgItemMessage(hWnd,IDC_TREE1,
                  TVM_GETNEXTITEM,TVGN_DROPHILITE,0);
        SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SELECTITEM,
                           TVGN_CARET,(LPARAM)Selected);
        SendDlgItemMessage(hWnd,IDC_TREE1,
                           TVM_SELECTITEM,TVGN_DROPHILITE,0);
        ReleaseCapture();
        ShowCursor(TRUE);
        Dragging = FALSE;
      }
    }
    break;
    

    That's it, a nice drag and drop effect.

    Label Editing

    This time, we add code to enable us to edit the Tree item's text on the fly. It isn't hard, and basically the same as we have done it with the ListView control. Add a global variable called HWND hEdit; and trap these notification messages:

    case WM_NOTIFY:
    {
      if(((LPNMHDR)lParam)->code == TVN_BEGINLABELEDIT)
      {
        hEdit=TreeView_GetEditControl(hTree);
      }
    
      if(((LPNMHDR)lParam)->code == TVN_ENDLABELEDIT)
      {
        char Text[256]="";
        tvi.hItem=Selected;
        SendDlgItemMessage(hWnd,IDC_TREE1,TVM_GETITEM,0,
                          (WPARAM)&tvi);
        GetWindowText(hEdit, Text, sizeof(Text));
        tvi.pszText=Text;
        SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SETITEM,0,
                          (WPARAM)&tvi);
      }
    }
    break;
    

    That's it; it's easily and quickly done! There's no need for overbloated code to edit labels.

    F.A.Q.

    Q. How do I use big pictures in my tree control (32x32)?

    A. Doing a 32x32 size picture is really easy. If you meant that you wanted to use BIG pictures in your tree control, use the folowing:

    /* change old code to this */
    1. hImageList=ImageList_Create(32,32,ILC_COLOR32,2,10);
    2. Open Photoshop and load List.bmp into it.
    3. In the menu bar, choose image-> image size.
    4. Change the height to 32 (width is auto changed).
    5. Save the file.
    6. Recompile the code.

    Now you have 32x32-sized tree control pictures!

    Q. Why can't I see different pictures when I select my item?

    A. Make sure you have your mask set as:

    tvinsert.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;

    Q. How can I select items with a right-click of the mouse without the highlight going back to the last selected?

    A. Here it is:

    if(((LPNMHDR)lParam)->code == NM_RCLICK)    // right click
    {
      Selected=(HTREEITEM)SendDlgItemMessage
               (hWnd,IDC_TREE1,TVM_GETNEXTITEM,TVGN_DROPHILITE,0);
      if(Selected==NULL)
      {
        MessageBox(hWnd,"No Items in TreeView","Error",
                   MB_OK|MB_ICONINFORMATION);
        break;
      }
    
      SendDlgItemMessage(hWnd,IDC_TREE1,TVM_SELECTITEM,TVGN_CARET,
                        (LPARAM)Selected);
    }
    

    Grand Finale

    We have come to the end of this article. I hope everyone enjoyed this as much as it took me time to find and add the proper code.

    I know one thing: Once you have API power, you don't need MFC that much. But, I can't let you think otherwise; classes are powerful, after all...

    Bengi / 2003

    Downloads

    Download source files - 28.6 Kb
    Download demo project - 9.79 Kb
    • 1

    IT Offers






    The Network for Technology Professionals

    About Internet.com

    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers