Список изображений, ассоциируемый с деревом

Дерево выглядит значительно лучше, если с каждой его ветвью связать растровое изображение (bitmap image). Обычно с деревом ассоциируется список изображений, управляемый объектом класса cimageList. В общем случае с каждым узлом дерева можно связать два изображения. Одно — для узла в нормальном состоянии, другое — в выбранном. Мы уже ввели в состав класса переменную m_plmgList типа cimageList*, которая должна указывать на сформированный список. Немного позже мы попросим систему дать нам Windows-описатель (HIMAGELIST) поддерживаемого ею списка изображений для дисков, папок и файлов. Однако программист должен уметь самостоятельно формировать список произвольных растровых изображений и связывать его с объектом класса CTreeCtrl. Покажем, как это делается. Создайте несколько bitmap-изображений и присвойте им идентификаторы IDB_IDB_2 и т. д. Последнему изображению присвойте имя IDB_N. Для этого:

  1. Установите фокус на узел Тгее.гс в окне Resource View и вызовите контекстное меню.
  2. Выберите команду Add Resource, в окне появившегося диалога выберите элемент Bitmap и нажмите кнопку New.
  3. Перейдите в окно Properties. Для удобства вытащите его из блока окон (команда Floating) и отбуксируйте в сторону. В окне задайте идентификатор ID = IDB_1.
  4. Установите фокус на пустом поле будущего изображения. При этом содержимое окна Properties изменится, позволив вам задать размеры (Height = 16, Width = 16).
  5. Средствами редактора создайте изображение. Для создания второго изображения можно воспользоваться копией первого. В окне Resource View установите фокус на узел дерева ресурсов, соответствующий первому изображению, и вызовите контекстное меню.
  6. В этом меню выберите команду Insert Copy, затем в появившемся окне диалога измените язык на любой, отличный от текущего (он выведен в окне Language).
  7. Выполните двойной щелчок на новом узле дерева ресурсов в окне Resource View, измените изображение, вновь переведите фокус на узел дерева и перейдите в окно Properties.
  8. Измените IDB_1 на IDB_2 и при желании возвратите язык, заменив на тот, который принят по умолчанию.

Повторив эту процедуру столько раз, сколько необходимо иметь различающихся изображений, закончите тем, что последнему из них присвойте ID = IDB_N. Имена идентификаторов произвольны. Важно только то, что их числовые эквиваленты должны следовать подряд. Если вы не отрывались на создание других ресурсов, то Studio.Net сделала это автоматически. Будем считать, создано 3 изображения, и индекс последнего из них равен IDB_3. Для того что бы связать список с деревом вместо строки m_Tree. Insert I tern ("Item", 0,0); В функцию OnlnitialUpdate вставьте такой фрагмент:

//====== Традиционный для MS двухступенчатый способ

//====== создания нового объекта - списка изображений

m_pImgList = new CimageList;

m_pImgList->Create(16, 16, ILC_MASK, 0, 32);

for (UINT nID = IDB_1; nID <= IDB_3; nID++)

{

//====== Временный объект

CBitmap bitmap;

//====== Загрузка из ресурсов

bitmap.LoadBitmap(nID);

//====== Добавление в конец списка изображений

m_pImgList->Add(Sbitmap, (COLORREF)OxFFFFFF);

//====== Освобождаем память

bitmap.DeleteObject();

}

//=== Связывание списка изображений с объектом

CTreeCtrl m_Tree.SetlmageList(m_pImgList, TVSIL_NORMAL);

Параметры функции Create задают размеры изображений, их тип, начальный размер списка и квант его приращения при вставке новых изображений. Цикл загрузки изображений и вставки их в список будет корректно работать, только если их индексы следуют подряд. Метод SetlmageList связывает список с деревом, то есть элементом управления m_Tree типа CTreeCtrl. После этого можно начать формировать дерево.

Вставку новых ветвей осуществляют несколькими способами. Рассмотрим один из них, использующий специальную структуру типа TVINSERTSTRUCT. Просмотрите справку по этому типу, чтобы знать состав полей структуры. Обычно необходима одна глобальная структура такого типа. Это удобно, так как ею могут пользоваться несколько разных функций. В начало файла LeftView.cpp (после директив препроцессора) вставьте определение:

TVINSERTSTRUCT gtv; // Глобальная структура

Вернемся К функции OnlnitialUpdate. После строки m_Tree.SetlmageList... вставьте фрагмент, который задает форму дерева из трех узлов (или ветвей):

//====== Вставляем узел верхнего уровня иерархии

gtv.hParent = TVI_ROOT;

//====== Вставляем в конец списка

gtv.hlnsertAfter = TVI_LAST;

//====== Формат узла — два изображения и текст

gtv.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIFJTEXT;

//=== Индекс изображения для узла в обычном состоянии

gtv.item.iImage = 0;

//=== Индекс изображения для узла в выбранном состоянии

gtv.item.iSelectedlmage = 1;

//====== Текст, именующий узел

gtv.item.pszText = "First";

11====== Описатели трех ветвей

HTREEITEM hi, h2, h3;

//====== Вставка первого узла

hi = m_Tree.Insertltem(Sgtv);

//====== Первый узел будет родителем второго

gtv.hParent = h1;

//====== Атрибуты второго узла

gtv.item.iImage = 1;

gtv.item.pszText = "Second";

//====== Вставка второго узла

h2 = m_Tree.Insertltem(Sgtv);

//====== Второй, узел будет родителем третьего

gtv.hParent = h2;

gtv.item.ilmage = 2;

gtv.item.pszText = "Third";

//====== Вставка третьего узла

h3 = m_Tree.Insertltem(Sgtv);

Запустите приложение, и если вы не забыли создать bitmap-изображения, то они должны появиться слева от текстового ярлыка узла (рис. 5.1). Проанализируйте вложенность узлов дерева. Теперь замените в строке gtv.hParent = b2; b2 на b1и проверьте результат. Затем рекомендуем заменить b1 на константу TVI_ROOT и вновь посмотреть, что получится. Обратите внимание на то, что изображения изменяются при выборе узлов, то есть при переводе курсора мыши с одного узла на другой.

Рис. 5.1. Вид главного окна приложения Tree