Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Использование checkbox в списке ClistCtrl


DevDoc home page
 
   
 

Выпуск №11

Продолжаем рассматривать возможности списков. CListCtrl содержит множество опций, которые позволяют изменять внешний вид и поведение списка. Ниже рассматриваются способы добавления checkbox'ов к каждому элементу списку. Комбинируя эти техники с другими возможностями списков - можно получать профессионально оформленные программы. Читайте об этом ниже.

Продолжается регистрация участников конкурса по программированию. На момент выпуска статьи получены заявки от 35 программистов. Присоединяйтесь! Правила и заявка на регистрацию


Все материалы доступны на сайте http://www.devdoc.ru Наш девиз - новые статьи каждую неделю. Ресурс находится в постоянном развитии. Если у Вас есть интересный материал, вы можете опубликовать его на сайте. Инструкция по публикации.

Пожалуйста, присылайте свои вопросы и пожелания к темам статей на sub12@devdoc.ru

Если вам нравиться эта рассылка рекомендуйте ее своим друзьям. Подписаться можно по адресу http://subscribe.ru/catalog/comp.soft.prog.devdoc


Постоянная ссылка на статью: http://www.devdoc.ru/index.php/content/view/checkbox_clistctrl.htm

Автор: Кудинов Александр
Последняя модификация: 2007-03-05 20:54:19

Использование checkbox в списке ClistCtrl

Скачать исходники

Введение

Пожалуй, список - это один из самых популярных элементов управления в программах. Если не считать разные кнопки. Обычно списки строятся на базе CListCtrl. Он предоставляет разработчику множество опций. До версии 4.7 он не поддерживал чекбоксы для своих элементов. Для реализации этой функции можно было использовать класс CCheckListBox. Благодаря нововведению можно совмещать checkbox с остальными полезными функциями: Custom/Owner Draw, сортировка, поиск, рисование иконок рядом с элементами.

Как добавить CeckBox в CListCtrl?

Существует несколько путей для решения этой задачи. Наиболее распространенные:

  • Использовать режим Owner Draw и рисовать галочку самостоятельно. Это замечательный способ, если надо получить нестандартный внешний вид.
  • Использование Custom Draw. Метод имеет свои особенности, но в целом практически идентичен предыдущему варианту.
  • Можно рисовать иконку рядом с элементом, используя стандартные средства CListCtrl. При этом надо будет самостоятельно отслеживать нажатия на иконку, и менять ее внешний вид. Впрочем, собственную обработку надо выполнять и для предыдущих методов.
  • Использовать новые возможности CListCtrl.

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

Первые 3 варианта я не буду рассматривать, т.к. они достаточно трудоемки и могут понадобиться в очень редких случаях. Итак, приступим.

Включение чекбоксов

Сразу после создания объекта CListCtrl, или экземпляра вашего класса на его основе, необходимо вызывать:

ListView_SetExtendedListViewStyle(m_wndView.m_hWnd, LVS_EX_CHECKBOXES);

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

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

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

Если вы создали свой класс на базе CListCtrl, как в примере к статье, то вам надо добавить в карту сообщений этого класса строку:

ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnItemchangedLinksList)

Затем создать функцию следующего вида:

void CChildView::OnItemchangedLinksList(NMHDR* pNMHDR, LRESULT* pResult)
{
 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
 *pResult = 0;
 
 if (pNMListView->uOldState == 0 && pNMListView->uNewState == 0)
  return;    // не было изменений
 
 
 // Старое состояние чекбокса
 BOOL bPrevState = (BOOL)(((pNMListView->uOldState & 
  LVIS_STATEIMAGEMASK)>>12)-1);  
 if (bPrevState < 0)    // При первом запуске состояние может быть не определено
  bPrevState = 0;    // поэтому ставим его по умолчанию в false
 
 // Считать новое состояние
 BOOL bChecked = 
  (BOOL)(((pNMListView->uNewState & LVIS_STATEIMAGEMASK)>>12)-1);   
 if (bChecked < 0) // Новое состояние может быть неопределено. По умочанию тоже ставим false
  bChecked = 0; 
 
 if (bPrevState == bChecked) // Нет изменений
  return;
 
 //В этой точке bChecked содержит новое состояние для строки
}

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

Менять состояние элемента можно из программы с помощью метода CListCtrl::SetItemState следующим образом:

Bool bCheck = true;  //новое состояние
SetItemState(iItemIndex, UINT((int(bCheck) + 1) << 12),  LVIS_STATEIMAGEMASK);

Битовый сдвиг нужен, т.к. во флаге состояния элемента управления может быть несколько полей. Единица прибавляется, т.к. индексы состояний начинаются с 1.

См. информацию по LVITEM структуре в MSDN.

Получение состояния может быть выполнено аналогично.

Улучшение внешнего вида CListCtrl

После первого опыта со списком видно, что галочки рядом с элементами «скучные». Часто они не подходят к размеру шрифта и общему дизайну программы. Есть способ обойти это ограничение. К сожалению, в MSDN он описан очень плохо. Здесь я приведу только общие принципы реализации. Ничего сложного в этом нет, поэтому вы с легкостью сможете модифицировать пример к статье, чтобы он рисовал такие галочки, какие вам необходимы.

У CListCtrl есть метод SetImageList. Он позволяет устанавливать изображения иконок, которые будут использоваться при рисовании элементов. Список поддерживает 3 типа иконок:

  • Большие иконки
  • Маленькие иконки
  • Иконки состояния.

Последний тип с легкостью позволяет изменять изображения для иконок состояния. Т.е. надо сделать объект типа CImageList и добавить в него две иконки, которые бы соответствовали установленной и снятой галочке. Все! Теперь CListCtrl будет рисовать нужные вам элементы.

Ну и напоследок еще одна вкусность, которая почему-то замалчивается в документации. Я ее «вычислил», внимательно разглядывая структуру LVITEM. Надеюсь, вы последовали моему совету и сделали то же самое. Можно заметить, что для хранения состояния чекбокса используется член LVITEM ::state. Если быть конкретным, то биты с 12 по 15. Это несколько больше, чем надо для хранения значения true/false! Секрет прост – у каждого элемента может быть больше двух состояний. Причем, список «знает» только об одном – нулевом. Когда все биты равны нулю, то у элемента нет иконки состояния. Остальные значения могут быть произвольными.

Использовать эту особенность не просто, а очень просто. Надо просто создать необходимое количество иконок, поместить их в CImageList, а затем вызвать CListCtrl::SetImageList, чтобы установить новый список иконок состояния. После этого элемент управления будет циклически переключать состояния, и показывать соответствующие иконки.

Состояния можно ставить принудительно с помощью SetItemState: вместо булевого значения надо передавать индекс нужного состояния.

Помните, что индексы начинаются с 1.

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

Если все вышеперечисленное использовать с Виртуальными списками – можно получить очень мощный и гибкий элемент управления. Виртуальные списки позволяют хранить индексы состояния отдельно от элемента управления. Это может дать ряд преимуществ, если надо управлять большим объемом данных и менять состояния по сложным законам.

Наслаждайтесь новыми возможностями!


Если вам нравиться эта рассылка рекомендуйте ее своим друзьям. Подписаться можно по адресу http://subscribe.ru/catalog/comp.soft.prog.devdoc

Copyright (C) Kudinov Alexander, 2006-2007

Перепечатка материалов с данного сайта запрещена без писменного разрешения автора. При перепечатке обязательно указывать ссылку на оригинал.


В избранное