Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

TreeView

Part of WindowsGuiCategory

Description

Demonstrates basic usage of Win32 TreeView control. Creates very simple tree, and responds to mouse click selections with confirmation in TextViewer. Only uses Win32 api calls ... no GUI framework. Buttons created, but only 'stubbed' functionality.

Example

/*
 *  Copyright (C) 2004 by Digital Mars, www.digitalmars.com
 *  Written by Lynn Allan by adapting code by Walter Bright
 *
 *  This software is provided 'as-is', without any express 
 *  or implied warranty. In no event will the authors be held
 *  liable for any damages arising from the use of this software.
 *
 *  Permission is granted to anyone to use this software for 
 *  any purpose, including commercial applications, and to alter
 *  it and redistribute it freely, subject to the following 
 *  restrictions:
 *
 *  o The origin of this software must not be misrepresented; 
 *    you must not claim that you wrote the original software.
 *    If you use this software in a product, an acknowledgment
 *    in the product documentation would be
 *    appreciated but is not required.
 *  o Altered source versions must be plainly marked as such,
 *    and must not be misrepresented as being the original
 *    software.
 *  o This notice may not be removed or altered from any source
 *    distribution.
 */

/* Compile with:
 *  dmd -O -release TreeView.d win32.lib gdi32.lib comctl32.lib TreeView.def
 *  or
 *  dmd -g -debug TreeView.d win32d.lib gdi32.lib comctl32.lib TreeView.def
 *
 * TreeView.def should contain:
 * EXETYPE NT
 * SUBSYSTEM WINDOWS
 */

import std.string;
import std.outbuffer;
import std.c.windows.windows;
import win32.commctrl;


const int IDC_BTN_BOOKS = 103;
const int IDC_BTN_SEARCH = 104;
const int IDC_EDIT_SEARCH_WORDS = 105;

const int IDC_EDIT_TEXT_VIEWER = 106;
const int IDC_BTN_OPTIONS = 107;
const int IDC_BTN_HELP = 108;

const int IDC_TREE_CHAP_SELECTOR = 109;
const int IDC_LIST_SEARCH_MATCHES_LIST = 110;

static HINSTANCE ghInstance;

static HWND      ghBooksBtn;
static HWND      ghChapSelectorTree;
static HWND      ghHelpBtn;
static HWND      ghOptionsBtn;
static HWND      ghSearchBtn;
static HWND      ghSearchWordsEdit;

static HWND      ghTextViewerEdit;
static HWND      ghWndMain;
static HTREEITEM gbHcsBook[68];

void CreateControls()
{
  HWND hChapSelectorTree;
  
  ghBooksBtn = CreateWindowA("BUTTON", "Books", 
                     WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
                     5, 5, 53, 25, ghWndMain, 
                             cast(HMENU) IDC_BTN_BOOKS, ghInstance, null);
  ghSearchBtn = CreateWindowA("BUTTON", "Search", 
                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
                      58, 5, 53, 25, ghWndMain, 
                      cast(HMENU) IDC_BTN_SEARCH, ghInstance, null);

  ghSearchWordsEdit = CreateWindowA("EDIT", "", 
                            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT,
                            115, 5, 145, 25, ghWndMain, 
                            cast(HMENU) IDC_EDIT_SEARCH_WORDS, ghInstance, null);

  ghOptionsBtn = CreateWindowA("BUTTON", "Options", 
                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
                       265, 5, 53, 25, ghWndMain, 
                       cast(HMENU) IDC_BTN_OPTIONS, ghInstance, null);

  ghHelpBtn = CreateWindowA("BUTTON", "Help", 
                            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
                            320, 5, 53, 25, ghWndMain, 
                            cast(HMENU) IDC_BTN_HELP, ghInstance, null);

  ghTextViewerEdit = CreateWindowA("EDIT", "", 
                           WS_CHILD | WS_VISIBLE | WS_BORDER 
                           | ES_AUTOVSCROLL | WS_VSCROLL
                           | ES_LEFT | ES_MULTILINE | ES_NOHIDESEL,
                           115, 32, 260, 300, ghWndMain, 
                           cast(HMENU) IDC_EDIT_TEXT_VIEWER, ghInstance, null);

  SendMessageA(ghTextViewerEdit, WM_SETTEXT, 0, 

      cast(int)cast(char*)"Hello\x0D\x0A"
                          "Line 2\x0D\x0A"
                          "Line 3\x0D\x0A"

                          "Long Line 4 to check word wrap aaa bbb ccc ddd eee "
                          "fff ggg hhh iii jjj kkk lll mmm\x0D\x0A"
                          "Line 5\x0D\x0A"
                          "Line 6");


  InitCommonControls();

  hChapSelectorTree = CreateWindowA("SYSTREEVIEW32", "", 
                            WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES |
                            WS_CLIPSIBLINGS | TVS_HASBUTTONS | TVS_LINESATROOT,
                            5, 32, 110, 300, ghWndMain, 
                            cast(HMENU) IDC_TREE_CHAP_SELECTOR, ghInstance, null);
  if (hChapSelectorTree == null) {
    MessageBoxA(null, cast(char *)("ChapSelector Tree not created!"), 
                "Error", MB_OK | MB_ICONEXCLAMATION);
  }
  else {
    ghChapSelectorTree = hChapSelectorTree;
  }
}


void DoMessagePump()
{
  MSG msg;
  while (GetMessageA(&msg, cast(HWND) null, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessageA(&msg);
  }
}


void CreateMainWindow()
{
  HWND hWnd;
  hWnd = CreateWindowA("DWndClass", "TreeView Example", 
               WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX 
               | WS_SYSMENU | WS_VISIBLE,
               CW_USEDEFAULT, CW_USEDEFAULT, 385, 375, HWND_DESKTOP,
               cast(HMENU) null, ghInstance, null);
  assert(hWnd);
  ghWndMain = hWnd;
}


void InitApplication()
{
  WNDCLASS wc;
  wc.lpszClassName = "DWndClass";
  wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = &WindowProc;
  wc.hInstance = ghInstance;
  wc.hIcon = LoadIconA(cast(HINSTANCE) null, IDI_APPLICATION);
  wc.hCursor = LoadCursorA(cast(HINSTANCE) null, IDC_CROSS);
  wc.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = null;
  wc.cbClsExtra = wc.cbWndExtra = 0;

  assert(RegisterClassA(&wc));
}

void InitInstance()
{
  ghInstance = GetModuleHandleA(null);
  InitApplication();

  CreateMainWindow();
  CreateControls();
  LoadChapSelector();
}

void LoadChapterText(LPARAM lParam)
{
  LPNM_TREEVIEWA pnmtv = cast(LPNM_TREEVIEWA) lParam;
  TV_ITEMA tvI;
  char szText[256];

  tvI.mask = TVIF_TEXT | TVIF_PARAM;
  tvI.pszText = szText;
  tvI.cchTextMax = 32;
  tvI.hItem = pnmtv.itemNew.hItem;

  SendMessageA(ghChapSelectorTree, TVM_GETITEM, 0, 

               cast(int)cast(TV_ITEMA*)&tvI);

  OutBuffer buf = new OutBuffer;
  buf.reserve(32);
  buf.write(toString(tvI.pszText));
  buf.write(" = ");
  buf.write(toString(tvI.lParam));

  SendMessageA(ghTextViewerEdit, WM_SETTEXT, 0, 

               cast(int)cast(char*)buf.toString());
}

void LoadBook(int bookNum, char[] bookName, 
              char[] bookAbbrev, int chapCount)
{
  TV_ITEMA tvI;
  TV_INSERTSTRUCTA tvIns;

  tvI.mask = TVIF_TEXT | TVIF_PARAM;
  tvI.pszText = bookName;
  tvI.cchTextMax = 10;
  tvI.lParam = bookNum * 1000;
  tvIns.item = tvI;
  tvIns.hInsertAfter = cast(HTREEITEM)TVI_ROOT;
  tvIns.hParent = null;
  gbHcsBook[bookNum] = cast(HTREEITEM)SendMessageA(ghChapSelectorTree, 
                                                   TVM_INSERTITEM, 0, 

                                                   cast(int)&tvIns);

  tvI.cChildren = 0;

  tvIns.hParent = gbHcsBook[bookNum];
  tvIns.hInsertAfter = cast(HTREEITEM)TVI_LAST;

  for (int i = 1; i <= chapCount; ++i) {
    tvI.pszText = bookAbbrev ~ "." ~ toString(i);
    tvI.lParam = bookNum * 1000 + i;
    tvIns.item = tvI;
    SendMessageA(ghChapSelectorTree, 
                 TVM_INSERTITEM, 0, 

                 cast(int)&tvIns);
  }
}

void LoadChapSelector()
{
  LoadBook(1, "Genesis", "Gen", 10);
  LoadBook(2, "Exodus", "Exo", 8);
  LoadBook(3, "Leviticus", "Lev", 4);
  LoadBook(4, "Numbers", "Num", 6);
}


/**********************************************************/

/* Note the similarity of this code to the console D startup
 * code in \dmd\src\phobos\dmain2.d
 * You'll also need a .def file with at least the following in it:
 *  EXETYPE NT
 *  SUBSYSTEM WINDOWS
 */

extern (C) void gc_init();
extern (C) void gc_term();

extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleUnitTests();


extern (Windows)
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
            LPSTR lpCmdLine, int nCmdShow)
{
  int result = 1;

  gc_init();    // initialize garbage collector
  _minit();     // initialize module constructor table

  try {
    _moduleCtor();      // call module constructors
    _moduleUnitTests(); // run unit tests (optional)

    InitInstance();
  DoMessagePump();
  }
  catch (Object o) {    // catch any uncaught exceptions

    MessageBoxA(null, cast(char *)o.toString(), "Error",
                MB_OK | MB_ICONEXCLAMATION);
    result = 0;   // failed
  }
  gc_term();      // run finalizers; terminate garbage collector

  return result;
}

extern(Windows)
int WindowProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam)
{
  LPNMHDR  pnmhdr;

  switch (uMsg) {
    case WM_COMMAND: {
      switch (LOWORD(wParam)) {
        case IDC_BTN_BOOKS:
          if (HIWORD(wParam) == BN_CLICKED) {
            MessageBoxA(hWnd, "Clicked", "Books",
                        MB_OK | MB_ICONINFORMATION);
          }
          break;
        case IDC_BTN_SEARCH:
          if (HIWORD(wParam) == BN_CLICKED) {
            MessageBoxA(hWnd, "Clicked", "Search",
                        MB_OK | MB_ICONEXCLAMATION);
          }
          break;
        case IDC_BTN_OPTIONS:
          if (HIWORD(wParam) == BN_CLICKED) {
            MessageBoxA(hWnd, "Clicked", "Options",
                        MB_OK | MB_ICONEXCLAMATION);
          }
          break;
        case IDC_BTN_HELP:
          if (HIWORD(wParam) == BN_CLICKED) {
            MessageBoxA(hWnd, "Clicked", "Help",
                        MB_OK | MB_ICONEXCLAMATION);
          }
          break;
        case IDC_EDIT_SEARCH_WORDS:
          if (HIWORD(wParam) == BN_CLICKED) {
            MessageBoxA(hWnd, "Clicked", "Search Words",
                        MB_OK | MB_ICONEXCLAMATION);
          }
          break;
        case IDC_EDIT_TEXT_VIEWER:
          if (HIWORD(wParam) == BN_CLICKED) {
            MessageBoxA(hWnd, "Clicked", "Text Viewer",
                        MB_OK | MB_ICONEXCLAMATION);
          }
          break;
      }
      break;
    }
    case WM_DESTROY:
      PostQuitMessage(0);

      break;

    case WM_NOTIFY:
      pnmhdr = cast(LPNMHDR)lParam;
      if (pnmhdr.hwndFrom == cast(HANDLE)ghChapSelectorTree) {
        UINT code = pnmhdr.code;
        if (code == TVN_SELCHANGED || code == TVN_KEYDOWN) {
          LoadChapterText(lParam);
        }
      }
      break;

    default:
      break;
  }
  return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}

Requirements

This example requires Core32.

Source

Posted by Lynn
Date/Time Sat Sep 25, 2004 9:25 am