Blog. Just Blog

Раскраска строк ListView на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Элемент диалоговых окон ListView (или SysListView32) - очень удобный элемент, особенно для табличного отображения данных или ведения логов. При всем своем удобстве, у него есть недостаток, что при заполнении списка нельзя указывать цвета текста и фона для отдельных строк. Но способ раскрасить строки ListView все-таки есть. При отрисовке списка окну приложения посылается сообщение WM_NOTIFY, которое можно перехватить и самостоятельно обработать. В lParam сообщения передается указатель на структуру NMLVCUSTOMDRAW, в которой и описаны все подробности об отрисовываемой строке. Это составная структура и ее составляющие зависят от версии библиотеки Comctl32, но описываемый способ не сработает разве что на Windows 95, если вы его где-то откопаете. Однако компилятор FASM тоже ни сном, ни духом про структуру NMLVCUSTOMDRAW, придется сделать описание самостоятельно:
  1. ; Структура для обработки сообщений
  2. struct NMLVCUSTOMDRAW
  3.         ; NMHDR
  4.         hwndFrom        dd ?
  5.         idFrom          dd ?
  6.         code            dd ?
  7.  
  8.         ; NMCUSTOMDRAWINFO
  9.         dwDrawStage     dd ?
  10.         hdc             dd ?
  11.         left            dd ?
  12.         top             dd ?
  13.         right           dd ?
  14.         bottom          dd ?
  15.         dwItemSpec      dd ?
  16.         uItemState      dd ?
  17.         lItemlParam     dd ?
  18.  
  19.         ; NMLVCUSTOMDRAW
  20.         clrText         dd ?
  21.         clrTextBk       dd ?
  22. ends
Теперь разберем значения полей структуры. В hwndFrom должен быть хэндл списка ListView, в code - уведомление NM_CUSTOMDRAW. Если эти два условия выполняются, то требуется задействовать наш обработчик. А вот дальше есть важные особенности. Отрисовка строки выполняется в два этапа: сперва в dwDrawStage приходит уведомление CDDS_PREPAINT, на которое окно приложения должно ответить установкой статуса CDRF_NOTIFYITEMDRAW, то есть надо сообщить системе, что мы хотим самостоятельно внести коррективы в процесс отрисовки. В этом случае система посылает еще одно уведомление - CDDS_ITEMPREPAINT, и именно на этом втором этапе мы можем указать цвет фона и текста для строки. Цвет текста задается в clrText, а цвет фона - в clrTextBk. Весь этот процесс описан в MSDN, но как-то слишком разрозненно.

После теоретической подготовки переходим к практике. Сперва сделаем список с раскраской "зеброй", то есть чередование светлого и более темного фона строк. Это значительно повышает наглядность, особенно на широких таблицах. В параметре dwItemSpec структуры NMLVCUSTOMDRAW передается индекс (порядковый номер) строки. Проверяем его, и, если индекс четный, то устанавливаем один фон, если нечетный - другой. Обработчик WM_NOTIFY для окна ListView будет выглядеть примерно так:
  1.         ; Сообщение NM_CUSTOMDRAW?
  2.         cmp     dword [eax+nml.code],NM_CUSTOMDRAW
  3.         jne     .processed
  4.  
  5.         ; Пред-отрисовка строки?
  6.         cmp     dword [eax+nml.dwDrawStage],CDDS_PREPAINT
  7.         jne     @f
  8.  
  9.         ; Установить ответ окна
  10.         invoke  SetWindowLong,[hwnddlg],DWL_MSGRESULT,CDRF_NOTIFYITEMDRAW
  11.         mov     eax,CDRF_NOTIFYITEMDRAW
  12.         jmp     .processed
  13. @@:
  14.         ; Требуется нарисовать строку?
  15.         cmp     dword [eax+nml.dwDrawStage],CDDS_ITEMPREPAINT
  16.         jne     @f
  17.  
  18.         ; Цвет фона нечетных строчек
  19.         mov     esi,0E0E0E0h
  20.         ; Проверить индекс строки на четность
  21.         test    dword [eax+nml.dwItemSpec],1
  22.         jnz     .row_odd
  23.  
  24.         ; Цвет фона четных строчек
  25.         mov     esi,0FFFFFFh
  26. .row_odd:
  27.         ; Установить цвет текста строки
  28.         mov     dword [eax+nml.clrText],0
  29.         ; Установить цвет фона
  30.         mov     dword [eax+nml.clrTextBk],esi
  31. @@:
  32.         jmp     .processed
Как видите, ничего сложного. Дополнительный плюс в том, что при добавлении или удалении строчек в списке, его раскраска "зеброй" будет каждый раз автоматически пересчитываться и правильно перерисовываться. Но этот же плюс выходит боком в случае, если индивидуальная раскраска требуется только для отдельных строчек списка. При прокручивании или обновлении окна списка вызывается его перерисовка, поэтому раскраску каждой строки придется хранить где-нибудь в памяти и обрабатывать индивидуально. Разберем это на более сложном примере, теперь строки списка будут раскрашены в случайные цвета, значения которых будут храниться в массиве.
  1. section '.data' data readable writeable
  2. ...
  3. colors  rd      1000    ; Массив фоновых цветов строк
  4. ...
При заполнении списка сохраним в массиве цвет каждой строки:
  1.         ; Заполнить список строчками
  2.         xor     ebx,ebx
  3. @@:
  4.         ...
  5.         ; Тут вызывается какая-нибудь функция генерации случайного числа,
  6.         ; результат которой записывается в EAX
  7.         ...
  8.  
  9.         ; Сохранить цвет фона в массиве
  10.         mov     ecx,ebx
  11.         shl     ecx,2
  12.         and     eax,0FFFFFFh
  13.         mov     [colors+ecx],eax
  14.  
  15.         ...
  16.         ; Добавляем строку в список
  17.         ...
  18.  
  19.         inc     ebx
  20.         cmp     ebx,1000
  21.         jb      @b
Обработчик WM_NOTIFY для окна ListView немного меняется. Теперь цвет фона не зависит от четности строки, а берется из массива цветов по номеру строки. Для простоты цвет текста берется инверсным к цвету фона, в реальном проекте можно также задавать его при добавлении строк и хранить в соответствующем массиве.
  1.         ; Сообщение NM_CUSTOMDRAW?
  2.         cmp     dword [eax+nml.code],NM_CUSTOMDRAW
  3.         jne     .processed
  4.  
  5.         ; Пред-отрисовка строки?
  6.         cmp     dword [eax+nml.dwDrawStage],CDDS_PREPAINT
  7.         jne     @f
  8.  
  9.         ; Установить ответ окна
  10.         invoke  SetWindowLong,[hwnddlg],DWL_MSGRESULT,CDRF_NOTIFYITEMDRAW
  11.         mov     eax,CDRF_NOTIFYITEMDRAW
  12.         jmp     .processed
  13. @@:
  14.         ; Требуется нарисовать строку?
  15.         cmp     dword [eax+nml.dwDrawStage],CDDS_ITEMPREPAINT
  16.         jne     @f
  17.  
  18.         ; Получить номер строки
  19.         mov     ebx,dword [eax+nml.dwItemSpec]
  20.         ; Вычислить индекс массива фоновых цветов
  21.         shl     ebx,2
  22.         mov     esi,[colors+ebx]
  23.         ; Вычислить текст текста - инверсный от цвета фона
  24.         mov     edi,esi
  25.         not     edi
  26.         and     edi,0FFFFFFh
  27.  
  28.         ; Установить цвет текста строки
  29.         mov     dword [eax+nml.clrText],edi
  30.         ; Установить цвет фона
  31.         mov     dword [eax+nml.clrTextBk],esi
  32. @@:
  33.         jmp     .processed
Некоторая сложность этого метода заключается в том, что при добавлении или удалении строчек в списке обязательно требуется вносить изменения и в массив цветов, также удаляя или добавляя в него нужные значения.

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

Примеры программ с исходными текстами (FASM)Примеры программ с исходными текстами (FASM)

Coloured.ListView.Demo.zip (7,322 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 3943 | Комментариев: 6

Метки: Assembler, окна
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Grey (20.12.2013 в 15:27):
осечка, млин
;-)))
ManHunter (20.12.2013 в 15:18):
"Нельзя просто взять и воткнуть иконки" (С) Боромир :)
Иконки можно взять откуда угодно напрямую, но вставить их в ListView все равно придется только через ImageList, предварительно добавив их туда.
Grey (20.12.2013 в 15:17):
Т.е. без добавления ImageList не обойтись...? Я наивно полагал что и напрямую иконки можно воткнуть.
ManHunter (20.12.2013 в 15:05):
Не планируется, но подумаю.
И штудирование MSDN никто не отменял:
http://msdn.microsoft.com/en-u...s.85%29.aspx
http://www.frolov-lib.ru/books...2/ch3_1.html
Grey (20.12.2013 в 15:03):
Как добавить иконки к строкам в ListView (или TreeView)? Второй части статьи не будет?
int_90 (03.02.2012 в 01:06):
А не подскажите как работать с выделенной строкой?(к примеру выделил(не кликнул) строку открылась подсказка).Перерыл пол гугля

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2017
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.1 сек. / MySQL: 2 (0.0045 сек.) / Память: 4.5 Mb
Наверх