Демонстрационная программа - 27 KB
Исходные тексты - 44 KB
Класс CFListCtrl - это элемент управления типа дерево-список для MFC. Это уже вторая версия элемента управления, которая обладает следующими особенностями:
Хочу обратить внимание на то, что эта версия элемента управления не совместима с предыдущей, поэтому лучше не обновлять его в существующих проектах.
Сначала необходимо подключить к проекту файлы FListCtrl.h и FListCtrl.cpp и добавить в файл StdAfx.h следующую строку:
#include "FListCtrl.h" |
Элемент управления может быть создан двумя способами:
// создаем имэдж-лист с маскированными картинками 16 на 16, всего 10 штук m_imageList.Create(16, 16, ILC_COLOR16|ILC_MASK, 0, 10); // загружаем битмэп в имэдж лист, в качестве цвета маски задаем розовый CBitmap bitmap; bitmap.LoadBitmap(IDB_IMAGELIST); m_imageList.Add(&bitmap, RGB(255, 0, 255)); // подключаем имэдж-лист к списку m_treeList.SetImageList(&m_imageList); |
// создаем имэдж-лист с маскированными картинками 16 на 16, всего 10 штук m_imageList.Create(16, 16, ILC_COLOR16|ILC_MASK, 0, 10); // загружаем битмэп в имэдж лист, в качестве цвета маски задаем розовый CBitmap bitmap; bitmap.LoadBitmap(IDB_IMAGELIST); m_imageList.Add(&bitmap, RGB(255, 0, 255)); // создаем список, идентификатор IDC_TREELIST должен быть предварительно // где-то определен m_treeList.Create(WS_VISIBLE|WS_CHILD|LVS_SHAREIMAGELISTS, CRect(0, 0, 100, 100), this, IDC_TREELIST); // подключаем имэдж-лист к три-листу m_treeList.SetImageList(&m_imageList); |
Добавить новый столбец в список можно используя функцию 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.