Treeview

Tree-view là 1 dạng cửa sổ hiển thị 1 danh sách các item dạng parent-child.


Ví dụ bạn hay gặp nhất là trình quản lý thư mục của Windows OS.

Tree view
#include "windows.h"
#include "commctrl.h"

#define ID_TREEVIEW 100

HINSTANCE g_hInst;

HWND CreateATreeView(HWND hwndParent);
HTREEITEM AddItemToTree(HWND hwndTV, LPTSTR lpszItem, int nLevel);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// Ham Winmain()
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    MSG  msg ;
    HWND hwnd;
    WNDCLASS wc;
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.lpszClassName = TEXT( "TreeView" );
    wc.hInstance     = hInstance ;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName  = NULL;
    wc.lpfnWndProc   = WndProc;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    
    RegisterClass(&wc);
    // Create parent window
    hwnd = CreateWindow( wc.lpszClassName, TEXT("Menu"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250,350, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);   // Update windows

    while( GetMessage(&msg, NULL, 0, 0))
    {
        DispatchMessage(&msg);
    }
    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch(msg)
    {
    case WM_CREATE:
    {
        HWND hwndTreeview;
        hwndTreeview = CreateATreeView(hwnd);
        AddItemToTree(hwndTreeview, L"Drink", 1);
        AddItemToTree(hwndTreeview, L"Orange juice", 2);
        AddItemToTree(hwndTreeview, L"Price: 20K", 3);
        AddItemToTree(hwndTreeview, L"Coffee", 2);
        AddItemToTree(hwndTreeview, L"Price: 25K", 3);
        AddItemToTree(hwndTreeview, L"Tea", 2);
        AddItemToTree(hwndTreeview, L"Price: 15K", 3);
        break;
    }
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        return 0;
    }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

// Ham tao treeview
HWND CreateATreeView(HWND hwndParent)
{
    RECT rcClient;  // dimensions of client area
    HWND hwndTV;    // handle to tree-view control

    // Ensure that the common control DLL is loaded.
    InitCommonControls();

    // Get the dimensions of the parent window's client area, and create
    // the tree-view control.
    GetClientRect(hwndParent, &rcClient);
    hwndTV = CreateWindowEx(0, WC_TREEVIEW, TEXT("Tree View"), WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES, 0, 0, rcClient.right, rcClient.bottom, hwndParent, (HMENU)ID_TREEVIEW, g_hInst, NULL);
    return hwndTV;
}

HTREEITEM AddItemToTree(HWND hwndTV, LPTSTR lpszItem, int nLevel)
{
    TVITEM tvi;
    TVINSERTSTRUCT tvins;
    static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST;
    static HTREEITEM hPrevRootItem = NULL;
    static HTREEITEM hPrevLev2Item = NULL;
    HTREEITEM hti;

    tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
    
    // Set the text of the item.
    tvi.pszText = lpszItem;
    tvi.cchTextMax = sizeof(tvi.pszText)/sizeof(tvi.pszText[0]);

    // Assume the item is not a parent item, so give it a
    // document image.
    tvi.iImage = 0;
    tvi.iSelectedImage = 0;

    // Save the heading level in the item's application-defined
    // data area.
    tvi.lParam = (LPARAM)nLevel;
    tvins.item = tvi;
    tvins.hInsertAfter = hPrev;

    // Set the parent item based on the specified level.
    if (nLevel == 1)
        tvins.hParent = TVI_ROOT;
    else if (nLevel == 2)
        tvins.hParent = hPrevRootItem;
    else
        tvins.hParent = hPrevLev2Item;

    // Add the item to the tree-view control.
    hPrev = (HTREEITEM)SendMessage(hwndTV, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);

    if (hPrev == NULL)
        return NULL;

    // Save the handle to the item.
    if (nLevel == 1)
        hPrevRootItem = hPrev;
    else if (nLevel == 2)
        hPrevLev2Item = hPrev;

    // The new item is a child item. Give the parent item a
    // closed folder bitmap to indicate it now has child items.
    if (nLevel > 1)
    {
        hti = TreeView_GetParent(hwndTV, hPrev);
        tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
        tvi.hItem = hti;
        tvi.iImage = 0;
        tvi.iSelectedImage = 0;
        TreeView_SetItem(hwndTV, &tvi);
    }
    return hPrev;
}

Giải thích:
Thư viện

#include "commctrl.h"

Chứa các function liên quan đến các lớp cửa sổ common control.

hwnd = CreateWindow( wc.lpszClassName, TEXT("Menu"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250,350, NULL, NULL, hInstance, NULL);

Trong bài này, tôi có ý định tạo 1 cửa sổ cha (parent) với title là “Menu” với kích thước như hàm khai báo ở trên. Sau đó, tôi sẽ tạo cửa sổ treeview là cửa sổ con (child) của cửa sổ parent. Cửa sổ treeview này có chức năng hiển thị 1 menu đồ uống như: Orange juice, Coffee, Tea,… Khi người dùng click vào tên 1 đồ uống bất kì, thì giá của loại đồ uống đó sẽ được hiển thị dưới dạng cây.

hwndTreeview = CreateATreeView(hwnd);

Hàm này để tạo treeview.
Trong đó:
– Giá trị truyền vào là handler của cửa sổ cha.
– Giá trị trả về: là handler trỏ tới treeview vừa được tạo.

InitCommonControls();

Treeview là 1 trong các loại cửa sổ kiểu common control (treeview, tooltip, trackbar, …). Do vậy, cần gọi hàm này trước khi tạo treeview.

GetClientRect(hwndParent, &rcClient);

Hàm này lấy tọa độ (left, right, top, bottom) của cửa sổ parent và lưu vào biến rcClient.

hwndTV = CreateWindowEx(0, WC_TREEVIEW, TEXT("Tree View"), WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES, 0, 0, rcClient.right, rcClient.bottom, hwndParent, (HMENU)ID_TREEVIEW, g_hInst, NULL);

Để tạo treeview ta dùng hàm CreateWindowEx() với hằng số WC_TREEVIEW được truyền cho tham số lpClassName.
Trong đó:
– rcClient.right : là chiều rộng của cửa sổ cha (parent)
– rcClient.bottom : là chiều cao của cửa sổ cha (parent)
– ID_TREEVIEW : là ID của treeview (là hằng số nguyên, người lập trình tự định nghĩa)
– g_hInst: là biến instant global. (Trong bài này, biến này không có nhiều ý nghĩa. Tôi sẽ giới thiệu trong các bài viết sắp tới).

AddItemToTree(hwndTreeview, L"Drink", 1);
AddItemToTree(hwndTreeview, L"Orange juice", 2);
AddItemToTree(hwndTreeview, L"Price: 20K", 3);
AddItemToTree(hwndTreeview, L"Coffee", 2);
AddItemToTree(hwndTreeview, L"Price: 25K", 3);
AddItemToTree(hwndTreeview, L"Tea", 2);
AddItemToTree(hwndTreeview, L"Price: 15K", 3);

Các hàm trên add các item vào cửa sổ treeview vừa được tạo.
Trong đó:
– hwndTreeview: handler trỏ tới treeview được tạo.
– “Drink”, “Orange juice”,… là các item và sub-item của treeview.

Dưới đây, ta sẽ đi tìm hiểu hàm AddItemToTree() cụ thể.

Kết quả:

Tree view

Be the first to comment

Leave a Reply