Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

Using C

This section describes how to use SftTree/DLL in an application written using the C programming language.

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 <windows.h> statement. 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)In order to use SftTree/DLL controls, an application must call the SftTree_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, where your application registers its window classes (normally during application initialization):
SftTree_RegisterApp(hInstance); /* Use SftTree/DLL with this application */
C)Once SftTree/DLL controls are no longer needed, an application must call the SftTree_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 (normally during application termination).
SftTree_UnregisterApp(hInstance); /* No longer use SftTree/DLL */
D)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

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

  • using dialog resources
  • using CreateWindow(Ex)

Adding a tree control using dialog resources is accomplished by using a resource editor to design a dialog. Once a tree control is created, its window handle can be obtained by using the Windows GetDlgItem function. For more information, see "Creating a Dialog Resource".

Another method to create a tree control is by using the CreateWindow(Ex) Windows call:

hwndTree = CreateWindow(
    TEXT(SFTTREE_CLASS), /* Window class */
    TEXT(""), /* Caption (none) */
    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 */
    x, y, cx, cy, /* Location */
    hwndParent, /* Parent window */
    (HMENU) IDC_TREE, /* Tree control ID */
    app_instance, /* Application instance */
    NULL);
if (g_hwndTree == NULL)
    ; /* Error handling here */

For more information on the various parameters used, see the Windows API 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. For additional information, see "Notifications".

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:

case WM_COMMAND:                     /* WM_COMMAND message handler */
    if ((int) LOWORD(wParam) == IDC_TREE) {
        switch(HIWORD(wParam)) {
        case SFTTREEN_LBUTTONDBLCLK_TEXT:
        case SFTTREEN_LBUTTONDOWN_BUTTON:
        case SFTTREEN_LBUTTONDBLCLK_BUTTON: {
            int index;
            BOOL fExpand, fControl;
            /* Get current position */
            index = SftTree_GetExpandCollapseIndex(hwndTree);
            /* Check if item is expanded */
            fExpand = SftTree_GetItemExpand(hwndTree, index);
            /* If the CONTROL key is pressed, expand all dependent levels */
            fControl = (BOOL)(GetKeyState(VK_CONTROL)&0x8000);
            if (fExpand)
                SftTree_Collapse(hwndTree, index, TRUE);
            else
                SftTree_Expand(hwndTree, index, TRUE, fControl);
            break;
         }
        case SFTTREEN_EXPANDALL: { // expand all
            int index;
            index = SftTree_GetExpandCollapseIndex(hwndTree);
            SftTree_Expand(hwndTree, index, TRUE, TRUE);
            break;
         }
        case SFTTREEN_AUTOEXPANDING: {
            int index;
            index = SftTree_GetExpandCollapseIndex(hwndTree);
            SftTree_Expand(hwndTree, index, TRUE, FALSE);
            break;
         }
        }
    }
    break;

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 SftTree_GetDragInfo, which makes a pointer to a SFTTREE_DRAGINFO structure available. This area is only valid while processing one WM_COMMAND notification and must be retrieved for each notification. The SFTTREE_DRAGINFO structure members are read/only unless otherwise indicated. SftTree_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.). SftTree_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:

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

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

int m_editIndex;                         /* Index of item being edited */
int m_editCol;                           /* Column # being edited */
HWND m_hwndEdit;                         /* Control used for editing */

/* Edit a specific cell.                                   */

static void StartEdit(int index, int col)
{
    TCHAR szBuffer[80];
    RECT rect;
    HWND EditParent;

    /* Make the cell completely visible */
    SftTree_MakeCellVisible(hwndTree, index, col);
    /* Get the location */
    if (!SftTree_GetDisplayCellRect(hwndTree, index, col, TRUE, &rect, NULL))
        return;
    m_editIndex = index; /* save position */
    m_editCol = col;

    /* Change selection style to not shown anything */
    SftTree_SetNoFocusStyle(hwndTree, SFTTREE_NOFOCUS_NOTHING);

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

    /* 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. */

    SftTree_AdjustCellEditRect(hwndTree, m_editIndex, m_editCol, &rect);
    EditParent = SftTree_GetCellEditWindow(hwndTree, m_editIndex, m_editCol);
    m_hwndEdit = CreateWindow(TEXT("EDIT"), TEXT(""),/* Class, Title */
            WS_CHILD|WS_BORDER|ES_LEFT|ES_AUTOHSCROLL, /* Styles */
            rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
            EditParent,                  /* Tree control */
            (HMENU) IDC_EDIT_your_id,    /* <-- provide unique ID */
            app_instance,                /* <-- provide instance handle */
            NULL);
    if (!m_hwndEdit)                     /* Failed */
        return;

    /* Set some edit control attributes */

    /* Copy the font used for tree items */
    SendMessage(m_hwndEdit, WM_SETFONT, SendMessage(hwndTree, WM_GETFONT, 0, 0L), 0L);

    /* Copy the text found in the tree control */
    SftTree_GetTextCol(hwndTree, m_editIndex, m_editCol, szBuffer);
    SetWindowText(m_hwndEdit, szBuffer);
    /* Select all text in the edit control and display it */
    SendMessage(m_hwndEdit, EM_SETSEL, 0, -1L);
    ShowWindow(m_hwndEdit, SW_SHOW);
    SetFocus(m_hwndEdit);                /* Set input focus to the control */
}

. . .
case WM_COMMAND:                     /* WM_COMMAND message handler */
    if ((int) LOWORD(wParam) == IDC_TREE) {
        switch(HIWORD(wParam)) {
        case SFTTREEN_LBUTTONDBLCLK_TEXT: {
            /* Edit the current cell */
            /* Get cell to edit (honors cell merging) */
            int index, col;
            index = SftTree_GetCaretIndex(hwndTree);/* Get item index */
            col = SftTree_GetCaretColumn(hwndTree);/* Get column number */
            StartEdit(index, col);
            break;
         }
        case SFTTREEN_QUITEDIT:
            /* Abandon editing */
            QuitEdit();
            break;
        case SFTTREEN_VALIDATEEDIT:
            /* Validate input data */
            ValidateEdit();
            break;
        }
    }
    break;

Once a tree control has an attached child window, 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.                                           */

static void QuitEdit(void)
{
    if (m_hwndEdit) {
        /* If the control has the focus, set the focus back to the */
        /* tree control after destroying the control */

        BOOL fHadFocus = (GetFocus() == m_hwndEdit);

        DestroyWindow(m_hwndEdit);
        m_hwndEdit = NULL;
        /* Restore nofocus display method */
        SftTree_SetNoFocusStyle(hwndTree, SFTTREE_NOFOCUS_KEEPSEL);
        if (fHadFocus)
            SetFocus(hwndTree);          /* Back to tree control */
    }
}

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

static void ValidateEdit(void)
{
    if (m_hwndEdit) {
        TCHAR szBuffer[80];

        /* Get the text from the edit control */
        GetWindowText(m_hwndEdit, szBuffer, sizeof(szBuffer));

        /* Validate the data */
        if (lstrcmp(TEXT(""), szBuffer) == 0) {
            MessageBox(NULL, TEXT("Just to demonstrate data input validation, this example ")
                   TEXT("rejects empty cells.  Please enter some data."),
                   TEXT("SftTree/DLL"), MB_OK|MB_TASKMODAL|MB_ICONSTOP);
            SetFocus(m_hwndEdit);
        } else {
            DestroyWindow(m_hwndEdit);
            m_hwndEdit = NULL;
            /* Save the data in the tree control */
            SftTree_SetTextCol(hwndTree, m_editIndex, m_editCol, szBuffer);
            /* Restore nofocus display method */
            SftTree_SetNoFocusStyle(hwndTree, 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.