Общие замечания

Элемент управления List View представляет собой окно класса «SysListView32», предназначенное для отображения набора элементов; каждый такой элемент состоит из иконки и текстовой метки. List View предоставляет несколько способов отображения и упорядочения своих элементов. Например, дополнительная информация, соответствующая каждому элементу, может быть отображена в колонках, расположенных справа от иконки и текстовой метки. Заметим, что именно этот элемент управления используется в Windows Explorer для отображения списка файлов. В MFC функциональность элемента управления List View инкапсулируется классом CListCtrl.

Класс CListCtrl

Заголовочный файл #include <afxcmn.h>
Непосредственный предок класс CWnd
Объектная модель DYNAMIC

Ниже перечислены основные методы класса CListCtrl.

Конструирование (construction)

CListCtrl(void);
BOOL Create(
   DWORD fdwStyle,
   const RECT& rect,
   CWnd* pParentWnd,
   UINT uID
);

В качестве одного из стилей, задаваемых параметром fdwStyle необходимо обязательно указывать WS_CHILD. Кроме этого, обычно используется стиль WS_VISIBLE, а также один или несколько стилей, специфичных для данного элемента управления:

LVS_ICON
Элементы списка представляются изображениями 32 x 32 пикселя, текст элемента выводится под изображением.
LVS_SMALLICON
Элементы списка представляются изображениями 16 x 16 пикселей, текст элемента выводится справа от изображения.
LVS_LIST
Аналогично LVS_SMALLICON, но элементы списка всегда отображаются упорядоченными.
LVS_REPORT
Каждый элемент списка выводится отдельной строкой и может содержать подэлементы, отображаемые в отдельных колонках, каждая из которых, как правило, имеет заголовок. Пользователь может изменять с помощью мышки ширину колонок и перемещать их друг относительно друга.

Данные четыре стиля являются взаимоисключающими и определяют внешний вид списка (в данном тексте также употребляется термин режим отображения). В процессе работы приложение может переназначать эти стили, изменяя таким образом визуальное представление элементов списка. Это можно сделать с помощью унаследованного от класса CWnd метода

BOOL ModifyStyle(
   DWORD fdwRemove,
   DWORD fdwAdd,
   UINT fuFlags = 0
);

Через параметр fdwRemove передается комбинация стилей, которые необходимо «удалить», а через fdwAdd — комбинация стилей, подлежащих «добавлению». Параметр fuFlags позволяет указать комбинацию флагов, которые будут переданы в метод SetWindowPos после изменения стиля окна; если этот параметр задан равным нулю, метод SetWindowPos вызываться не будет. Например, переключить список в режим отображения, соответствующий стилю LVS_ICON, можно следующим образом:

CListCtrl listFiles;
...
listFiles.ModifyStyle(LVS_TYPEMASK, LVS_ICON);

Иногда после изменения режима отображения (например, при замене стиля LVS_ICON на LVS_SMALLICON) список «забывает» откорректировать диапазон полос прокрутки. Для того, чтобы заставить его сделать это, можно использовать следующий код:

CListCtrl listFiles;
RECT rcClient;
...
listFiles.GetClientRect(&rcClient);
listFiles.MoveWindow(0, 0, 0, 0);
listFiles.MoveWindow(&rcClient);

Если список имеет рамку (то есть размеры его клиентской области не совпадают с размерами окна), необходимо использовать методы GetWindowRect и ScreenToClient для корректного восстановления размеров окна:

CListCtrl listFiles;
RECT rcList;
...
listFiles.GetWindowRect(&rcList);
CWnd* pParentWnd = listFiles.GetParent();
ASSERT_VALID(pParentWnd);
pParentWnd->ScreenToClient(&rcList);
listFiles.MoveWindow(0, 0, 0, 0);
listFiles.MoveWindow(&rcList);

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

Помимо четырех перечисленных, для элементов управления List View поддерживаются следующие стили:

LVS_AUTOARRANGE
Автоматически упорядочивать элементы списка в режимах отображения ICON и SMALLICON.
LVS_ALIGNTOP
Выравнивать элементы списка по его верхней границе (слева направо, сверху вниз).
LVS_ALIGNLEFT
Выравнивать элементы списка по его левой границе (сверху вниз, слева направо).
LVS_SORTASCENDING
Сортировать элементы списка по возрастанию.
LVS_SORTDESCENDING
Сортировать элементы списка по убыванию.
LVS_NOCOLUMNHEADER
Не показывать в режиме отображения REPORT заголовки столбцов.
LVS_NOSORTHEADER
При клике по заголовку столбца список не будет посылать родительскому окну извещение LVN_COLUMNCLICK, обработчик которого, как правило, выполняет сортировку элементов списка по данному столбцу. Сам заголовок будет при этом иметь «плоский» вид (как в Registry Editor, например).
LVS_EDITLABELS
Разрешить редактирование текста элементов «по месту» (in-place). Родительское окно будет получать извещения LVN_BEGINLABELEDIT и LVN_ENDLABELEDIT, которые оно должно соответствующим образом обработать.
LVS_NOLABELWRAP
Не разбивать текст элемента на несколько строк в режиме отображения ICON.
LVS_NOSCROLL
Не обеспечивать возможность прокрутки содержимого окна списка.
LVS_SHAREIMAGELISTS
Не уничтожать списки изображений при разрушении окна элемента управления.
LVS_SINGLESEL
Не позволять пользователю выбирать несколько элементов одновременно.
LVS_SHOWSELALWAYS
Всегда отмечать цветом выбранные элементы.

Остальные параметры метода Create имеют достаточно традиционный смысл: через rect необходимо передать размеры создаваемого окна; параметр pParentWnd должен определять родительское окно и не может быть равен NULL. Наконец, через параметр uID передается идентификатор создаваемого элемента управления. При успешном создании окна метод Create возвращает ненулевое значение.

Расширенные стили (extended styles)

Элемент управления List View поддерживает следующие расширенные стили:

LVS_EX_CHECKBOXES
Слева от каждого элемента списка будет отображаться checkbox.
LVS_EX_FULLROWSELECT
В режиме отображения REPORT выделение будет охватывать всю строку целиком вместе с подэлементами.
LVS_EX_HEADERDRAGDROP
В режиме отображения REPORT будет возможно перетаскивание колонок списка за их заголовки.
LVS_EX_ONECLICKACTIVATE
Для активизации элемента списка будет требоваться одиночный клик левой клавишей мышки.
LVS_EX_TWOCLICKACTIVATE
Для активизации элемента списка будет требоваться двойной клик левой клавишей мышки.
LVS_EX_TRACKSELECT
Список будет отслеживать перемещение курсора мышки, автоматически выделяя элемент, оказавшийся под курсором.

Заметим, что список расширенных стилей пополняется практически с каждой версией IE, поэтому для получения их полного перечня целесообразно обратиться к разделу MSDN «Extended list view styles». Для назначения списку требуемой комбинации расширенных стилей можно воспользоваться методом

DWORD SetExtendedStyle(
   DWORD fdwExStyle
);

Параметр fdwExStyle может быть любой осмысленной комбинацией флагов LVS_EX_xxx. Метод возвращает предыдущую комбинацию расширенных стилей. Для получения текущих расширенных стилей списка используется метод

DWORD GetExtendedStyle(void) const;

Возвращаемое значение, как и в предыдущем случае, содержит комбинацию флагов LVS_EX_xxx.

Атрибуты (attributes)

CImageList* SetImageList(
   CImageList* pImgList,
   int nType
);

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

LVSIL_NORMAL
Список содержит изображения 32 x 32, используемые в режиме ICON.
LVSIL_SMALL
Список содержит изображения 16 x 16, используемые во всех остальных режимах.

Заметим, что элемент управления не проверяет размеров изображений в назначаемом списке, поэтому данный параметр имеет чисто логическое значение (вполне возможно, например, назначение списка типа LVSIL_SMALL, содержащего изображения 32 x 32, которые затем будут использоваться в режимах SMALLICON, LIST и REPORT — зрелище ужасающее). Метод возвращает указатель на объект, соответствующий предыдущему список изображений того же типа, что и назначаемый; если ранее список изображений не назначался, этот указатель имеет значение NULL. Для корректной работы элемента управления во всех четырех возможных режимах отображения ему должны быть назначены списки изображений обоих типов.

CImageList* GetImageList(
   int nType
) const;

Возвращает указатель на текущий список изображений типа nType.

BOOL SetTextColor(
   COLORREF crColor
);

Назначает цвет, которым выводится текст элементов и подэлементов списка, равным crColor.

COLORREF GetTextColor(void) const;

Возвращает цвет, которым выводится текст элементов и подэлементов списка.

BOOL SetBkColor(
   COLORREF crColor
);

Назначает цвет фона окна списка равным crColor.

COLORREF GetBkColor(void) const;

Возвращает цвет фона окна списка.

BOOL SetTextBkColor(
   COLORREF crColor
);

Назначает цвет фона под текстом элементов и подэлементов списка равным crColor.

COLORREF GetTextBkColor(void) const;

Возвращает цвет фона под текстом элементов и подэлементов списка.

int GetItemCount(void);

Возвращает количество элементов в списке.

BOOL SetItem(
   const LVITEM* pLVI
);

Изменяет заданный элемент списка. Через параметр pLVI необходимо передать указатель на структуру, поля которой определяют изменяемый элемент и его новые атрибуты — иконку, текст, состояние, etc. Ниже приведено описание полей структуры LVITEM:

UINT mask
Комбинация битовых флагов, определяющих, какие поля структуры необходимо использовать при изменении атрибутов данного элемента.
int iItem
Индекс элемента списка.
int iSubItem
Индекс подэлемента списка (используется только в режиме отображения REPORT).
UINT state
Комбинация битовых флагов, определяющих визуальное состояние элемента.
UINT stateMask
Маска, определяющая, какие из флагов поля state необходимо использовать.
LPTSTR pszText
Текст элемента (или подэлемента) списка.
int cchTextMax
Размер буфера (в символах), адресуемого полем pszText (используется только при получении информации об элементе, при вызове метода SetItem значение этого поля игнорируется).
int iImage
Индекс иконки, соответствующей данному элементу, в списке изображений.
LPARAM lParam
Произвольное 4-байтовое значение, связанное с данным элементом.

Для формирования значения поля mask могут использоваться следующие флаги:

LVIF_STATE
Использовать поля state и stateMask.
LVIF_TEXT
Использовать поля pszText и cchTextMax.
LVIF_IMAGE
Использовать поле iImage.
LVIF_PARAM
Использовать поле lParam.

Заметим, что поля mask, iItem и iSubItem должны инициализироваться всегда. Для формирования значений полей state и stateMask используются следующие флаги:

LVIS_FOCUSED
Элемент списка имеет фокус, его текст «окружается» стандартной фокусной рамкой (focus rectangle). Заметим, что даже в случае, когда в списке разрешен выбор нескольких элементов, фокус может иметь только один из них.
LVIS_SELECTED
Элемент выбран. Его внешний вид в этом случае определяется системными цветами и наличием/отсутствием фокуса.
LVIS_CUT
Элемент помечен для операции cut-and-paste.
LVIS_DROPHILITED
Элемент выделен как целевой для операции drag-and-drop.
BOOL GetItem(
   LVITEM* pLVI
) const;

Записывает в структуру по адресу pLVI атрибуты заданного элемента. Перед вызовом этого метода необходимо инициализировать поля mask, iItem и iSubItem структуры, адресуемой параметром pLVI.

int GetNextItem(
   int iItem,
   int fnFlags
);

Возвращает индекс элемента, логически следующего за iItem. Параметр fnFlags определяет направление поиска и состояние искомого элемента; для формирования значения этого параметра могут использоваться следующие флаги:

LVNI_ABOVE
Искать выше элемента iItem.
LVNI_BELOW
Искать ниже элемента iItem.
LVNI_TOLEFT
Искать слева от элемента iItem.
LVNI_TORIGHT
Искать справа от элемента iItem.

Если ни один из этих флагов не указан, то по умолчанию устанавливается LVNI_ALL, являющийся комбинацией всех четырех и предписывающий вести поиск по всем направлениям. Состояние искомого элемента задается следующими флагами:

LVNI_FOCUSED
Искомый элемент имеет фокус.
LVNI_SELECTED
Искомый элемент выбран.
LVNI_DROPHILITED
Искомый элемент выделен как целевой для операции drag-and-drop.

Если элемент в требуемом состоянии не найден в указанном направлении, метод GetNextItem возвращает значение -1.

BOOL SetItemText(
   int iItem,
   int iSubItem,
   LPCTSTR pszSrc
);

Назначает текст элемента с индексом iItem (или подэлемента с индексом iSubItem для режима отображения REPORT) в соответствии со строкой pszSrc. Заметим, что для назначения текста элемента параметр iSubItem необходимо задать равным 0; индексы подэлементов начинаются с 1.

int GetItemText(
   int iItem,
   int iSubItem,
   LPTSTR pszDest,
   int cchMaxLen
) const;
CString GetItemText(
   int iItem,
   int iSubItem
) const;

Позволяет получить копию текста элемента с индексом iItem (или подэлемента с индексом iSubItem для режима отображения REPORT). Первый вариант этого метода копирует текст в буфер по адресу pszDest, имеющий размер cchMaxLen символов и возвращает длину скопированной строки. Второй вариант метода возвращает объект класса CString, содержащий текст элемента или подэлемента.

BOOL SetItemData(
   int iItem,
   DWORD dwData
);

Связывает с элементом, имеющим индекс iItem, произвольное 4-байтовое значение dwData.

DWORD GetItemData(
   int iItem
) const;

Возвращает 4-байтовое значение, связанное с элементом, имеющим индекс iItem.

BOOL GetSubItemRect(
   int iItem,
   int iSubItem,
   int fnArea,
   CRect& rectDest
);

Записывает в rectDest границы области подэлемента iSubItem элемента iItem. Параметр fnArea определяет область подэлемента, границы которой необходимо вернуть, и может иметь одно из следующих значений:

LVIR_ICON
Область, занимаемая картинкой.
LVIR_LABEL
Область, занимаемая текстом.
LVIR_BOUNDS
Область, занимаемая всем подэлементом целиком, включая картинку и текст.
DWORD SetHoverTime(
   DWORD dwTime = -1
);

Назначает время в миллисекундах, в течение которого нужно держать курсор мышки над элементом списка, чтобы этот элемент был автоматически выделен (при использовании расширенного стиля LVS_EX_TRACKSELECT). Значение -1 соответствует стандартному системному времени. Метод возвращает предыдущее значение времени.

DWORD GetHoverTime(void) const;

Возвращает текущее значение времени в миллисекундах, в течение которого нужно держать курсор мышки над элементом для его автоматического выделения.

Операции (operations)

int InsertItem(
   const LVITEM* pLVI
);
int InsertItem(
   int iItem,
   LPCTSTR pszText
);
int InsertItem(
   int iItem,
   LPCTSTR pszText,
   int iImage,
);

Вставляет новый элемент в список. Первый вариант этого метода позволяет задать все атрибуты вставляемого элемента, второй — только текст, а третий — текст и индекс иконки, соответствующей вставляемому элементу. В любом случае, метод возвращает индекс позиции, в которую был вставлен новый элемент; в случае ошибки возвращается значение -1.

BOOL DeleteItem(
   int iItem
);

Удаляет из списка элемент с индексом iItem.

BOOL DeleteAllItems(void);

Удаляет из списка все элементы.

BOOL SortItems(
   PFNLVCOMPARE pfnCompare,
   DWORD dwData
);

Метод выполняет сортировку элементов списка, сравнивая их с помощью функции, адресуемой параметром pfnCompare. Эта функция должна иметь следующий прототип:

int CALLBACK имя_функции(
   LPARAM lParam1,
   LPARAM lParam2,
   LPARAM nParamSort
);

Через параметры lParam1 и lParam2 в данную функцию передаются 4-байтовые значения, связанные со сравниваемыми элементами списка, а через параметр nParamSort — значение dwData, заданное при вызове метода SortItems. Функция сравнения должна возвращать отрицательное значение, если первый из сравниваемых элементов должен располагаться перед вторым; положительное значение — в обратном случае; либо нулевое значение, если порядок следования сравниваемых элементов безразличен. Заметим, что сам алгоритм сортировки определяется реализацией элемента управления и мы не имеем к нему доступа.

BOOL EnsureVisible(
   int iItem,
   BOOL fPartialOK
);

Делает элемент с индексом iItem видимым, при необходимости выполняя прокрутку окна списка. Через параметр fPartialOK необходимо передать нулевое значение, если элемент должен стать видимым полностью; либо нулевое значение, если допустимо частичное отображение элемента.

BOOL Scroll(
   CSize sizeAmount
);

Выполняет прокрутку содержимого окна списка на заданное расстояние.

BOOL RedrawItems(
   int iFirstItem,
   int iLastItem
);

Перерисовывает элементы списка, имеющие индексы от iFirstItem до iLastItem.

Режим отображения REPORT

int InsertColumn(
   int nIndex,
   const LVCOLUMN* pLVC
);

Вставляет в позицию nIndex колонку, характеристики которой задаются структурой, адресуемой параметром pLVC. Структура LVCOLUMN имеет следующие поля:

UINT mask
Комбинация битовых флагов, определяющих, какие поля структуры необходимо использовать при вставке колонки.
int fmt
Флаг, определяющий формат колонки.
int cx
Ширина колонки в пикселях.
LPTSTR pszText
Заголовок колонки.
int cchTextMax
Размер буфера (в символах), адресуемого полем pszText (используется только при получении информации о колонке, при вызове метода InsertColumn значение этого поля игнорируется).
int iSubItem
Индекс подэлемента, который будет отображаться в данной колонке.

Для формирования значения поля mask могут использоваться следующие флаги:

LVCF_FMT
Использовать поле fmt.
LVCF_WIDTH
Использовать поле cx.
LVCF_TEXT
Использовать поля pszText и cchTextMax.
LVCF_SUBITEM
Использовать поле iSubItem.

Поле fmt может иметь одно из следующих значений:

LVCFMT_LEFT
Выравнивать текст в колонке по левому краю.
LVCFMT_CENTER
Центрировать текст в колонке.
LVCFMT_RIGHT
Выравнивать текст в колонке по правому краю.

Заметим, что текст в самой первой колонке, содержащей «основной» элемент и имеющей индекс 0, всегда выравнивается по левому краю. Существует также «альтернативный» вариант метода InsertColumn, позволяющий ограничиться указанием заголовка вставляемой колонки:

int InsertColumn(
   int nIndex,
   LPCTSTR pszText,
   int fmt = LVCFMT_LEFT,
   int cx = -1,
   int iSubItem = -1
);

При успешном выполнении метод InsertColumn возвращает позицию вставленной колонки, а при ошибках — значение -1.

BOOL DeleteColumn(
   int nIndex
);

Удаляет из списка колонку, находящуюся в позиции nIndex.

BOOL GetColumn(
   int nIndex,
   LVCOLUMN* pLVC
) const;

Записывает в структуру, адресуемую параметром pLVC, характеристики колонки, находящейся в позиции nIndex. Перед вызовом данного метода необходимо присвоить соответствующее значение полю mask, а при получении заголовка колонки — выделить память для буфера и указать его адрес в поле pszText, а длину в поле cchTextMax.

BOOL SetColumn(
   int nIndex,
   const LVCOLUMN* pLVC
);

Назначает характеристики колонки, находящейся в позиции nIndex, в соответствии со значениями полей структуры, адресуемой параметром pLVC и возвращает ненулевое значение при успешном выполнении.

int GetColumnWidth(
   int nIndex
) const;

Возвращает ширину в пикселях колонки, находящейся в позиции с индексом nIndex.

BOOL SetColumnWidth(
   int nIndex,
   int cx
);

Устанавливает ширину колонки, находящейся в позиции с индексом nIndex, равной cx пикселей. Можно указать либо абсолютное значение, либо одну из следующих констант:

LVSCW_AUTOSIZE
Текст любого элемента должен помещаться целиком.
LVSCW_AUTOSIZE_USEHEADER
Текст заголовка должен помещаться целиком. Если это значение используется для последней колонки, то она займет всю оставшуюся область списка.

Еще раз подчеркнем, что в режиме отображения REPORT добавление в список «основного» элемента осуществляется с помощью метода InsertItem, а назначение текста его подэлементов — с помощью метода SetItem с указанием соответствующих индексов в поле iSubItem структуры LVITEM. При этом, перед добавлением в список элементов необходимо вставить в него все необходимые колонки.

обновлено
29.03.2006
 
Проверка PR и ТИЦ