Программирование на Visual C++. Архив рассылки - Алекс Jenter
Шрифт:
Интервал:
Закладка:
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
static HBITMAP hBm = NULL;
...
case WM_DRAWITEM:
return DrawClassicStyleBtn((LPDRAWITEMSTRUCT)lParam, hBm);
...
}
void DrawClassicStyleBtn(LPDRAWITEMSTRUCT pis, HBITMAP hBm, int deflate = 4) {
UINT uState = DSS_NORMAL;
UINT uEdge = EDGE_RAISED;
int x = 0, y = 0;
BOOL bFocus = FALSE;
RECT rFocus;
if (IDC_BMPBTN == pis->CtlID) {
switch(pis->itemAction) {
case ODA_DRAWENTIRE:
case ODA_SELECT:
if (pis->itemState & ODS_DISABLED) {
uState = DSS_DISABLED;
} else if (pis->itemState & ODS_SELECTED) {
x += 1; // сдвиг всего рисунка вправо-вниз подчеркивает
y += 1; // визуальный эффект нажатия кнопки
uEdge = EDGE_SUNKEN;
}
break;
case ODA_FOCUS:
if (pis->hwndItem == GetFocus()) {
memcpy(&rFocus, &pis->rcItem, sizeof(RECT));
rFocus.left += deflate;
rFocus.top += deflate;
rFocus.right -= deflate;
rFocus.bottom -= deflate;
bFocus = TRUE;
}
break;
}
DrawState(pis->hDC, NULL, NULL, (LONG)hBm, 0, x, y, 0, 0, DST_BITMAP | uState);
DrawEdge(pis->hDC, &pis->rcItem, uEdge, BF_RECT);
if (bFocus) DrawFocusRect(pis->hDC, &rFocus);
}
}
Выигрыш подобного подхода состоит в меньшем использовании самостоятельно подготавливаемых ресурсов и меньшем их потреблении при работе программы. К недостаткам (и весьма заметным, на мой взгляд) можно отнести то, что происходит потеря контроля над внешним видом кнопки в различных ее состояниях. Впрочем, работа этих упомянутых функций ориентирована на поддержание стандартного внешнего вида контролов, поэтому и результат не очень выразителен. На мой взгляд, данная техника больше подходит к выполнению кнопок, имеющих в основном стандартный внешний вид, но снабженных небольшими изображениями по соседству с текстом кнопки.
Следует заметить , что при необходимости можно (а иногда и нужно) пользоваться комбинацией приведенных методик: предположим, использовать для отрисовки чертыре битмапа, но границу рисовать функцией DrawEdge().
При подготовке данного материала мною использован код, опубликованный в одном из сообщений эхоконференции SU.WIN32.PROG (FidoNet). Автор кода – Dmitry Timoshkov <[email protected]> – вполне может и не узнать его, поскольку код был мною довольно сильно переработан и дополнен :-))).
На сегодня все. До встречи!
Алекс Jenter [email protected] Красноярск, 2001. Рассылка является частью проекта RSDN.Программирование на Visual C++
Выпуск №51 от 21 октября 2001 г.
Здравствуйте, уважаемые подписчики!
Наконец-то вы дождались нового сезона выхода рассылки! Вы наверное уже наверняка заметили, что отпуск немного (честно говоря, намного) затянулся. Это связано с моим переездом – получилось так, что мне повезло выиграть стипендию на прохождение магистерской программы в немецком университете. В такой ситуации без всяческих проблем не обойтись, и надо сказать адаптация в Германии заняла гораздо больше времени, чем я рассчитывал. Да и интернет тут у меня появился совсем недавно. Так что прошу прощения за столь долгую отлучку. Теперь все в порядке, и рассылка опять будет набирать обороты.
Видя, что рассылка так долго не выходит, меня спрашивали, не нужна ли помощь. Отвечаю – помощь всегда нужна! Сейчас помощь больше всего нужна сайту RSDN – в том смысле, что нам не хватает талантливых людей, готовых вести разделы на сайте, верстать статьи и пр. и пр. Если вы чувствуете себя в силах помочь – милости просим, пишите на [email protected]!
И еще один организационный вопрос. Рассылка, как и раньше, будет выходить один раз в неделю и предположительно по воскресеньям, хотя день может и меняться.
Подключившись наконец к интернету и забрав накопившиеся письма, я узнал, что в выложенном мной перед уходом в отпуск chm-файле с архивом рассылки есть некоторые недоработки – а именно, с поиском. Это в принципе неудивильно, так как создавался этот файл достаточно спешно ;-) Я в ближайшее время постараюсь разобраться с этим.
Ну, это пока все, что я хотел сказать. Теперь – вперед, к вершинам мастерства!
СТАТЬЯ
Использование ListView в режиме виртуального списка
Автор: Тимофей Чадов
Демонстрационная программа – 161 KB
Исходные тексты – 39 KB
Все программисты делятся на тех, кто повсеместно применяет виртуальный режим, и тех, кто о нем даже и не слышал. Конечно, это шутка, как и любая с долей … шутки-)
На таких сайтах как CodeGuru, есть несколько неплохих примеров применения виртуальных списков. Однако, многие программисты, с которыми мне приходится сталкиваться, лишь изредка прибегают к этой технике, ошибочно считая, что это если не извращение, то уж по крайней мере излишество. Многие заблуждаются, считая, что применение виртуальных списков необходимо только лишь в случаях больших массивов данных, например, при отображении информации из баз данных. Конечно это справедливо, однако, о чем действительно часто забывают – применение виртуальных списков позволяет не только повысить производительность, но и обеспечивает разделение данных и их представлений. Последнее, на мой взгляд, не менее важно.
Конечно, как и везде, нужно знать меру. Не стоит сломя голову бежать переписывать свой код, если требуется вывести диалоговое окно для выбора десятков элементов: cойдет и обычный подход. Однако, если логика вашего приложения основана на применении представления на основе ListView с широкими возможностями по добавлению|удалению|редактированию, да к тому же большого объема записей, – стоит задуматься о виртуальном режиме.
Итак, в этой статье я попробую приподнять завесу тайны над этим чудесным режимом. Вы готовы к путешествию в виртуальность?
Виртуальность это простоДля работы с виртуальным списком в простейшем случае достаточно следующего:
• Создать виртуальный список
• Вовремя заботиться о количестве элементов
• По запросу списка заполнять элементы нужной информацией
В некоторых случаях возможно понадобятся и более сложные вещи:
• Кеширование
• Сортировка
• Быстрый поиск элементов
Итак, обо всем по порядку.
Переход в режим виртуальностиЧтобы включить режим "виртуальности", необходимо установить стиль LVS_OWNERDATA. Текущая версия библиотеки элементов управления не позволяет переводить список из обычного режима в виртуальный "на лету", поэтому установку данного стиля необходимо делать при создании элемента. Если вы использует редактор диалога достаточно отметить переключатель Owner Data на вкладке More Style в окне свойств List Control. В случае применения класса СListView следует перекрыть PreCreateWindow.
Вся прелесть виртуального режима в том, что список хранит не сами элементы, а только их общее количество, диапазон отображаемых в данный момент, и тому подобную "мелочь". Значения самих элементов (строковые метки, рисунки и т.п) запрашиваются у приложения непосредственно перед их отрисовкой на экране. Такой прием позволяет значительно сэкономить память и существенно повысить производительность, особенно для больших объемов данных.
ПРИМЕЧАНИЕ
В MSDN сказано, что после установки данного стиля, число элементов, которые сможет хранить список, будет ограничено максимальным значением DWORD (для обычных списков только int). Однако, все функции (в том числе и API) для работы со списком принимают int. Кроме этого, мне не удалось использовать более 100.000.000 элементов. Более того, в примере MSJ за ноябрь 1996 г. от Strohm Armstrong встречается именно эта магическая цифра. Отговорка стандартна: "Сложно представить, что возникнет необходимость использовать больше". Нет вопросов, если бы использовалась хотя бы степень двойки, а так, IMHO, ограничение такой странной (круглой) цифрой выглядит коварным замыслом.
Количество элементовИтак, список создан. Чтобы вставить в него элементы, достаточной задать их количество. Количество элементов в виртуальном списке задается одной из следующих функций.
void CListCtrl::SetItemCount(int iCount)
void CListCtrl::SetItemCountEx(int iCount, DWORD dwFlags = LVSICF_NOINVALIDATEALL);
iCount новое количество элементов dwDlags Комбинация флагов, определяющая реакцию списка на изменение количества элементов. LVSICF_NOINVALIDATEALL Список не будет перерисован, пока добавленные элементы не окажутся с поле видимости. LVSICF_NOSCROLL Позиция скроллинга не изменитсяТаким образом, все что нам нужно, чтобы оперировать элементами списка, – это задать их количество. Никаких вызовов InsertItem, DeleteItem и т.п. Это существенно упрощает код, отвечающий за манипуляцию с данными. Конечно, это не избавляет от подобных операций с самой информацией, однако, разделение данные-представление благоприятно сказывается на ясности кода, а значит способствует уменьшению ошибок.