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

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

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

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

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

Для использования органа управления List View ваше приложение должно выполнить несколько действий:

  • создать окно на базе предопределенного класса окна WC_LISTVIEW ;
  • создать один, два или три списка изображений, которые будут использованы для идентификации строк или для отображения состояния строк (назначение этих списков мы рассмотрим позже);
  • добавить изображения (пиктограммы) в созданные списки;
  • подключить списки изображений к органу управления List View;
  • вставить столбцы и установить их ширину;
  • вставить элементы списка, указав данные, которые должны быть отображены в столбцах или определив, что эти данные будут предоставлены позже при обработке соответствующего извещения.

Теперь мы подробно расскажем вам о том, как выполнить перечисленные выше действия.

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

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

hwndList = CreateWindowEx(0L, WC_LISTVIEW, "",
  WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT | 
  LVS_EDITLABELS,
  0, 0, rc.right - rc.left, rc.bottom - rc.top,
  hWnd, (HMENU)IDC_LISTVIEW, hInst, NULL);

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

В дополнение к обычным стилям окна, таким как WS_VISIBLE, WS_CHILD и WS_BORDER, необходимо указать специальные стили с префиксом имени LVS_, определяющие внешний вид и поведение органа управления List View. Как минимум, следует указать один из следующих четырех стилей: LVS_REPORT , LVS_ICON, LVS_SMALLICON или LVS_LIST.

Ниже мы привели краткое описание этих, а также остальных стилей окна List View.

Стиль Описание
LVS_REPORT Список отображается в виде детального отчета, состоящего из нескольких столбцов (рис. 3.1)
LVS_ICON Список отображается в виде окна с пиктограммами стандартного размера (рис. 3.2)
LVS_SMALLICON Список отображается в виде окна с пиктограммами уменьшенного размера (рис. 3.3)
LVS_LIST Простой список с пиктограммами уменьшенного размера (рис. 3.4)
LVS_ALIGNLEFT Используется вместе с LVS_ICON и LVS_SMALLICON. Если указан этот стиль, пиктограммы будут выровнены по левой границе
LVS_ALIGNTOP Используется вместе с LVS_ICON и LVS_SMALLICON. Если указан этот стиль, пиктограммы будут выровнены по верхней границе. Стиль LVS_ALIGNTOP используется по умолчанию
LVS_AUTOARRANGE Используется вместе с LVS_ICON и LVS_SMALLICON для выполнения автоматического размещения пиктограмм внутри окна органа управления List View
LVS_NOSCROLL Отключение возможности свертки содержимого окна органа управления List View
LVS_EDITLABELS Этот стиль позволяет пользователю редактировать название элемента списка. Если указан стиль LVS_EDITLABELS, приложение должно обрабатывать извещение LVN_ENDLABELEDIT, которое будет описано позже
LVS_NOCOLUMNHEADER Если указан стиль LVS_NOCOLUMNHEADER, в режиме детального просмотра не отображается заголовок столбцов, с помощью которого выполняется сортировка и изменение размера столбцов
LVS_NOLABELWRAP Подпись под пиктограммами отображается в одной строке
LVS_NOSORTHEADER Если указан этот стиль, с помощью заголовка окна невозможно выполнить сортировку столбцов в режиме детального просмотра
LVS_OWNERDRAWFIXED Стиль позволяет родительскому окну выполнить рисование содержимого списка. Для этого родительское окно должно обрабатывать сообщение WM_DRAWITEM
LVS_SHAREIMAGELIST Этот стиль предназначен для организации совместного использования списков изображений несколькими органами управления List View
LVS_SHOWSELALWAYS Выбранные элементы списка отображаются с выделением даже в том случае, когда орган управления List View не активен
LVS_SINGLESEL Пользователь может выделить в списке только один элемент (по умолчанию можно выделить сразу несколько элементов)
LVS_SORTASCENDING Выполнение сортировки текстовых строк элементов в прямом порядке
LVS_SORTDESCENDING То же, но в обратном порядке

Как мы уже говорили, стили LVS_REPORT, LVS_ICON, LVS_SMALLICON и LVS_LIST определяют режим работы органа управления List View. При создании этого органа управления вы должны указать только один из перечисленных стилей. Однако в дальнейшем если появится необходимость изменить режим работы, это можно будет легко сделать при помощи функций GetWindowLong и SetWindowLong .

Когда список отображается в виде окна со стандартными или уменьшенными пиктограммами, у вас есть возможность выбрать один из нескольких способов выравнивания пиктограмм во внутренней области этого окна. Для этого вы должны указать один из следующих стилей: LVS_ALIGNLEFT, LVS_ALIGNTOP или LVS_AUTOARRANGE.

По умолчанию (если не указан стиль LVS_ALIGNLEFT) пиктограммы выравниваются по верхней границе окна. Такое поведение соответствует стилю LVS_ALIGNTOP. Вы можете также выровнять пиктограммы по левой границе окна, задав стиль LVS_ALIGNLEFT. Разумеется, стили LVS_ALIGNTOP и LVS_ALIGNLEFT несовместимы, поэтому вы можете использовать только один из них.

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

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

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

Итак, вы создали окно органа управления List View, выбрав для него подходящий набор стилей. Теперь следует заняться наполнением этого окна изображениями и элементами списка.

В зависимости от того, в каких режимах будет работать создаваемый вами орган управления List View, вы должны создать один, два или три списка из следующего набора:

  • список стандартных пиктограмм;
  • список пиктограмм уменьшенного размера;
  • список пиктограмм состояния.

Как выбрать нужные списки?

Список стандартных пиктограмм нужен только в том случае, если вы будете использовать орган управления List View в режиме LVS_ICON (рис. 3.2 в разделе "Приложение List Application").

Список пиктограмм уменьшенного размера нужен для всех остальных режимов (рис. 3.1, 3.3, 3.4).

Что же касается списка пиктограмм состояния (state image list), то он используется для выделения состояния отдельных элементов списка. В SDK есть исходные тексты приложения ListCtrl, создающего список пиктограмм состояния.

Для создания списка изображения вы должны вызвать функцию ImageList_Create :

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

Параметры cx и cy определяют, соответственно, ширину и высоту добавляемых изображений. Если вы создаете список пиктограмм стандартного или уменьшенного размера, для определения значения этих параметров следует использовать функцию GetSystemMetrics , передав ей в первом случае параметры SM_CXICON и SM_CYICON , а во втором - параметры SM_CXSMICON и SM_CYSMICON .

Функция GetSystemMetrics была нами описана в 11 томе "Библиотеки системного программиста".

Параметр flags определяет тип изображений, из которых состоит список. Вы можете создавать список из пиктограмм, аппаратно-зависимых битовых изображений DDB или аппаратно-независимых битовых изображений DIB. Приведем список возможных значений параметра flags:

Значение Описание
ILC_COLOR4 4-битовое изображение DIB
ILC_COLOR8 8-битовое изображение DIB
ILC_COLOR16 16-битовое изображение DIB
ILC_COLOR24 24-битовое изображение DIB
ILC_COLOR32 32-битовое изображение DIB
ILC_PALETTE Используются цветовые палитры
ILC_COLORDDB Изображение DDB
ILC_MASK Использование маски. Изображение состоит из двух изображений, причем одно из них является монохромной маской. Такой формат имеют пиктограммы и курсоры

При создании списка изображений из пиктограмм в SDK значение параметра flags рекомендуется указывать как TRUE, однако логичнее указать значение ILC_MASK.

Параметр cInitial определяет размер блока памяти, выделяемого для хранения изображений, так как этот размер зависит от количества изображений. При добавлении в созданный список новых изображений сверх значения, указанного в этом параметре, происходит динамическое изменение размера заказанного блока памяти. Такое изменение выполняется в соответствии со значением параметра cGrow.

Функция ImageList_Create при нормальном завершении возвращает идентификатор созданного списка изображений, который надо сохранить для дальнейшего использования. В случае ошибки возвращается значение NULL.

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

himlSmall = ImageList_Create(
  GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),
  ILC_MASK, 9, 1);
himlLarge = ImageList_Create(
  GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
  ILC_MASK, 9, 1);

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

Мы только что создали списки изображений, однако пока они пустые и орган управления List View ничего о них "не знает".

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

int WINAPI ImageList_AddIcon(
  HIMAGELIST himl, // идентификатор списка изображений
  HICON hicon      // идентификатор добавляемого изображения
);

Если вы добавляете в список пиктограммы, определенные в ресурсах приложения, вызов функции ImageList_AddIcon можно выполнять в цикле, загружая пиктограммы функцией LoadIcon :

for(i = IDI_ICON1; i <= IDI_ICON9; i++)
{
  hIcon = LoadIcon(hInst, MAKEINTRESOURCE(i));
  ImageList_AddIcon(himlSmall, hIcon);
  ImageList_AddIcon(himlLarge, hIcon);
}

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

Подключение списков изображений к органу List View

На данном этапе мы создали и заполнили списки изображений. Теперь их надо подключить к органу управления List View, вызвав макрокоманду ListView_SetImageList :

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

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

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

Значение Содержимое списка
LVSIL_NORMAL Пиктограммы стандартного размера
LVSIL_SMALL Пиктограммы уменьшенного размера
LVSIL_STATE Пиктограммы состояния элементов списка

Макрокоманда ListView_SetImageList посылает органу управления List View сообщение LVM_SETIMAGELIST и определена следующим образом:

#define ListView_SetImageList(hwnd, himl, iImageList) \
  (HIMAGELIST)(UINT)SendMessage((hwnd), LVM_SETIMAGELIST, \
  (WPARAM)(iImageList), (LPARAM)(UINT)(HIMAGELIST)(himl))

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

ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
ListView_SetImageList(hwndList, himlLarge, LVSIL_NORMAL);

Вставка столбцов

Если вы собираетесь просматривать список в виде детального отчета (стиль LVS_REPORT), необходимо вставить нужное количество столбцов, а также определить для каждого столбца заголовок и ширину.

Вставка столбцов выполняется макрокомандой ListView_InsertColumn , посылающей органу управления сообщение LVM_INSERTCOLUMN :

int ListView_InsertColumn(
  HWND hwnd,  // идентификатор органа List view
  int iCol,   // номер столбца
  const LV_COLUMN FAR * pcol); // адрес структуры LV_COLUMN

Нумерация столбцов начинается с нуля.

Перед тем как вызывать макрокоманду ListView_InsertColumn, вы должны по очереди для каждого столбца заполнить структуру LV_COLUMN , определенную следующим образом:

typedef struct _LV_COLUMN 
{ 
  UINT mask; // маска использования полей структуры LV_COLUMN
  int fmt;   // тип выравнивания для столбца
  int cx;    // ширина столбца в пикселах
  LPTSTR pszText; // адрес строки заголовка столбца
  int cchTextMax; // размер буфера, адрес которого 
                  // задан в pszText
  int iSubItem;   // номер дополнительного элемента 
} LV_COLUMN;

Поле маски mask определяет, какие из полей структуры LV_COLUMN будут использованы. Ниже мы перечислили возможные значения масок, которые можно объединять при помощи логической операции ИЛИ:

Маска Заполненное поле структуры LV_COLUMN
LVCF_FMT fmt
LVCF_SUBITEM iSubItem
LVCF_TEXT pszText
LVCF_WIDTH cx

Поле fmt определяет тип выравнивания для столбца. Можно указывать одно из следующих значений: LVCFMT_LEFT, LVCFMT_RIGHT или LVCFMT_CENTER. Они задают, соответственно, выравнивание влево, вправо или по центру столбца.

Ширина столбца в пикселах задается полем cx.

Для того чтобы задать заголовок столбца, вы должны определить буфер и записать в него соответствующую текстовую строку, закрыв ее двоичным нулем. Размер буфера должен быть указан в поле cchTextMax (в байтах).

Теперь о поле iSubItem.

Как мы уже говорили раньше, список содержит элементы, каждый из которых имеет имя и связанную с ним пиктограмму (привязка пиктограммы выполняется на этапе добавления строк). Кроме того, для каждого элемента можно задать дополнительные элементы. В SDK элементы называются item, а дополнительные элементы - subitem.

В режиме детального отчета пиктограмма и название элемента отображаются в самом левом столбце, имеющим номер 0. Дополнительные элементы, заданные в виде текстовых строк, отображаются в остальных столбцах детального отчета (с номерами 1, 2 и т. д.).

В поле iSubItem вы должны записать номер дополнительного элемента, который будет связан с текущим столбцом отчета.

Ниже приведен фрагмент кода, в котором выполняется вставка трех столбцов с номерами 0, 1 и 2:

GetClientRect(hWnd, &rc);
memset(&lvc, 0, sizeof(lvc));
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = (rc.right - rc.left) / 4;
  
lvc.iSubItem = 0;
lvc.pszText = "Application Name";
ListView_InsertColumn(hwndList, 0, &lvc);

lvc.iSubItem = 1;
lvc.pszText = "Icon Name";
ListView_InsertColumn(hwndList, 1, &lvc);

lvc.iSubItem = 2;
lvc.pszText = "Cost, USD";
ListView_InsertColumn(hwndList, 2, &lvc);
ListView_SetColumnWidth(hwndList,2,(rc.right - rc.left) / 8);

Ширина первого и второго столбца устанавливается равной четверти ширины главного окна приложения (которая в нашем случае равна ширине окна органа управления List View).

Ширина третьего столбца устанавливается равной одной восьмой ширины окна, причем для разнообразия мы делаем это при помощи макрокоманды ListView_SetColumnWidth . Эта макрокоманда посылает органу List View сообщение LVM_SETCOLUMNWIDTH . Такую процедуру можно выполнять и позже, а не только в момент создания окна органа управления List View.

Вставка элементов списка

На последнем этапе вы должны вставить в список элементы. Проще всего это сделать с помощью макрокоманды ListView_InsertItem , посылающей органу управления List View сообщение LVM_INSERTITEM :

int ListView_InsertItem(
  HWND hwnd,                 // идентификатор окна List View
  const LV_ITEM FAR * pitem); // адрес структуры LV_ITEM

Перед тем как вставлять элемент, вы должны записать его атрибуты в структуру LV_ITEM , определенную следующим образом:

typedef struct _LV_ITEM 
{ 
  UINT   mask; // маска использования полей структуры LV_ITEM
  int    iItem;       // номер элемента
  int    iSubItem;    // номер дополнительного элемента
  UINT   state;       // текущее состояние элемента
  UINT   stateMask;   // маска состояния элемента
  LPTSTR pszText;     // адрес текстового буфера
  int    cchTextMax;  // размер текстового буфера
  int    iImage;      // номер пиктограммы элемента
  LPARAM lParam;// 32-битовое значение, связанное с элементом
} LV_ITEM;

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

Маска Заполненное поле структуры LV_ITEM
LVIF_TEXT pszText
LVIF_IMAGE iImage
LVIF_PARAM lParam
LVIF_STATE state

Ниже мы привели фрагмент исходного текста приложения List Application, в котором к созданному ранее списку добавляется 9 элементов:

memset(&lvi, 0, sizeof(lvi));
lvi.mask = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
lvi.pszText = LPSTR_TEXTCALLBACK;
for(i=0; i<9; i++)
{
  lvi.iItem = i;
  lvi.iSubItem = 0;
  lvi.cchTextMax = 40;
  lvi.lParam = (LPARAM)&rgApplInfo[i];
	
  lvi.iImage = i;
  ListView_InsertItem(hwndList, &lvi);

  lvi.iItem = i;
  lvi.iSubItem = 1;
  ListView_InsertItem(hwndList, &lvi);

  lvi.iItem = i;
  lvi.iSubItem = 2;
  ListView_InsertItem(hwndList, &lvi);
}

Так как в нашем примере пиктограммы состояния элементов не используются, мы не заполняем поля state и stateMask.

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

Аналогичным образом мы поступаем и с полем iImage, записывая в него номер пиктограммы для элемента. Напомним, что в разных режимах работы органа управления List View будут использованы пиктограммы из разных списков (стандартного и уменьшенного размера).

В поле pszText можно было бы записать адрес текстовой строки, соответствующей названию элемента или дополнительному элементу, однако мы занесли туда значение LPSTR_TEXTCALLBACK . В этом случае адрес нужной строки будет предоставляться при обработке соответствующего извещения, о чем речь еще впереди.

На этом мы завершим описание процесса создания и наполнения органа управления List View. Из-за ограниченного объема книги мы не рассмотрели все особенности процесса. За более подробной информацией вы можете обратиться к справочной документации, которая поставляется вместе с SDK.

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