Click here to Skip to main content
15,896,372 members
Articles / Desktop Programming / Win32

Win32 Editable TreeView and ListView Merged as One

Rate me:
Please Sign up or sign in to vote.
4.93/5 (59 votes)
26 Apr 2011CPOL6 min read 144.7K   11.9K   154  
A custom tree control for Win32.
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0500

///////////////////////////////////////////////////////////////////////////////////////
//
//
// TreeList Control For Win32
// Create by Eitan Michaelson 4/2011 , Noyasoft@gmail.com
//
//
///////////////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>

#include "Container.h"
#include "Resource.h"

#pragma warning(disable : 4996) // CRT Secure - off (VC 8)


///////////////////////////////////////////////////////////////////////////////////////
//
// Section  : Defines
//
///////////////////////////////////////////////////////////////////////////////////////

#define COLOR_WHITE RGB(255,255,255)
#define COLOR_GREEN RGB(0,255,0)
#define COLOR_RED   RGB(255,0,0)


///////////////////////////////////////////////////////////////////////////////////////
//
// Section  : Statics
//
///////////////////////////////////////////////////////////////////////////////////////

// This module is just a usage sample so I didn't bother with being thread safe
// Statics are OK here

// Handles array for 4 instances
static TREELIST_HANDLE TreeListHandle[4] = {0,0,0,0};

// Position for each instance on the parent window
static RECT            TreeListRect[4] =  {{010,010,300,150 },{310,010,610,150 }, {010,160,300,300 }, {310,160,610,300 }};

// Flags for each instance
static DWORD           TreeListFlags[4] =  {TREELIST_DRAW_EDGE, TREELIST_DRAW_EDGE | TREELIST_ANCHOR_RIGHT, TREELIST_DRAW_EDGE | TREELIST_ANCHOR_BOTTOM, TREELIST_DRAW_EDGE | TREELIST_ANCHOR_BOTTOM | TREELIST_ANCHOR_RIGHT | TREELIST_NORMAL_EDITBOX};




////////////////////////////////////////////////////////////////////////////////////
//
// Function: Container_ValidateEditRequest
// Description:
// Parameters:
//              TreeListHandle a Handle to the control that was changed
//              pAnyPtr:    the pointer that was set for the edited node
//              NewData:    What was typed by the user
//              Override:   a string to be pushed back to the node
//                          insted of the original "NewData" (optional)
// Return:      BOOL:       If this edit request is valid or not
// Logic:       This is only a sample!
//
////////////////////////////////////////////////////////////////////////////////////

static BOOL _stdcall Container_ValidateEditRequest(const TREELIST_HANDLE TreeListHandle,const void *pAnyPtr, const char *NewData,char *Override)
{

    // Process the edit request here


    // Example : get the pointer back:
    // ------------------------------
    // if(pAnyPtr)
    //     MessageBox(NULL,(char*)pAnyPtr,"Got the pointer..",MB_OK);


    // Example: Force changing the cell data
    // -------------------------------
    // sprintf(Override,"%d",atol(NewData)); // Convert the user string to a number ("089" -> "89") and send it back to the API

    return TRUE; // 'FALSE' Will prevent the edit request
}

////////////////////////////////////////////////////////////////////////////////////
//
// Function: Container_TreeListAddItem
// Description: Wrapper around TreeListNodeAdd ,
//             a helper function to create a setup like the VC6 debugger TreeView box.
// Parameters: TREELIST_HANDLE a treelist handle
//             Column info
//             Note: last parameter is using a 'printf' like style
//             Note: the length of "Name" and "Value" should be less then TREELIST_MAX_STRING !
// Return:     NODE_HANDLE
//
////////////////////////////////////////////////////////////////////////////////////

static NODE_HANDLE Container_TreeListAddItem(TREELIST_HANDLE ListTreeHandle, NODE_HANDLE ParentHandle,BOOL Editable, long Color, void *pAnyPtr, char *Name,char *Value,...)
{

    va_list args;
    int InputLebgth = 0;
    char    ValBuffer[1024] = {0};
    TreeListNodeData NodeItems[2]; // Only Value and Name columns so we will need an array of 2 nodes

    // Retrieve the variable arguments
    va_start( args, Value );
    vsprintf( ValBuffer, Value, args );
    va_end(args);

    memset(&NodeItems,0,sizeof(NodeItems));

    // Column 0 : Not editable, no back pointer
    strncpy(NodeItems[0].Data,Name,TREELIST_MAX_STRING);
    NodeItems[0].Editable           = FALSE;
    NodeItems[0].pExternalPtr       = 0;

    // Column 1 - Value
    strncpy(NodeItems[1].Data,ValBuffer,TREELIST_MAX_STRING);
    NodeItems[1].Editable           = Editable;
    NodeItems[1].Numeric            = FALSE;
    NodeItems[1].AltertedTextColor  = RGB(0,22,67);
    NodeItems[1].Colored            = TRUE;
    NodeItems[1].BackgroundColor    = Color;


    NodeItems[1].pExternalPtr       = pAnyPtr;

    // Call the API to add the data to the tree and return the node handle
    return(TreeListAddNode(ListTreeHandle,ParentHandle,(TreeListNodeData*)(NodeItems),1));

}

////////////////////////////////////////////////////////////////////////////////////
//
// Function: Container_BuildColumns
// Description: Build the columns
// Parameters:void
// Return:void
//
////////////////////////////////////////////////////////////////////////////////////

static void Container_BuildColumns(TREELIST_HANDLE ListTreeHandle,int PreFix)
{
    
    // Add columns, for the purpose of demonstration we will add additional column in each instance
    int iCount = 0;
    int iWidth = 300;
    char ColText[32] = {0};
    
    iWidth = iWidth - (300/(PreFix+1));
    
    for(iCount = 0; iCount < (PreFix);iCount++)
    {
        sprintf(ColText,"Column %d",iCount);
        TreeListAddColumn(ListTreeHandle,ColText,   iWidth/PreFix);
    }  
    
    //                 Name of column           Width
    //                 ---------------------------------
    TreeListAddColumn(ListTreeHandle,"Value",  TREELIST_LAST_COLUMN); // Note 'TREELIST_LAST_COLUMN' should be set for the last column.
}

////////////////////////////////////////////////////////////////////////////////////
//
// Function: Container_BuildTree
// Description: Uses the wrppper (Container_TreeListAddItem) to build the tree
// Parameters:NODE_HANDLE a treelist handle
// Return:void
//
////////////////////////////////////////////////////////////////////////////////////

static void Container_BuildTree(TREELIST_HANDLE ListTreeHandle,int PreFix)
{

    NODE_HANDLE Root,ChildA,ChildB,ChildC,GChildA,GChildB,GChildC,GChildD,GGChildA,GGChildB;
    char RootText[32] = {0};
    char TimeText[32] = {0};
    
    _strtime( TimeText );

    sprintf(RootText,"Cell # %d",PreFix);

    // Insert some nodes
    // -------------------------------------------------------------------------------------------------------------------------------------
    //                                                          Parent      Can Edit?  Color?                 Back Ptr   Col#0 Data                  Col#1 Data ('printf' format)
    Root        =   Container_TreeListAddItem (ListTreeHandle,  NULL,        FALSE,    COLOR_WHITE,            0,        RootText,                   "{...}"                        );
    ChildA      =   Container_TreeListAddItem (ListTreeHandle,  Root,        FALSE,    COLOR_WHITE,            0,        "Child A",                  "0x%x",rand ()                 );
    ChildB      =   Container_TreeListAddItem (ListTreeHandle,  Root,        FALSE,    COLOR_WHITE,            0,        "Child B",                  "{...}"                        );
    ChildC      =   Container_TreeListAddItem (ListTreeHandle,  Root,        TRUE,     COLOR_GREEN,            0,        "Child C",                  "Handle: 0x%x",ListTreeHandle  );
    GChildA     =   Container_TreeListAddItem (ListTreeHandle,  ChildC,      TRUE,     COLOR_WHITE,            0,        "Grandchild A",             "Ticks: %d",GetTickCount()     );
    GChildB     =   Container_TreeListAddItem (ListTreeHandle,  ChildC,      TRUE,     COLOR_WHITE,            0,        "Grandchild B",             "%s",TimeText                  );
    GChildC     =   Container_TreeListAddItem (ListTreeHandle,  ChildC,      TRUE,     COLOR_RED,              0,        "Grandchild C",             "My root# is %d",PreFix        );
    GChildD     =   Container_TreeListAddItem (ListTreeHandle,  ChildB,      FALSE,    COLOR_WHITE,            0,        "Grandchild D",             "{...}"                        );
    GGChildA    =   Container_TreeListAddItem (ListTreeHandle,  GChildD,     TRUE,     COLOR_WHITE,            0,        "Grand-Grandchild A",       "Created By Eitan Michaelson"  );
    GGChildB    =   Container_TreeListAddItem (ListTreeHandle,  GChildD,     FALSE,    COLOR_WHITE,            0,        "Grand-Grandchild B",       "2011 Noyasoft@gmail.com"      );

}


////////////////////////////////////////////////////////////////////////////////////
//
// Function: Container_BuildTreeLists
// Description: Create few instances of the control on the parent window
// Parameters:void
// Return:void
//
////////////////////////////////////////////////////////////////////////////////////

static void Container_BuildTreeLists(HWND hWndDlg)
{
    
    int iCount      = 0;
    int iTotal      = 0;
    int iTreeNum    = 0;
    
    srand ((unsigned int)time(NULL));
    
    for(iTreeNum = 0;iTreeNum < 4;iTreeNum++)
    {
        TreeListHandle[iTreeNum] = TreeListCreate(GetModuleHandle(NULL) ,hWndDlg,&TreeListRect[iTreeNum],TreeListFlags[iTreeNum] ,&Container_ValidateEditRequest);
        
        if(TreeListHandle[iTreeNum])
        {
            Container_BuildColumns(TreeListHandle[iTreeNum],iTreeNum);
            for(iCount;iCount <= (iTotal + 25);iCount++)
                Container_BuildTree(TreeListHandle[iTreeNum],iCount);
            
            iTotal += iCount;
            
        }
    }  
}

////////////////////////////////////////////////////////////////////////////////////
//
// Function: Container_KillTreeLists
// Description: Destroy all the control instances we've created
// Parameters:void
// Return:void
//
////////////////////////////////////////////////////////////////////////////////////

static void Container_KillTreeLists(void)
{
    
    int iTreeNum = 0;
    
    for(iTreeNum = 0;iTreeNum < 4;iTreeNum++)
    {
        
        if(TreeListHandle[iTreeNum])
            TreeListDestroy(TreeListHandle[iTreeNum]); // Kill and free the control data
    }
    
}


////////////////////////////////////////////////////////////////////////////////////
//
// Function: WinWndProc
// Description: The dialog proc
// Parameters:
// Return:
// Logic:
//
////////////////////////////////////////////////////////////////////////////////////

INT_PTR CALLBACK WinWndProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{


    char Title[32]      = {0};

    switch (Msg)
    {

    case WM_INITDIALOG : // This is a good place to init the control
        {


            // Set the windows's title
            sprintf(Title,"TreeList Control Sample (%s)",TREELIST_APIVERSION);
            SetWindowText(hWndDlg,Title);
            
            // Attach the controls
            Container_BuildTreeLists(hWndDlg);
            
            return TRUE;
        }

    case WM_CLOSE:
        {

            // Remove the controls
            Container_KillTreeLists();
            
            EndDialog(hWndDlg, IDOK);
            return TRUE;;
        }
    }

    return FALSE;
}

////////////////////////////////////////////////////////////////////////////////////
//
// Function: WinMain
// Description: The mother of all windows
// Parameters:
// Return:
// Logic:
//
////////////////////////////////////////////////////////////////////////////////////

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{

    // Start The Main Dialog
    DialogBox(hInstance , MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL, WinWndProc);

    return 0;

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Software Developer
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions