Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

Using C++/MFC

This section describes how to use SftTree/DLL in an application written using C++ and the Microsoft Foundation Class library (MFC).

Adding SftTree/DLL to an Application

Please see "Building Applications" to prepare a project for development with SftTree/DLL.

A)Every source program making use of a SftTree/DLL control must include the required header file SftTree.h by using the #include directive.
#include "SftTree.h" /* SftTree/DLL required header file */
This include statement should appear after the #include <stdafx.h> statement or can be included at the end of stdafx.h. The file is located in the directory \Program Files\Softelvdm\SftTree DLL 7.5\Include (unless changed during the installation). On Windows 64-bit versions, the root folder is \Program Files (x86).The project settings may need to be updated so the #include file can be located (see "Building Applications" for more information).
B)The source program SftTreeM.cpp must be added to your project. It is added to the project, without making any modifications to the file, using Visual Studio's Project, Add To Project, Files... menu command. The file is located in the directory \Program Files\Softelvdm\SftTree DLL 7.5\Include (unless changed during the installation). On Windows 64-bit versions, the root folder is \Program Files (x86).Instead of simply adding it to the project, you can include the file using the #include directive. However, it must be included in a source file (*.cpp) as it is not a header file and only one source file can #include the file SftTreeM.cpp.
#include "SftTreeM.cpp"
This include statement should appear after the #include "SftTree.h" statement.The project settings may need to be updated so the source file or #include file can be located (see "Building Applications" for more information).
C)In order to use SftTree/DLL controls, an application must call the CSftTree::RegisterApp function. The call to this function is required so that SftTree/DLL window classes can be registered. This call has to be made before any SftTree/DLL controls are created. Add the following statement to your source code. The preferred location is the InitInstance member function of your CWinApp or CSftTree_App based application object:
CSftTree::RegisterApp(); /* Use SftTree/DLL with this application */
D)Once SftTree/DLL controls are no longer needed, an application must call the CSftTree::UnregisterApp function. The call to this function is required so that SftTree/DLL window classes can be unregistered and cleanup processing can take place. This call has to be made after all SftTree/DLL controls have been destroyed. The preferred location is the ExitInstance member function of your CWinApp based application object:
CSftTree::UnregisterApp(); /* No longer use SftTree/DLL */
E)The application's executable (Exe or Dll) must be linked with the correct Lib file, depending on the target environment. Please see "Building Applications" for more information.The project settings may need to be updated so the Lib files can be located (see "Building Applications" for more information).

Adding a Tree Control

ClassWizard does not support new classes such as CSftTree, so any tree control instance variables, notification handlers, message map entries, etc., have to be added manually. To simplify this process, you can copy these items that are generated by ClassWizard for other "standard" Windows controls (such as a list box).

There are two methods to add a tree control to an application:

Adding a tree control using dialog resources is accomplished by using a resource editor to design a dialog. For more information, see "Creating a Dialog Resource". Once a tree control is created, its CSftTree based object can be obtained by using the Windows GetDlgItem function or attached to a CSftTree or CSftTreeSplit object using SubclassDlgItem.

CSftTree * pTree;
pTree = (CSftTree *) GetDlgItem(IDC_TREE);

or

CSftTree m_Tree;
m_Tree.SubclassDlgItem(IDC_TREE, this);

Another method to create a tree control is by using the CSftTree::Create or CSftTreeSplit::Create member function.

CSftTree m_Tree;
if (!m_Tree.Create(
        SFTTREESTYLE_NOTIFY | /* Notify parent window */
        SFTTREESTYLE_DRAGDROP | /* Drag & drop enabled */
        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(x, y, x+cx, y+cy), /* Location */
        this, /* Parent window */
        IDC_TREE)) /* Tree control ID */
    ; /* Error handling here */

For more information on the various parameters used, see the Create member function documentation.

Handling Notifications

As with standard Windows controls, applications must respond to events and messages to cause controls to respond to user requests. Most applications may want to implement some form of notification handler. By using the SftTree/DLL Wizard application, sample event handlers are generated for you.

ClassWizard does not support new classes such as CSftTree. So any tree control instance variables, notification handlers, message map entries, etc., have to be added manually. To simplify this process, you can copy these items that are generated by ClassWizard for other "standard" Windows controls (such as a list box).

Expanding/Collapsing Items

Note: A tree control will only send notification messages if its window style includes the SFTTREESTYLE_NOTIFY style.

By handling the appropriate notification, a tree control can respond to the mouse-button clicks on the small button bitmaps or (double-)clicks on other areas of the tree control. If an application does not implement an event handler, the tree items do not automatically expand and collapse. The following code sample illustrates how the notifications could be handled:

/* Add the following to your parent window class. */
afx_msg void OnLButtonExpandCollapse();
afx_msg void OnExpandAll();
afx_msg void OnAutoExpand();
/* Add the following to the parent window message map. */
ON_SFTTREEN_LBUTTONDOWN_BUTTON(IDC_TREE, OnLButtonExpandCollapse)
ON_SFTTREEN_LBUTTONDBLCLK_BUTTON(IDC_TREE, OnLButtonExpandCollapse)
ON_SFTTREEN_EXPANDALL(IDC_TREE, OnExpandAll)
ON_SFTTREEN_AUTOEXPANDING(IDC_TREE, OnAutoExpand)
/* Respond to events as the user clicks on different tree  */
/* components.  The events handled here can be changed to  */
/* suit your application.                                  */
void CYourClass::OnLButtonExpandCollapse()
{
    /* get index of item to expand/collapse */
    int index = m_Tree.GetExpandCollapseIndex();
    /* get current expand/collapsed status */
    BOOL fExpanded = m_Tree.GetItemExpand(index);
    /* if control key is used we'll expand all dependents */
    BOOL fDepth = (::GetKeyState(VK_CONTROL)&0x8000);

    if (fExpanded)
        m_Tree.Collapse(index, TRUE);
    else
        m_Tree.Expand(index, TRUE, fDepth);
}

/* Respond to numeric keypad multiply key.                 */

void CYourClass::OnExpandAll()
{
    /* get index of item to expand/collapse */
    int index = m_Tree.GetExpandCollapseIndex();

   m_Tree.Expand(index, TRUE, TRUE);
}

/* Auto-Expand                                             */

void CYourClass::OnAutoExpand()
{
    /* get index of item to expand/collapse */
    int index = m_Tree.GetExpandCollapseIndex();

    m_Tree.Expand(index, TRUE, FALSE);
}

Drag & Drop

Note: A tree control will only support drag & drop operations if its window style includes the SFTTREESTYLE_DRAGDROP style.

When a user initiates a drag & drop operation, a WM_COMMAND / SFTTREEN_BEGINDRAG notification is sent to the parent window. All items that are currently selected are part of the drag & drop operation. To abort the operation at this point, the application can clear all selections or send a WM_CANCELMODE message to the tree control. However, items may not be deleted or inserted during a drag & drop operation.

To find out more about the current drag & drop operation, an application can use GetDragInfo, which makes a pointer to a SFTTREE_DRAGINFO structure available. This area is only valid while processing one notification and must be retrieved for each notification. The SFTTREE_DRAGINFO structure fields are read/only unless otherwise indicated. GetDragInfo should be used when processing SFTTREEN_BEGINDRAG, SFTTREEN_DRAGGING and SFTTREEN_ENDDRAG or SFTTREEN_CANCELDRAG notifications.

A user can abort a drag & drop operation by pressing the Escape key, at which point an application will receive a SFTTREEN_CANCELDRAG notification.

For more information, see the SFTTREE_DRAGINFO structure.

Cell Editing

Note: A tree control will only generate the cell editing notifications if its window style includes the SFTTREESTYLE_NOTIFY style.

SftTree/DLL supports a very easy cell editing protocol. Unlike other custom controls, no new API has to be used to edit data in a SftTree/DLL tree control. Existing Windows controls can be used to edit cells, and because they are completely under your application's control, even owner-drawn controls and other custom controls can be used.

An application can "attach" a control to a SftTree/DLL control by creating the control and defining the tree control as the control's parent. This control, usually used to edit cells, is completely under your application's control. The tree control forwards all messages for the control directly to your application. This control can be created in response to a mouse button click (or double-click), or any other reasonable event in your application. Any Windows control can be used (edit controls, combo boxes, etc.). GetDisplayCellRect can be used to determine the proper location for the control.

This example shows how an application can respond to a left mouse-button double-click event by creating an edit control on the current item:

/* Cell Editing */
int m_editIndex;                     /* Index of item being edited */
int m_editCol;                       /* Column # being edited */
CEdit* m_pEdit;                      /* Control used for editing */

void StartEdit(int index, int col);  /* Start cell editing */
afx_msg void OnStartEdit();          /* Start cell editing */
afx_msg void OnQuitEdit();           /* Abandon cell editing */
afx_msg void OnValidateEdit();       /* Validate input */

/* Add the following to the window message map.            */

/* Cell Editing */
ON_SFTTREEN_LBUTTONDBLCLK_TEXT(IDC_TREE, OnStartEdit)
ON_SFTTREEN_QUITEDIT(IDC_TREE, OnQuitEdit)
ON_SFTTREEN_VALIDATEEDIT(IDC_TREE, OnValidateEdit)

/* Add the following to your parent window class           */
/* constructor.                                            */

m_pEdit = NULL;                      /* No cell editing */

/* These routines handle cell editing. In this example,    */
/* an edit control is used. Any Windows control can be     */
/* used, even custom controls.                             */

/* Edit a specific cell.                                   */

void CYourClass::StartEdit(int index, int col)
{
    CRect rect;

    /* Make the cell completely visible */
    m_Tree.MakeCellVisible(index, col);
    /* get the item location */
    if (!m_Tree.GetDisplayCellRect(index, col, TRUE, &rect, NULL))
        return;                          /* No column active */
    m_editIndex = index; /* save position */
    m_editCol = col;

    /* Change selection style to not shown anything */
    m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_NOTHING);

    /* Repaint now in case we scrolled to make item visible */
    m_Tree.UpdateWindow();

    /* Create the edit control.*/
    /* Based on the tree control attributes and your preference, you may */
    /* have to adjust the rectangle used for the edit control. */

    m_Tree.AdjustCellEditRect(m_editIndex, m_editCol, rect);
    CWnd* pEditParent = m_Tree.GetCellEditWindow(m_editIndex, m_editCol);
    m_pEdit = new CEdit;
    m_pEdit->Create(
            WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, /* Styles */
            rect,                        /* Coordinates */
            pEditParent,                 /* Parent window */
            IDC_EDIT_your_id);           /* <-- provide unique ID */

    /* Set some edit control attributes */

    /* Copy the font used for tree items */
    m_pEdit->SetFont(m_Tree.GetFont(), FALSE);

    /* Copy the text found in the tree control */
    CString str;
    m_Tree.GetText(m_editIndex, m_editCol, str);
    m_pEdit->SetWindowText(str);
    /* Select all text in the edit control and display it */
    m_pEdit->SetSel(0, -1, TRUE);
    m_pEdit->ShowWindow(SW_SHOW);
    m_pEdit->SetFocus();                 /* Set input focus to the control */
}

/* Start editing in response to a                          */
/* SFTTREEN_LBUTTONDBLCLK_TEXT notification.               */

void CYourClass::OnStartEdit()
{
    /* Get cell to edit (honors cell merging) */
    int index, col;
    index = m_Tree.GetCaretIndex();      /* Get item index */
    col = m_Tree.GetCaretColumn();       /* Get column number */
    StartEdit(index, col);
}

Once a tree control has one or more attached child windows, it generates the SFTTREEN_QUITEDIT and SFTTREEN_VALIDATEEDIT notifications, which signal the tree's parent window to abandon editing by destroying any associated controls, or to validate the input data, issue error messages and/or destroy the controls. When an application receives the SFTTREEN_QUITEDIT notification, it must unconditionally abort editing by destroying all child controls.

/* Quit editing in response to a SFTTREEN_QUITEDIT         */
/* notification.                                           */

void CYourClass::OnQuitEdit()
{
    if (m_pEdit) {
        /* If the control has the focus, set the focus back to the */
        /* tree control after destroying the control */

        BOOL fHadFocus = (GetFocus() == m_pEdit);

        m_pEdit->DestroyWindow();
        delete m_pEdit;
        m_pEdit = NULL;
        /* Restore nofocus display method */
        m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_KEEPSEL);
        if (fHadFocus)
            m_Tree.SetFocus();           /* Back to tree control */
    }
}

/* Validate edit data in response to a                     */
/* SFTTREEN_VALIDATEEDIT notification.                     */

void CYourClass::OnValidateEdit()
{
    if (m_pEdit) {
        CString str;

        /* Get the text from the edit control */
        m_pEdit->GetWindowText(str);

        /* Validate the data */
        if (str == _T("")) {
            AfxMessageBox(_T("Just to demonstrate data input validation, ")
               _T("this example rejects empty cells.  Please enter some data."));
            m_pEdit->SetFocus();
        } else {
            m_pEdit->DestroyWindow();
            delete m_pEdit;
            m_pEdit = NULL;
            /* Save the data in the tree control */
            m_Tree.SetText(m_editIndex, m_editCol, str);
            /* Restore nofocus display method */
            m_Tree.SetNoFocusStyle(SFTTREE_NOFOCUS_KEEPSEL);
        }
    }
}

While editing cells using a control, the user may abort editing by pressing the Escape key. This generates a SFTTREEN_QUITEDIT notification.

Additional Considerations

When creating controls for cell editing, a suitable font may have to be used. If a control is too small to display the data, the data may not only be clipped, but may even be completely suppressed. This is particularly noticeable with edit controls. An application can choose to increase the size of the control used for cell editing.

If cell editing is started under program control during a WM_INITDIALOG message or anytime the tree control has not yet been painted, the tree control has to be painted explicitly before a child control can be attached. This can be accomplished by using the UpdateWindow call.

3D Display

The extended window style WS_EX_CLIENTEDGE can be specified for the tree control, resulting in a 3D edge instead of a flat border.