Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Системное программирование и WinAPI > Создать таблицу цветов |
Автор: Sphinx 23.6.2010, 07:30 |
Общая задача: создать табличку с образцами цвета и текстовое название этого цвета. Для этого использую ListView к которому прикручен ImageList. Сам ImageList заполняю с помощью ImageList_AddIcon. Но получается как-то не гибко и не практично - если нужно добавить какой-то цвет, то надо рисовать иконку заполненую этим цветом... Было бы лучше заполнять ImageList программно - нужен новый цвет, залил его в соответствующий элемент. Но как это сделать я не знаю. Что посоветуете? |
Автор: Sphinx 23.6.2010, 08:56 | ||
Я представлял себе это немного проще - после ImageList_Create надо заполнить его нужными цветами.
Если я правильно понял, то для этого не нужно создавать ImageList ? А как рисовать, точнее как определить координаты области куда надо залить цвет? Или я ничего не понимаю... |
Автор: GremlinProg 23.6.2010, 09:03 | ||||
да, верно
вся информация по координатам приходит вместе с соответствующими сообщениями: для WM_DRAWITEM - это DRAWITEMSTRUCT для NM_CUSTOMDRAW - это NMLVCUSTOMDRAW |
Автор: Sphinx 23.6.2010, 09:07 |
Спасибо, попробую разобраться. Но с примерчиком было бы проще. |
Автор: GremlinProg 23.6.2010, 10:23 |
пример тут: http://msdn.microsoft.com/en-us/library/bb761817(v=VS.85).aspx |
Автор: Sphinx 23.6.2010, 12:47 |
Не получается. В обработчике NM_CUSTOMDRAW делается вызов только CDDS_PREPAINT. В нем, как и в примере ничего не делаю, только возврат CDRF_NOTIFYITEMDRAW. Все, дальше дело не идет, вызов CDDS_ITEMPREPAINT никогда не проходит. |
Автор: GremlinProg 23.6.2010, 13:00 |
очевидно дело в выборе режима отображения: |
Автор: Sphinx 23.6.2010, 14:46 |
Стоит флаг LVS_REPORT. Табличку я же вижу в текстовом виде. Может еще какие-то флаги нужны. |
Автор: GremlinProg 23.6.2010, 14:59 |
а если попробовать вот так: http://msdn.microsoft.com/en-us/library/ms364048(VS.80).aspx#customdraw_topic4 |
Автор: Sphinx 23.6.2010, 15:16 |
Попробую разобраться... но на первый взгляд не вижу принципиальных отличий. |
Автор: Earnest 23.6.2010, 15:29 |
Честно говоря, не понимаю зачем здесь CustomDraw\OwnerDraw. Разве что поучиться, ибо полезная весчь. А задачу я бы решала, как автор изначально предлагал: нужно добавить цвет - добавляем еще один элемент в ImageList, а потом в лист-вью. В чем проблема-то? Создаем совместимый битмап нужного размера, заполняем его нужным цветом (да хотя бы с помощью PatBlt), вставляем в ImageList... что еще? |
Автор: GremlinProg 23.6.2010, 15:40 | ||||
![]() не для того он нужен: можно ведь комаров бить и сковородкой, но ведь она не для этого предназначена Добавлено через 4 минуты и 25 секунд скажу больше: для такой задачи я бы использовал listbox |
Автор: Earnest 23.6.2010, 15:51 |
Ну, вопрос вкуса. Разрабатывать ImageList для такого случая точно бы не стоило, но он уже есть, так что пусть работает... Да и у автора уже реализация была на его основе, совсем чуть-чуть изменить. Чем меньше мне по кнопкам тыкать тем лучше - в самом общем случае ... ![]() |
Автор: GremlinProg 23.6.2010, 16:06 |
нет, я непротив, можно оставить все как есть, обычно это был бы правильный выбор: как спланировал - так и сделал, работодатель это оценит (если узнает ![]() прсто вопрос был как раз о гибкости и что лучше |
Автор: Sphinx 23.6.2010, 19:23 | ||||
Этот вариант был использован только потому, что я не знал другого. А вариант через ImageList был неоднократно опробован. Но одно дело, когда в ImageList добавить пяток, десяток образцов иконок, а когда несколько десятков, то тут становится сложнее создавать образцы и корректировать цвета. Возникла идея создавать в памяти множество (по количеству цветов) 24-битных битмапов, заполняя их нужным цветом и потом включать их в ImageList. Но как это делать я не знаю и, собственно об этом изначально был вопрос.
Можно немного подробнее, достаточно просто перечислить функции и очередность их вызова. Но вариант через NM_CUSTOMDRAW мне больше нравится. Он более гибок и менее ресурсоемок. Вот только не удается получить работающий код. Если удастся заставить его работать, то я предпочту этот вариант. Если сказал А, то говори и Б. Какова последовательность действий для этого? |
Автор: Earnest 23.6.2010, 19:57 |
Sphinx, если несколько десятков, да еще и редактировать, тогда действительно, лучше через CustomDraw. Но можно и через ImageList. Вообще, полезно иметь выбор, в голове, на будущее, и вообще. Значит, насчет добавления в ImageList 1) создать битмап - CreateCompatibleBitmap - но может и не совместимый, а какой-то конкретной цветности - суть в том, что все картинки в ImageList должны быть одинаковых размеров и цветности.. 2) совместимый контекст - CreateCompatibleDC, 3) дальше выбираем битмап в контекст (SelectObject) и рисуем в этом контексте что хотим. В твоем случае - нужно просто закрасить - куча вариантов на любой вкус: от Rectangle до PatBlt 4) Осталось добавить битмап в ImageList: одна из функций Add, т.е. ImageList_AddXXX проще всего, по-моему, использовать Masked, в качестве цвета маски передать что угодно - хоть белый, хоть черный, лишь бы не свой. 5) Если захочется редактировать, то насколько помню, есть функции Set\Get |
Автор: Sphinx 23.6.2010, 20:54 | ||
А битмап может быть один или надо создавать их столько сколько нужно цветов? Если один, то как указать, где заканчивается один цвет и начинается другой? т.е как один битмап подключить к ImageList несколько раз. |
Автор: Sphinx 24.6.2010, 09:05 | ||
Сделал тестовый вариант, работает:
Посмотрите, все ли корректно. Не уверен в манипуляциях с контекстами - все ли что нужно удаляется. |
Автор: Earnest 24.6.2010, 09:07 | ||
Sphinx, можно по-разному. Если нужно сразу загрузить несколько цветов, то можно все их в один битмап засунуть и раскрасить по секциям. Ну примерно так, как ты тулбар рисуешь - посмотри на битмап, соответствующий тулбару, и все поймешь. Граница цветов определяется размерами картинки в ImageList (т.е. ее шириной). ImageList из этого битмапа нарежет себе столько картинок, сколько в нем секций заданной ширины. А потом можно добавлять по одному. Естественно, для добавления битмап создается временный - после запихивания в ImageList хранить его не надо. Добавлено через 7 минут и 44 секунды
Перед этим нужно "освободить" битмап из контекста - пока он выбран, он на самом деле не удалится. Проще всего сохранят то, что возвращает SelectObject, и потом восстанавливать. Кроме того, нет никакой необходимости создавать и разрушать контекст и битмап в цикле, можно просто перекрашивать. Т.е. в цикле остается только Filling и ImageList_Add. И я бы поставила проверку, что ImageList_Add возвращает i: что-то типа VERIFY (ImageList_Add(himl, hbmScreen, NULL) == i); Даже не столько ради самой проверки, а чтобы показать читателю, что соответствующая цвету картинка имеет индекс i. |
Автор: Sphinx 24.6.2010, 09:17 |
Спасибо, с битмапом понятно, а вот как в таком случае с ImageList? Какой размер указывать и количество. Если реальные, то получится в нем всего один image. |
Автор: GremlinProg 24.6.2010, 09:21 | ||||||||
:)) 1. создаешь массив, допустим так:
2. создаешь список со стилями LBS_OWNERDRAWFIXED | LBS_NODATA 3. задаешь число его элементов:
4. перехватываешь у родителя WM_DRAWITEM:
вроде бы все, фокус и выделение не рисовал, сам нарисуешь, код не проверял, принцип должен быть ясен |
Автор: Earnest 24.6.2010, 09:23 |
Размер - это размер картинки, тут сам определись. Он сам определит, сколько отдельных изображений получится. Только тогда нужно использовать не Add, а Load. А потом никто не мешает добавлять картинки по одной, как ты сделал в цикле. Добавлено через 2 минуты и 26 секунд А нет, вру. В добавляемом через Add битмапе тоже может содержаться несколько картинок. A Load - это из ресурсов. |
Автор: Sphinx 24.6.2010, 10:03 | ||||||
Почему то не получается так. Пока не удален контекст, содержимое битмапа не копируется, хотя ImageList_Add отрабатывает корректно.
А что, бывают случаи когда индекс начинается не с нуля или перепрыгивает? Добавлено через 5 минут GremlinProg, спасибо. Буду разбираться и пробовать. Добавлено через 14 минут и 51 секунду Earnest, удалось пользоваться одним битмапом, вот подправленный вариант:
|
Автор: Earnest 24.6.2010, 12:25 | ||
Нет, но, во-первых это проверка для того, чтобы лишний раз убедиться, что в ImageLis нет лишних картинок. Ты ведь говорил о том, что нужно добавление динамическое, т.е. в произвольные моменты времени. Т.е. этот код - стартовый. А кроме того, чтобы читатель понял как извлечь картинку для цвета из ImageList он должен опираться на неявные знания: что ImageList возвращает индекс добавленной картинки, что в нем ровно столько картинок, сколько ты сделал цветов и т.д. Поверь, такие вещи забываются очень быстро, так что код должен помогать читателю. Странно, что неосвобожденный битмап не копируется, я никогда не сталкивалась, но все возможно. Я бы тогда создала 1 битмап шириной NUMCOLORS картинок, нарисовала в нем все цвета и добавила все скопом. Т.е. в цикле будет только раскраска прямоугольников (со сдвигом по х, конечно). |
Автор: Sphinx 24.6.2010, 13:00 | ||
Не соглашусь. Откуда там взяться лишним картинкам, если ImageList только что создан. Вся информация о цвете (его hex-код, текстовое название...) хранится в массиве структур из которого она последовательно выбирается для добавления к ImageList. Поэтому индекс цвета и индекс в массиве структур должны и будут совпадать. При добавлении нового цвета он будет добавляться в конец массива структур и в конец ImageList. Другое дело, если массив структур со свойствами цветов будет сортироваться. Тогда надо будет в него добавлять поле со значением индекса в ListImage. После ImageList_Add надо делать проверку, что функция отработала корректно и если да, то можно сохранить возвращенный индекс в свойствах цвета (если в этом есть необходимость). А делать проверку соответствия возвращеного индекса индексу в массиве структур... не знаю, мне кажется безсмысленно. |
Автор: Earnest 24.6.2010, 16:21 | ||
Т.е. ImageList когда-то создан, а потом туда по мере необходимости картинки добавляются. Но если не хочешь, чтобы не надо, убеждать не буду. |