Сообщений 21    Оценка 106        Оценить  
Система Orphus

Элемент управления CFListCtrl 2.0

Дерево - список

Автор: Денис Солоненков
Опубликовано: 27.08.2002
Исправлено: 13.03.2005
Версия текста: 1.0.1


Intro
Создание элемента управления
Добавление столбцов
Добавление строк
Операции с элементами строк
Редактирование
Изменение цвета
Стили
Сообщения


Демонстрационная программа - 27 KB
Исходные тексты - 44 KB

Intro

Класс CFListCtrl - это элемент управления типа дерево-список для MFC. Это уже вторая версия элемента управления, которая обладает следующими особенностями:

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

Создание элемента управления

Сначала необходимо подключить к проекту файлы FListCtrl.h и FListCtrl.cpp и добавить в файл StdAfx.h следующую строку:

#include "FListCtrl.h"

Элемент управления может быть создан двумя способами:

  1. С использованием редактора формы диалога
  2. Динамическое создание:

Добавление столбцов

Добавить новый столбец в список можно используя функцию InsertFColumn. Прототип этой функции представлен ниже:

 
int InsertFColumn(int iIndex, CString strText, int nWidth, int nFormat = FL_LEFT,
                                     int iDefaultControlProfile = FL_UNDEFINED);

Эта функция принимает в качестве параметров индекс добавляемого столбца, его название и ширину. Также можно указать выравнивание текста (одна из констант FL_LEFT, FL_CENTER, FL_RIGHT), которое действует не только для заголовка, но и для текста всего столбца. Последний параметр - это индекс профиля элементов управления, используемых для редактирования элементов списка. Разговор о профилях пойдет позже, а сейчас пример:

m_treeList.InsertFColumn(0, _T("Column 1"), 100);
m_treeList.InsertFColumn(1, _T("Column 2"), 150);
m_treeList.InsertFColumn(2, _T("Column 3"), 150, FL_CENTER);

m_treeList.SetTree(0);  // устанавливает номер столбца, в котором будет
                        // отображаться дерево

Последний вызов в этом примере устанавливает номер столбца, в котором появится дерево. Дерево может и отсутствовать, или его можно убрать в процессе выполнения программы, вызвав SetTree(-1).

Добавление строк

Строки добавляет функция с именем InsertFRow.

HFROW InsertFRow(HFROW hParent, HFROW hPosition, CString strText, 
                 int iImageIndex = -1, int iControlProfile = -1);

Первый параметр хэндл родительской строки или FL_ROOT, если строка не является дочерней. Параметр hPosition задает хэндл строки, после которой будет добавлена новая строка, это также может быть одно из значение FL_FIRST или FL_LAST, заставляющих функцию InsertFRow вставить строку в начало или конец списка дочерних строк. Следующие два параметра задают текст и индекс картинки в имэдж-листе. Текст и картинка появятся в колонке с деревом; если дерево не установлено, они появятся в нулевом столбце.

Удалять строки можно при помощи методов RemoveFRow и RemoveAllFRows.

Перечислять с помощью метода GetNextFRow. Последний в качестве параметра принимает хэндл текущей строки и значение, определяющее хэндл какой строки нужно вернуть следующим. Для этого параметра доступны следующие значения:

Параметр nfrCode функции GetNextFRow Возвращаемое значение
FL_NEXT Хэндл следующей строки, либо NULL, если строка последняя. Перебор ведется среди строк одного родителя.
FL_PREV Хэндл предыдущей строки, либо NULL, если строка первая. Перебор ведется среди строк одного родителя.
FL_FIRST_CHILD Хэндл первой дочерней строки для данной.
FL_LAST_CHILD Хэндл последней дочерней строки.
FL_PARENT Хэндл родительской строки или FL_ROOT, если строка не имеет родителя.

Число дочерних строк можно узнать вызовом функции GetFRowCount, в качестве параметра которой передается хэндл родительской строки, число дочерних элементов которой нужно посчитать. Если в качестве значения этого параметра передать FL_ROOT, то функция вернет число строк самого верхнего уровня. В принципе, теперь можно обращаться к строкам и по индексу. Для этого служит функция FindIndex, первый параметр которой - это хэндл родительской строки или FL_ROOT, а второй - это индекс. Функция возвращает хэндл строки, который затем можно использовать при вызове других функций.

Раскрывать и закрывать узлы дерева можно с помощью функции Collapse, последний параметры которой задает тип действия. В случае, если передать значение TRUE, то узел будет закрыт, иначе - открыт. Если данный узел не виден, т.е. его родитель сам закрыт, то его состояние будет сохранено, и он откроется, как только будет раскрыт родительский узел. Определить видима ли строка или нет позволяет метод IsFRowVisible, а определить закрыт узел или нет - IsCollapsed.

Операции с элементами строк

Сюда относятся функции для изменения текста, картинок, профилей in-place элементов управления и другие. Особо интересного тут сказать нечего, но если что-то не понятно, в исходных текстах класса CFListCtrl есть комментарии. Приведу лишь короткий пример:

m_treeList.SetFItemText(hFRow, iFColumn, _T("Sample Text"));

Редактирование

Класс CFListCtrl поддерживает четыре типа in-place элементов управления для редактирования. Это FL_BUTTON, FL_CHECKBOX, FL_EDIT и FL_COMBOBOX. В отличие от предыдущей версии CFListCtrl, эти элементы управления не назначаются непосредственно каждой ячейке таблицы. Вместо этого, сначала нужно создать профиль элементов редактирования и потом использовать его индекс. Выглядит это следующим образом:

m_treeList.SetReadOnly(FALSE);

int indx = m_treeList.AddControl(FL_EDIT|FL_BUTTON);

m_treeList.SetFItemControl(hFRow, iFColumn, indx);

В этом примере был сначала создан профиль, представляющий два органа управления: поле ввода и кнопку. Далее этот профиль был присвоен конкретному элементу, после чего текст элемента можно редактировать или нажать на кнопку. Первый вызов функции AddControl возвращает ноль, а при каждом следующем вызове возвращаемое значение увеличивается на единицу, поэтому в приведенном выше примере можно было и не сохранять его значение в отдельной переменной, а в вызове SetFItemControl непосредственно использовать значение 0.

Как уже упоминалось выше, существует четыре элемента управления, при этом их можно комбинировать между собой, например:

// флажок, поле ввода и кнопка
m_treeList.AddControl(FL_CHECKBOX|FL_EDIT|FL_BUTTON);

// выпадающий список со стилем dropdown
m_treeList.AddControl(FL_COMBOBOX|FL_EDITBOX); 

// ну это вообще круто!
m_treeList.AddControl(FL_CHECKBOX|FL_AUTOCHECK|FL_COMBOBOX|FL_EDITBOX);

Добавленный профиль - это не только тип элементов управления, но также и специфичные данные для них. Например, профиль, который включает выпадающий список, хранит массив строк и ассоциированные им пользовательские данные. Выглядит это так:

 
int indx = m_treeList.AddControl(FL_COMBOBOX);
m_treeList.AddControlComboItem(indx, _T("Item 1"));
m_treeList.AddControlComboItem(indx, _T("Item 2"));
m_treeList.AddControlComboItem(indx, _T("Item 3"));

m_treeList.SetFItemControl(hFRow, iFColumn, indx);

Теперь если выделить данную ячейку и открыть выпадающий список, то там появятся три добавленных строки. Изменять элементы выпадающего списка можно в любой момент, более того, каждый раз перед тем, как пользователь его открывает, CFListCtrl посылает уведомляющее сообщение, позволяющее соответствующим образом заполнить выпадающий список. Однако это не обязательно делать каждый раз - можно вообще не обрабатывать это сообщение, а сформировать список только один раз, как в предыдущем примере.

Каждый профиль можно присвоить нескольким ячейкам таблицы, либо назначить по умолчания для отдельного столбца. Делается при вызове функции InsertFColumn, например:

int indx = m_treeList.AddControl(FL_COMBOBOX);
m_treeList.InsertFColumn(0, _T("Column A"), 100, FL_LEFT, indx);

При этом все вновь добавляемые строки в этом столбце будут использовать combobox для редактирования элементов. Если в программе используется несколько органов управления CFListCtrl, то профили можно создать только в одном, а остальные органы управления подключить к первому, например:

m_treeListA.AddControl(FL_COMBOBOX);
m_treeListA.AddControl(FL_COMBOBOX|FL_EDIT);

m_treeListB.AttachControls(&m_treeListA);

Теперь оба списка разделяют одни и те же профили, соответственно и органы управления combobox у них будут совершенно одинаковые, т.е. содержащими одни и те же элементы. Ну и последнее о профилях: используя функцию SetFRowControls, можно установить их для всей строки, например:

m_treeList.AddControl(FL_COMBOBOX);      // первый выпадающий список
m_treeList.AddControl(FL_COMBOBOX);      // второй выпадающий список, который
                                         // можно заполнить другими значениями
m_treeList.AddControl(FL_EDIT);

m_treeList.InsertFColumn(0, _T("Column A"), 100, FL_LEFT, 0);
m_treeList.InsertFColumn(1, _T("Column B"), 100, FL_LEFT, 2);
m_treeList.InsertFColumn(2, _T("Column C"), 100, FL_LEFT, 2);
 
HFROW hRoot = m_treeList.InsertFRow(FL_ROOT, FL_LAST, _T("Row 1"));
HFROW hFRow = m_treeList.InsertFRow(hRoot, FL_LAST, _T("Sub Row"));
m_treeList.SetFRowControls(hFRow, 2, -1, 1);

Небольшие пояснения, что здесь происходит. Сначала создаются три профиля, затем добавляются три столбца (совпадение количества профилей и количества столбцов чисто случайное) и каждому из них назначается профиль по умолчанию. При первом вызове InsertFRow добавляется строка, которая редактируется в первом столбце выпадающим списком, во втором и третьем - окном ввода. Следующий вызов добавляет дочернюю строку. Наконец, последний вызов устанавливает, что дочерняя строка редактируется в первом столбце выпадающим списком, среднее поле строки никак не редактируется, а последнее можно изменить с помощью поля ввода.

Изменение цвета

Как видно на снимке экрана, CFListCtrl позволяет настроить цвет отдельной строки или столбца. Делается это с помощью функции SetFColor:

void SetColor(int nArea, HFROW hFRow, int iFColumn,
              COLORREF crText = FL_DONTSET, COLORREF crBackground = FL_DONTSET);

Первый параметр этой функции - это область, цвет которой нужно изменить. Доступны следующие значения:

FL_FULL Основной цвет
FL_FCOLUMN Цвет столбца, номер которого задается параметром iFColumn
FL_FROW Цвет строки, которая задается описателем hFRow
FL_SELECTED_FROW Цвет выделенной строки
FL_SELECTED_FITEM Цвет выделенного элемента

В качестве цвета можно использовать предопределенные значения FL_DONTSET - цвет не изменяется и FL_NOCOLOR - цвет не установлен. Если цвет не установлен для определенной строки (состояние по умолчанию), то используется цвет столбца, если и он не установлен, то используется основной цвет.

Стили

Для установки и получения значения стилей предназначены функции SetFStyle и GetFStyle. Элемент управления CFListCtrl поддерживает два стиля. Первый - это уже упоминавшийся FL_READONLY, для установки которого используется функция SetReadOnly. Другой стиль называется FL_LINEAR_TREE - узлы дерева располагаются в линию, т.е. дочерние строки не смещаются. Кроме того, стоит упомянуть стандартные расширенные стили обычного списка: LVS_EX_FULLROWSELECT и LVS_EX_GRIDLINES:

// линейное дерево
m_treeList.SetFStyle(0, FL_LINEAR_TREE);

// горизонтальные и вертикальные линии
m_treeList.SetExtendedStyle(LVS_EX_GRIDLINES);  

// выделение всей строки
m_treeList.SetExtendedStyle(LVS_EX_FULLROWSELECT);

Сообщения

Класс CFListCtrl в процессе работы посылает родительскому окну сообщения WM_NOTIFY. Для обработки таких сообщений нужно добавить обработчик следующего вида в заголовочный файл:

afx_msg void OnEventFunc (NMHDR * pNotifyStruct, LRESULT * result);

в файле реализации:

 
void CFListDemoDlg::OnEventFunc(NMHDR * pNotifyStruct, LRESULT * result)
{
  FL_NOTIFY * notify = (FL_NOTIFY *)pNotifyStruct;
  *result = FL_OK;
}

и, наконец, в карте сообщений в файле реализации:

ON_NOTIFY(FLNM_EVENT, IDC_TREELIST, OnEventFunc)

Доступные сообщения приведены в таблице ниже

FLNM_COLLAPSE Пользователь закрыл или открыл узел дерева
FLNM_CHECK Пользователь установил/снял флажок
FLNM_DELETE Строка удаляется вызовом DeleteFRow или DeleteAllFRows
FLNM_SELECT Изменилась выделенная строка
FLNM_EDIT_BEGIN Пользователь начинает редактировать в окне ввода
FLNM_EDIT_END Пользователь завершил редактирование в окне ввода или выпадающем списке
FLNM_BUTTON_CLICK Пользователь нажал на кнопку
FLNM_COMBOBOX_EXPAND Пользователь пытается открыть выпадающий список

В обработчике FLNM_EDIT_END можно разрешить внести изменения, присвоив *result значение FL_OK, или оставить текущее значение без изменений, присвоив *result значение FL_CANCEL. Кроме того, совместно с этими константами можно применять значение FL_CONTINUE, чтобы in-place орган управления не исчез, а остался на месте.

Посылаемая обработчику структура данных FL_NOTIFY содержит хэндл строки, для которой произошло событие, номер столбца (если установлено свойство readonly, он всегда равен -1), введенный пользователем текст или существующий текст. Подробнее о FL_NOTIFY можно узнать, открыв заголовочный файл FListCtrl.h.


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
    Сообщений 21    Оценка 106        Оценить