Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Windows 95 для программиста

© Александр Фролов, Григорий Фролов
Том 22, М.: Диалог-МИФИ, 1993, 271 стр.

[Назад] [Содеожание] [Дальше]

4.1. Создание органа управления Tree View

Ниже мы перечислили основные действия, которое должно выполнить приложение для того чтобы создать орган управления Tree View:

  • создать окно на базе предопределенного класса окна WC_TREEVIEW ;
  • создать список изображений, которые будут использованы для отображения состояния строк;
  • добавить изображения в созданный список;
  • подключить список изображений к органу управления Tree View;
  • вставить элементы с учетом их иерархического расположения в дереве.

Создание окна Tree View

Окно органа управления Tree View создается функцией CreateWindowEx на базе класса окна WC_TREEVIEW:

hwndTree = CreateWindowEx(0L, WC_TREEVIEW, "",
    WS_VISIBLE | WS_CHILD | WS_BORDER |
    TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT,
    0, 0, rc.right - rc.left, rc.bottom - rc.top,
    hWnd, (HMENU) IDC_TREEVIEW, hInst, NULL);

Перед вызовом этой функции (как и для других рассмотренных в этой книге органов управления) вы должны загрузить в память DLL-библиотеку COMCTL32.DLL . Это можно сделать при помощи функции InitCommonControls , вызвав ее без параметров.

Для окна органа управления Tree View вы можете использовать следующие дополнительные стили окна:

Стиль Описание
TVS_HASBUTTONS Если указан стиль TVS_HASBUTTONS, создается кнопка небольших размеров, внутри которой может отображаться символ "+" или "-". Эта кнопка используется для того чтобы раскрыть или закрыть список вложенных элементов
TVS_HASLINES Для отображения иерархии элементов используются пунктирные линии
TVS_LINESATROOT Указанные выше линии используются и для присоединения корневого элемента дерева. Этот стиль должен использоваться совместно со стилем TVS_HASLINES
TVS_EDITLABELS Этот стиль позволяет пользователю редактировать название элемента списка
TVS_SHOWSELALWAYS Выбранные элементы списка отображаются с выделением даже в том случае, когда орган управления Tree View не активен
TVS_DISABLEDROP Если указан этот стиль, орган управления Tree View не посылает родительскому окну извещение TVN_BEGINDRAG

Дополнительные стили окна могут комбинироваться между собой и со стандартными стилями окна при помощи логической операции ИЛИ.

С помощью пары функций GetWindowLong и SetWindowLong приложение может изменить стиль созданного ранее окна органа управления Tree View (можно использовать тот же способ, что и для органа управления List View).

Создание списка изображений

Для органа управления Tree View вы должны создать список изображений, которые будут использованы для отображения состояния элементов дерева.

Заметим, что каждый элемент может находиться в выбранном или невыбранном состоянии. Соответственно, для отображения этих состояний вы можете использовать разные изображения.

Список изображений создается рассмотренной нами ранее функцией ImageList_Create :

HIMAGELIST WINAPI ImageList_Create(
  int  cx,       // ширина изображения
  int  cy,       // высота изображения
  UINT flags,    // тип изображения
  int  cInitial, // первоначальное количество изображений
  int  cGrow);   // количество изображений, на которое 
    // увеличится размер списка при добавлении новых изображений

Вот, например, как создается список из трех изображений размером 33 х 33 пиксела в нашем приложении Some Books, исходные тексты которого мы приведем немного позже:

himl = ImageList_Create(33, 33, FALSE, 3, 0);

Заполнение списка изображений

Обычно в список изображений для органа управления Tree View добавляют не пиктограммы, имеющие квадратную форму и относительно большой размер, и битовые изображения. Это можно сделать при помощи макрокоманды ImageList_Add :

hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BOOKS));
idxBooks = ImageList_Add(himl, hBmp, NULL);

hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BOOK_CLOSED));
idxBookClosed = ImageList_Add(himl, hBmp, NULL);

hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BOOK_OPENED));
idxBookOpened = ImageList_Add(himl, hBmp, NULL);

Эта макрокоманда возвращает номера добавленных изображений, которые потребуются в дальнейшем при добавлении элементов в дерево.

Подключение списка изображений

Созданный список изображений подключается к органу управления Tree View при помощи макрокоманды TreeView_SetImageList :

HIMAGELIST TreeView_SetImageList(
  HWND hwnd,       // идентификатор окна органа Tree View
  HIMAGELIST himl, // идентификатор подключаемого списка
  int iImageTree); // тип изображений в списке

Первые два параметра макрокоманды задают, соответственно, идентификатор окна органа Tree View и идентификатор подключаемого списка, который мы только что создали и заполнили.

Параметр iImageTree может иметь следующие значения:

Значение Описание
TVSIL_NORMAL Обычные список изображений для отображения выбранного и невыбранного состояния элементов дерева
TVSIL_STATE Список содержит изображения, которые используются для отображения состояния элементов дерева (из-за недостатка места в нашей книге не рассматривается)

Ниже приведена строка исходного текста приложения, подключающая список изображений himl к органу управления hwndTree:

TreeView_SetImageList(hwndTree, himl, TVSIL_NORMAL);

Вставка элементов дерева

Вставка элементов в дерево выполняется при помощи макрокоманды TreeView_InsertItem , которая посылает органу управления Tree View сообщение TVM_INSERTITEM :

HTREEITEM TreeView_InsertItem(
  HWND hwnd,          // идентификатор окна органа Tree View
  TV_INSERTSTRUCT lpis); // указатель на структуру TV_INSERTSTRUCT

Через параметр hwnd Этой макрокоманде необходимо передать идентификатор созданного органа управления Tree View, а через параметр lpis - адрес структуры типа TV_INSERTSTRUCT . Эта структура и указатель на нее определены так:

typedef struct _TV_INSERTSTRUCT 
{  
  HTREEITEM hParent;  // идентификатор родительского элемента   
  HTREEITEM hInsertAfter; // идентификатор элемента, после
                          // которого будет выполнена вставка
  TV_ITEM   item;         // информация о вставляемом элементе
} TV_INSERTSTRUCT, FAR  *LPTV_INSERTSTRUCT; 

Если вставляется корневой элемент, поле hParent должно содержать значение TVI_ROOT или NULL. Если же вставляется вложенный элемент, в это поле необходимо записать идентификатор родительского элемента (т. е. элемента, расположенного выше по иерархии).

В поле hInsertAfter следует записать идентификатор элемента, после которого будет вставлен данный элемент или одно из следующих значений:

Значение Расположение вставляемого элемента
TVI_FIRST В начале списка
TVI_LAST В конце списка
TVI_SORT По алфавитному порядку

Структура item содержит информацию о вставляемом элементе. Соответствующий тип TV_ITEM определен следующим образом:

typedef struct _TV_ITEM
{
  UINT   mask  // маска использования полей структуры TV_ITEM
  HTREEITEM hItem;      // номер элемента 
  UINT      state;      // текущее состояние элемента 
  UINT      stateMask;  // маска состояния элемента
  LPSTR     pszText;    // адрес текстового буфера
  int       cchTextMax; // размер текстового буфера 
  int       iImage; // номер изображения невыбранного элемента
  int iSelectedImage;// номер изображения выбранного элемента
  int       cChildren;      // флаг дочерних элементов
  LPARAM  lParam;// 32-битное значение, связанное с элементом 
} TV_ITEM, FAR  *LPTV_ITEM;

Назначение большинства полей такое же, как и одноименных полей структуры LV_ITEM.

Поле маски mask определяет, какие из полей структуры TV_ITEM будут использованы при добавлении элементов. Возможны следующие значения масок (их можно объединять при помощи логической операции ИЛИ):

Маска Заполненное поле структуры TV_ITEM
TVIF_TEXT pszText
TVIF_IMAGE iImage
TVIF_SELECTEDIMAGE iSelectedImage
TVIF_PARAM lParam
TVIF_CHILDREN cChildren
TVIF_HANDLE hItem
TVIF_STATE state

В поля iImage и iSelectedImage следует записать номера изображений из списка, которые будут использованы для элемента, соответственно, в выбранном и невыбранном состоянии.

Поле cChildren содержит флаг, который показывает, есть ли у данного элемента связанные с ним дочерние элементы. Если есть, то в этом поле должно быть записано значение 1, в противном случае - 0. Если же в поле cChildren записать значение I_CHILDRENCALLBACK, приложение должно обрабатывать извещения TVN_GETDISPINFO и TVN_SETDISPINFO (аналогичные извещениям LVN_GETDISPINFO и LVN_SETDISPINFO, которые посылаются органу управления List View).

Для удобства в приложении Some Books мы добавляем элементы дерева при помощи функции InsTreeItem, исходный текст которой приведен ниже:

HTREEITEM InsTreeItem(HTREEITEM hParent, LPSTR szText, 
  HTREEITEM hAfter, int iImage, int iSelectedImage)
{
  TV_INSERTSTRUCT tvins;
  HTREEITEM hItem;

  memset(&tvins, 0, sizeof(tvins));
  tvins.item.mask = TVIF_TEXT | TVIF_IMAGE | 
     TVIF_SELECTEDIMAGE | TVIF_PARAM;
  tvins.item.pszText = szText;
  tvins.item.cchTextMax = lstrlen(szText);
  tvins.item.iImage = iImage;
  tvins.item.iSelectedImage = iSelectedImage;
  tvins.hInsertAfter = hAfter;
  tvins.hParent = hParent;
  
  hItem = TreeView_InsertItem(hwndTree, &tvins); 
  return hItem;
} 

Процедура заполнения дерева в приложении Some Books выглядит следующим образом.

Вначале мы вставляем корневой элемент, которому соответствует строка szBooks ("Книги издательства АО 'Диалог-МИФИ'"):

hItem = InsTreeItem((HTREEITEM)TVI_ROOT, szBooks, 
    (HTREEITEM)TVI_FIRST, idxBooks, idxBooks);

Этот элемент является корневым, поэтому параметр hParent имеет значение TVI_ROOT. Вставляемый элемент будет расположен первым по порядку, так как для параметра hAfter задано значение TVI_FIRST.

Далее мы вставляем два элемента, расположенные ниже по иерархии (первый уровень вложенности). Это текстовые строки szBSPSeries ("Библиотека системного программиста, (C) Фролов А.В., Фролов Г.В., 1991-1995 г.") и szStepSeries ("Персональный компьютер. Шаг за шагом, (C) Фролов А.В., Фролов Г.В., 1994-1995 г."):

hBSPItem = InsTreeItem(hItem, szBSPSeries, 
  (HTREEITEM)TVI_SORT, idxBooks, idxBooks);
hStepItem = InsTreeItem(hItem, szStepSeries, 
  (HTREEITEM)TVI_SORT, idxBooks, idxBooks);

Затем для каждого элемента первого уровня вставляем по два элемента второго уровня:

InsTreeItem(hBSPItem, rgSPLBookInfo[0].szBookName, 
  (HTREEITEM)TVI_SORT, idxBookClosed, idxBookOpened);
InsTreeItem(hBSPItem, rgSPLBookInfo[1].szBookName, 
  (HTREEITEM)TVI_SORT, idxBookClosed, idxBookOpened);

InsTreeItem(hStepItem, rgStepBookInfo[0].szBookName, 
  (HTREEITEM)TVI_SORT, idxBookClosed, idxBookOpened);
InsTreeItem(hStepItem, rgStepBookInfo[1].szBookName, 
  (HTREEITEM)TVI_SORT, idxBookClosed, idxBookOpened);

Так как в параметре hAfter указана константа TVI_SORT, все добавленные элементы будут отображаться в алфавитном порядке.

[Назад] [Содеожание] [Дальше]