Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

Virtual Sample (C++)

This sample illustrates a tree control in virtual mode, used to display a list with 1 million items.

The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\MFC\Virtual\SamplVw.cpp or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\MFC\Virtual\SamplVw.cpp (on 32-bit Windows versions).

/****************************************************************************/
/* SftTree/DLL 7.5 - Tree Control for C/C++                                 */
/* Copyright (C) 1995, 2016  Softel vdm, Inc. All Rights Reserved.          */
/****************************************************************************/

#include "stdafx.h"
#include "Virtual.h"

#include "sampldoc.h"
#include "samplvw.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSampleView

IMPLEMENT_DYNCREATE(CSampleView, CView)

BEGIN_MESSAGE_MAP(CSampleView, CView)
    //{{AFX_MSG_MAP(CSampleView)
    ON_WM_CREATE()
    ON_WM_SIZE()
    ON_COMMAND(IDM_RESIZE, OnResize)
    //}}AFX_MSG_MAP
    ON_SFTTREEN_LBUTTONDBLCLK_COLUMNRES(IDC_TREE, OnLButtonDblClkColumnResize)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSampleView construction/destruction

CSampleView::CSampleView()
{
    m_fFirstDone = FALSE;
    m_Item.LoadBitmap(IDB_ITEM);/* Item bitmap */
}

CSampleView::~CSampleView()
{
}

/////////////////////////////////////////////////////////////////////////////
// CSampleView drawing

void CSampleView::OnDraw(CDC* pDC)
{
    CSampleDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
}

/////////////////////////////////////////////////////////////////////////////
// CSampleView diagnostics

#ifdef _DEBUG
void CSampleView::AssertValid() const
{
    CView::AssertValid();
}

void CSampleView::Dump(CDumpContext& dc) const
{
    CView::Dump(dc);
}

CSampleDoc* CSampleView::GetDocument() // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSampleDoc)));
    return (CSampleDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSampleView message handlers

int CSampleView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    if (!m_Tree.CreateEx(
        WS_EX_CLIENTEDGE,
        SFTTREESTYLE_NOTIFY |            /* Notify parent window */
        SFTTREESTYLE_LEFTBUTTONONLY |    /* Only respond to left mouse button */
        SFTTREESTYLE_SCROLL |            /* Honor WS_H/VSCROLL */
        SFTTREESTYLE_DISABLENOSCROLL |   /* Disable scrollbars instead of hiding */
        WS_HSCROLL | WS_VSCROLL |        /* Vertical and horizontal scrollbars */
        WS_VISIBLE | WS_CHILD,           /* Visible, child window */
        CRect(0,0,0,0),                  /* Location */
        this,                            /* Parent window */
        IDC_TREE))                       /* Tree control ID */
            return -1;

    /* Resources, such as bitmaps, should be loaded and must remain    */
    /* valid until the tree control is destroyed or no longer uses     */
    /* these.                                                          */

    /* Initialize "virtual" data callback routines.  The      */
    /* routines used are defined below.  The callbacks are    */
    /* static functions so they don't have a 'this' pointer.  */
    /* We pass the 'this' pointer as userdata for the call-   */
    /* back routine.                                          */
    {
        SFTTREE_VIRTUALDEF virt = {
            SFTTREE_VERSION_700,
            (SFTTREE_DWORD_PTR)(LPVOID)this,
            VirtualStorageGetItemCallback,
            VirtualStorageReleaseItemCallback,
        };
        if (!m_Tree.VirtualInitialize(&virt))
            return -1; /* error handling goes here */
        /* Set current number of items in the control.             */
        if (!m_Tree.VirtualCount(1000000L, 1000000L))
            return -1; /* error handling goes here */
    }

    m_Tree.SetShowHeader(TRUE);          /* Show column headers */
    m_BgBitmap.LoadBitmap(IDB_BACKGROUND);/* Load a background bitmap */
    m_Tree.SetBackgroundBitmap(m_BgBitmap, SFTTREE_BGBITMAP_HSCROLL, SFTTREE_BGBITMAP_CENTER);/* Define the background bitmap */

    SFT_PICTURE Pic;                     /* Used for certain pictures */

    /* Register the item pictures.  These pictures are used    */
    /* for all items in the tree control. All three pictures   */
    /* must be the same size.                                  */
    {
        SFT_PICTURE aPic[3];
        Sft_InitPicture(&aPic[0]);
        Sft_InitPicture(&aPic[1]);
        Sft_InitPicture(&aPic[2]);
        m_aThreeItemBitmaps[0].LoadBitmap(IDB_EXPANDABLE);/* Expandable bitmap */
        Sft_SetPictureBitmap(&aPic[0], m_aThreeItemBitmaps[0]);/* Assign bitmap */
        m_aThreeItemBitmaps[1].LoadBitmap(IDB_EXPANDED);/* Expanded bitmap */
        Sft_SetPictureBitmap(&aPic[1], m_aThreeItemBitmaps[1]);/* Assign bitmap */
        m_aThreeItemBitmaps[2].LoadBitmap(IDB_LEAF);/* Leaf bitmap */
        Sft_SetPictureBitmap(&aPic[2], m_aThreeItemBitmaps[2]);/* Assign bitmap */
        m_Tree.SetPictures(aPic);        /* Use item pictures */
    }
    m_Tree.SetItemPictureAlign(TRUE);    /* Align item bitmaps */
    /* Register the cell picture size.  All cell pictures used */
    /* must be the same size.  Only one picture needs to be    */
    /* registered, even if several are used.                   */
    {
        SFTTREE_CELLINFOPARM CellInfo;
        CellInfo.version = 7;
        CellInfo.index = -1;             /* Registering picture size */
        Sft_InitPicture(&CellInfo.Cell.CellPicture1);/* Initialize */
        m_CellBitmap.LoadBitmap(IDB_SMILE1);/* Cell picture */
        m_Tree.SetCellInfo(&CellInfo);   /* Register use of cell pictures */
        /* Set individual cell pictures using this sample code: */

        // SFTTREE_CELLINFOPARM CellInfo;
        // CellInfo.version = 7;
        // CellInfo.index = cell_index_to_change;
        // CellInfo.iCol = column_number_to_change;
        // m_Tree.GetCellInfo(&CellInfo);
        // /* m_CellBitmap.LoadBitmap(IDB_your_bitmap); *//* Cell picture */
        // Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_CellBitmap);
        // CellInfo.Cell.flag = SFTTREE_BMP_RIGHT;
        // m_Tree.SetCellInfo(&CellInfo);
    }
    m_Tree.SetTreeLineStyle(SFTTREE_TREELINE_NONE);/* No tree lines */
    m_Tree.SetShowButtons(FALSE);        /* Expand/collapse buttons (level 1..n) */
    m_Tree.SetShowGrid(TRUE);            /* Show grid */
    m_Tree.SetGridStyle(SFTTREE_GRID_BOTH_DOT);/* Dotted grid lines */
    m_Tree.SetShowTruncated(TRUE);       /* Show ... if truncated */
    m_Tree.SetSelectionStyle(SFTTREE_SELECTION_CELL1);/* Select first cell only */
    m_Tree.SetSelectionArea(SFTTREE_SELECTIONAREA_ALL);/* Selection changes by clicking anywhere on an item */
    m_Tree.SetFlyby(TRUE);               /* Flyby highlighting */
    m_Tree.SetScrollTips(TRUE);          /* Show Scrolltips */
    m_Tree.SetReorderColumns(TRUE);      /* Column reordering */
    m_Tree.SetOpenEnded(TRUE, TRUE);     /* Left tree open ended*/
    m_Tree.SetOpenEnded(TRUE, FALSE);    /* Right tree open ended */
    m_Tree.SetShowHeaderButtons(TRUE);   /* Show column header as buttons */
    /* Define columns */
    {
        SFTTREE_COLUMN_EX aCol[3] = {
          { 0, 0,                        /* Reserved */
            100,                         /* Width (in pixels) */
            ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
            ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
            _T("First Column"),          /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            0,                           /* Display column number (display position) */
            SFTTREE_COL_MERGE |          /* Column can merge with next */
            SFTTREE_COL_MERGEINTO |      /* Previous column can merge into this column */
            0,                           /* Column flag */
            30,                          /* Minimum column width */
          },
          { 0, 0,                        /* Reserved */
            110,                         /* Width (in pixels) */
            ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
            ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
            _T("Second Column"),         /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            1,                           /* Display column number (display position) */
            SFTTREE_COL_MERGE |          /* Column can merge with next */
            SFTTREE_COL_MERGEINTO |      /* Previous column can merge into this column */
            0,                           /* Column flag */
            30,                          /* Minimum column width */
          },
          { 0, 0,                        /* Reserved */
            110,                         /* Width (in pixels) */
            ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
            ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
            _T("Third Column"),          /* Column header title */
            NULL, NULL,                  /* Reserved field and bitmap handle */
            SFTTREE_BMP_RIGHT,           /* Picture alignment */
            0, 0, 0,                     /* Reserved fields */
            SFTTREE_NOCOLOR,             /* Cell background color */
            SFTTREE_NOCOLOR,             /* Cell foreground color */
            SFTTREE_NOCOLOR,             /* Selected cell background color */
            SFTTREE_NOCOLOR,             /* Selected cell foreground color */
            0,                           /* Real column position (set by SetColumns call) */
            2,                           /* Display column number (display position) */
            0,                           /* Column flag */
            30,                          /* Minimum column width */
          }
        };
        m_Tree.SetColumns(3, aCol);      /* Set column attributes */
        m_Tree.SetSplitColumn(1);        /* Column split position */
    }

    m_Tree.SetShowRowHeader(SFTTREE_ROWSTYLE_BUTTONCOUNT0);/* Row style */
    /* Register the row header picture size.  All row header   */
    /* pictures used must be the same size.  Only one picture  */
    /* needs to be registered, even if several are used.       */
    {
        SFTTREE_ROWINFOPARM RowInfo;
        RowInfo.version = 7;
        RowInfo.index = -1;
        m_RowBitmap.LoadBitmap(IDB_ROW);/* Row header picture */
        Sft_InitPicture(&RowInfo.Row.RowPicture1);
        Sft_SetPictureBitmap(&RowInfo.Row.RowPicture1, m_RowBitmap);
        m_Tree.SetRowInfo(&RowInfo);
        /* Set individual row header bitmaps using: */
        // SFTTREE_ROWINFOPARM RowInfo;
        // RowInfo.version = 7;
        // RowInfo.index = index;
        // m_Tree.GetRowInfo(&RowInfo);
        // /* m_RowBitmap.LoadBitmap(IDB_your_bitmap); *//* Row header picture */
        // Sft_SetPictureBitmap(&RowInfo.Row.RowPicture1, m_RowBitmap);
        // RowInfo.Row.flag = SFTTREE_BMP_RIGHT;
        // m_Tree.SetRowInfo(&RowInfo);
    }
    m_Tree.SetRowColHeaderText(_T("?"));       /* Row/column header text */
    m_Tree.SetRowColHeaderStyle(ES_LEFT | SFTTREE_HEADER_UP);/* Row/column header style */
    m_RowColBitmap.LoadBitmap(IDB_SMILE1);/* Row/column header picture */
    Sft_InitPicture(&Pic);               /* Initialize */
    Sft_SetPictureBitmap(&Pic, m_RowColBitmap);
    m_Tree.SetRowColHeaderPicture(&Pic);       /* Row/column picture */
    m_Tree.SetRowColHeaderPictureStyle(SFTTREE_BMP_RIGHT);/* Row/column picture alignment */
    m_Tree.SetCharSearchMode(SFTTREE_CHARSEARCH_ALLCHARS, -1);/* Consider all characters typed */
    /* Use a ToolTips callback routine */
    {
        SFTTREE_TOOLTIPSPARM Parm;       /* Parameter list */
        Parm.lpfnToolTips = (SFTTREE_TOOLTIPSPROC) CSampleView::ToolTipsCallback;/* User supplied routine */
        Parm.UserData = (SFTTREE_DWORD_PTR)0;/* User supplied data */
        m_Tree.SetToolTipsCallback(&Parm);
    }
    /* Change the default colors */
    {
        SFTTREE_COLORS Colors;
        m_Tree.GetCtlColors(&Colors);    /* Get current color settings */
        Colors.colorTreeLines = COLOR_3DDKSHADOW | 0x80000000L;/* Tree line color */
        Colors.colorSelBgNoFocus = COLOR_BTNFACE | 0x80000000L;/* Selection background color (no input focus) */
        Colors.colorSelFgNoFocus = COLOR_BTNTEXT | 0x80000000L;/* Selection foreground color (no input focus) */
        m_Tree.SetCtlColors(&Colors);    /* Set new colors */
    }

    // In our example, we only consider 50 items when MakeColumnOptimal, MakeRowHeaderOptimal or
    // MakeSplitterOptimal is used.  Because our sample data is wider at the end of the list,
    // we'll change the TopIndex to the very last few items.
    // That way the last 50 items are analyzed.  In a typical application this is not necessary.
    m_Tree.SetTopIndex(m_Tree.GetCount() - 50);


    /* Make all column widths optimal, so text and pictures are */
    /* not clipped horizontally.                               */
    m_Tree.MakeColumnOptimal(-1, 50, TRUE);/* Make column widths optimal */
    /* Make row header width optimal, so text and pictures are  */
    /* not clipped horizontally.                               */
    m_Tree.MakeRowHeaderOptimal(50, TRUE);/* Make row header width optimal */
    m_Tree.RecalcHorizontalExtent(50, TRUE);/* Update horizontal scroll bar */

    m_Tree.SetTopIndex(0);

    return 0;
}

void CSampleView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    m_Tree.MoveWindow(0, 0, cx, cy);

    // when the window is created initially, it has a size of CRect(0,0,0,0)
    // so we'll have to optimize the splitter when the window is resized the
    // first time
    if (!m_fFirstDone && cx != 0 && cy != 0) {
        m_fFirstDone = TRUE;
        m_Tree.MakeSplitterOptimal(); /* Optimal splitter position */
    }
}

/* Respond to events as the user double-clicks on the      */
/* column resizing area.  The events handled here can be   */
/* changed to suit your application.                       */

void CSampleView::OnLButtonDblClkColumnResize()
{
    /* Resize column optimally */
    int realCol = m_Tree.GetResizeColumn();
    if (realCol >= 0) {
        m_Tree.MakeColumnOptimal(-1, 50, TRUE);/* Make column width optimal */
        m_Tree.RecalcHorizontalExtent(50, TRUE);/* Update horizontal scroll bar */
    } else {
        m_Tree.MakeSplitterOptimal();    /* Optimal splitter position */
    }
}

// Callback of type SFTTREE_TOOLTIPSPROC
void CALLBACK CSampleView::ToolTipsCallback(HWND hwnd,
    LPTSTR lpszBuffer, int type, int index, int column, SFTTREE_DWORD_PTR UserData, BOOL FAR* fInPlace)
{
    switch (type) {
    case SFTTREE_TOOLTIP_VSCROLL:        /* Vertical scrolling */
        wsprintf(lpszBuffer, _T("Item %d is on top"), index);
        break;
    case SFTTREE_TOOLTIP_CELL:           /* Cell tooltip */
        // If lpszBuffer is left as-is, the cell tooltip will be displayed, otherwise
        // the text in lpszBuffer will be shown as an explanatory tooltip.
        // we don't modify lpszBuffer, so we get the default in-place tooltip
        //wsprintf(lpszBuffer, TEXT("An explanatory tooltip for cell %d/%d"), index, column);
        break;
    case SFTTREE_TOOLTIP_COLUMN_HEADER:         /* Column header tooltip */
        wsprintf(lpszBuffer, _T("A tooltip for column %d"), column);
        break;
    default:                             /* unhandled type (future expansion) */
        return;
    }
}

// Callback of type LPFNSFTTREE_VGETITEM
void CSampleView::VGetItem(int totCols, LONG index, LPSFTTREE_ITEM FAR* lplpItem)
{
    // All item information (including all strings) MUST remain valid until VReleaseItem
    // is called. For this reason, the strings must be allocated using "new" or be static and CANNOT be
    // objects located on the stack (i.e., NO local variables).

    memset(&m_WorkingItem, 0, sizeof(m_WorkingItem));
    m_WorkingItem.level = 0;             // Provide the level number (must be 0)
    m_WorkingItem.fShown = TRUE;         // Must be shown (it's a flat list)
    m_WorkingItem.fEnabled = TRUE;       // Item is enabled (visually)
    m_WorkingItem.dwdData = 0;           // Userdata for this item (can be 0)
    m_WorkingItem.lpszRowHeader = NULL;  // Row header text (can be NULL)

    if ((index % 6) == 0)                /* Randomly change item bitmap */
        Sft_SetPictureBitmap(&m_WorkingItem.ItemPicture, m_Item);

    // Allocate string array for cell text
    m_WorkingItem.alpszString = new LPTSTR[totCols];
    // Create cell strings
    CString str;
    str.Format(_T("Item %09ld"), index);
    m_WorkingItem.alpszString[0] = new TCHAR[str.GetLength()+1];
    lstrcpy(m_WorkingItem.alpszString[0], str);

    int col;
    for (col = 1 ; col < totCols ; ++col) {
        str.Format(_T("Column %d(%ld)"), col, index);
        m_WorkingItem.alpszString[col] = new TCHAR[str.GetLength()+1];
        lstrcpy(m_WorkingItem.alpszString[col], str);
    }
    // (Optional) Allocate and initialize cells
    m_WorkingItem.aCells = new SFTTREE_CELL[totCols];
    memset(m_WorkingItem.aCells, 0, totCols*sizeof(SFTTREE_CELL));
    for (col = 0 ; col < totCols ; ++col) {
        LPSFTTREE_CELL lpCell = &m_WorkingItem.aCells[col];
        lpCell->colorBg = lpCell->colorFg = lpCell->colorBgSel = lpCell->colorFgSel = SFTTREE_NOCOLOR;
        lpCell->hFont = NULL;
        lpCell->flag = SFTTREE_BMP_LEFT;
        Sft_InitPicture(&lpCell->CellPicture1);
        if ((index % 5) == 0 && col == 1) {/* Randomly add bitmaps */
            Sft_SetPictureBitmap(&lpCell->CellPicture1, m_CellBitmap);/* Cell bitmap */
            lpCell->flag |= SFTTREE_BMP_RIGHT;/* Cell bitmap */
        }
        if (col == 2 && (index % 5) == 0) {/* Randomly change colors */
            lpCell->colorBg = 0x80000000 | COLOR_BTNFACE;
            lpCell->colorFg = 0x80000000 | COLOR_BTNTEXT;
        }
    }

    // (Optional) Create row header information
    m_WorkingItem.lpRow = new SFTTREE_ROW;
    memset(m_WorkingItem.lpRow, 0, sizeof(SFTTREE_ROW));
    m_WorkingItem.lpRow->colorBg = m_WorkingItem.lpRow->colorFg = SFTTREE_NOCOLOR;
    m_WorkingItem.lpRow->colorBgSel = m_WorkingItem.lpRow->colorFgSel = SFTTREE_NOCOLOR;
    Sft_InitPicture(&m_WorkingItem.lpRow->RowPicture1);
    if ((index % 8) == 0) {/*randomly add bitmaps */
        Sft_SetPictureBitmap(&m_WorkingItem.lpRow->RowPicture1, m_RowBitmap);
        m_WorkingItem.lpRow->flag = SFTTREE_BMP_LEFT; /* Row header bitmap alignment */
    }

    *lplpItem = &m_WorkingItem;
}

// Callback of type LPFNSFTTREE_VRELEASEITEM
void CSampleView::VReleaseItem(int totCols, LONG index, LPSFTTREE_ITEM lpItem)
{
    // free storage allocated during previous VGetItem call
    int col;
    if (m_WorkingItem.alpszString) {     // free string array previously allocated
        for (col = 0 ; col < totCols ; ++col) {
            if (m_WorkingItem.alpszString[col])
                delete m_WorkingItem.alpszString[col];
        }
        delete m_WorkingItem.alpszString;
        m_WorkingItem.alpszString = NULL;
    }
    if (m_WorkingItem.aCells) {          // free {popup "cells" pop_cell} previously allocated
        delete m_WorkingItem.aCells;
        m_WorkingItem.aCells = NULL;
    }
    if (m_WorkingItem.lpRow) {           // free row information previously allocated
        delete m_WorkingItem.lpRow;
        m_WorkingItem.lpRow = NULL;      // row header
    }
}

void CALLBACK CSampleView::VirtualStorageGetItemCallback(HWND hwnd,
        SFTTREE_DWORD_PTR UserData, int totCols, LONG index, LPSFTTREE_ITEM FAR* lplpItem)
{
    // This is a static function, so there is no this pointer, but userData contains
    // the object's this pointer, so a real member function can be called.
    CSampleView* pTHIS = (CSampleView*)(LPVOID)UserData;
    // Call the object's member function.
    pTHIS->VGetItem(totCols, index, lplpItem);
}

void CALLBACK CSampleView::VirtualStorageReleaseItemCallback(HWND hwnd,
        SFTTREE_DWORD_PTR UserData, int totCols, LONG index, LPSFTTREE_ITEM lpItem)
{
    // This is a static function, so there is no this pointer, but userData contains
    // the object's this pointer, so a real member function can be called.
    CSampleView* pTHIS = (CSampleView*)(LPVOID)UserData;
    // Call the object's member function.
    pTHIS->VReleaseItem(totCols, index, lpItem);
}


void CSampleView::OnResize()
{
    m_Tree.EnterResizeMode();
}