Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Системное программирование и WinAPI > custom button |
Автор: GP1000 10.4.2009, 18:49 | ||
Подскажите пожалуйста как сделать кнопку на основе иконки . Эта кнопка должна быть прозрачной по отношению к фону на котором она лежит .То есть в нормальном положении это должна быть одна иконка в нажатом положении другая . Я пробовал делать так :
Иконка отрисовывается ,но кнопочный фон серый все равно остается . Где и что я не правильно сделал? Что бы решить эту проблему я пошел другим путем - создавая свои дочерние окна и отрисовывавая в них иконки и самостоятельно отрабатывать их логику . Можно ли все это проще , через обычные кнопки ?? |
Автор: GremlinProg 15.4.2009, 17:38 |
можно попробовать поиграться со стилем WS_EX_TRANSPARENT но похоже, все равно придется перехватывать некоторый функционал кнопки, чтобы встроенная процедура окна ее не заливала тут возможны 2 случая: 1. если фон закрашивается на WM_ERASEBKGND, то достаточно переопределить класс кнопки с нулевой кистьюWNDCLASS::hbrBackground (но я, честно говоря, не припомню, чтобы встроенные классы явно пользовались этим параметром) 2. если фон кнопки закрашивается еще и при рисовании, на WM_PAINT, (а скорее всего так и есть), то можно переопределить класс окна кнопки с заглушками на сообщения WM_ERASEBKGND, WM_PAINT и WM_PRINT, но это, по сути - создание нового класса окна |
Автор: Andrey44 16.4.2009, 07:07 |
По моему это только писать самому свой класс для кнопки, по крайней мере я так и делал. Но можно еще в WM_DRAWITEM рисовать кнопки, но это скажем не очень-то удобно, если кнопок много. |
Автор: GremlinProg 16.4.2009, 10:26 |
GP1000, через WM_DRAWITEM и рисует |
Автор: Andrey44 16.4.2009, 11:20 |
GremlinProg, Я вижу что он рисует и как рисует. А не выходит у него потому-что рисует в том HDC который приходит в LPDRAWITEMSTRUCT. А нужно создавать в памяти рисовать в нем а потом выдавать на отрисовку. Я так и делал. Но очень неудобно когда много кнопок и много картинок. |
Автор: Andrey44 16.4.2009, 14:18 | ||
А кто говорил об ошибке?
А надо рисовать то что находится под кнопкой. Правильно? |
Автор: GremlinProg 16.4.2009, 14:35 | ||
правильно, но двойной буфер без WS_EX_TRANSPARENT прозрачности не принесет ни коим образом |
Автор: Andrey44 16.4.2009, 14:42 | ||
А причем тут WS_EX_TRANSPARENT? Он по-моему вообще не работает. Хотя не стану утверждать. А делал я так. Брал HDC родительского окна брал из его битмапа область над которой находится кнопка и рисовал ее на саму кнопку, по-моему все понятно , а вы стали ко мне придираться. |
Автор: GremlinProg 16.4.2009, 14:58 | ||
я не придираюсь, такой метод будет работать только если родительское окно не отсекает дочерние и это не самый хороший вариант, поскольку накладывает ограничения на родительское окно, а WS_EX_TRANSPARENT заставляет это родительское окно рисовать себя прежде, чем дочернее будет отрисовано, тогда можно гарантировать, что задний фон дочернего уже будет содержать часть родителя, без дополнительных операций |
Автор: Andrey44 16.4.2009, 15:09 |
GremlinProg, вы хотите сказать если я кнопке поставлю стиль WS_EX_TRANSPARENT, то она будет прозрачная? |
Автор: GremlinProg 16.4.2009, 15:18 | ||
нет, я уже писал что для этого требуется: http://forum.vingrad.ru/index.php?showtopic=255037&view=findpost&p=1843435 |
Автор: Andrey44 16.4.2009, 15:21 |
Хорошо, не будем спорить. Но я написал то что делал, и все работает. |
Автор: Emura 21.4.2009, 15:14 | ||||
Задам здесь вопрос. Andrey44
GremlinProg
Именно WS_CLIPCHILDREN и не дает нормально реализовать прозрачность, подскажите как побороть.. |
Автор: GremlinProg 21.4.2009, 17:05 | ||||
ладно, уговорили, привожу пример использования WS_EX_TRANSPARENT:
в приложении - скомпилированный exe'шник как видно, все прозрачно без лишних заморочек Добавлено через 3 минуты и 3 секунды
в пример этот флаг тоже включен |
Автор: Emura 21.4.2009, 18:57 |
Спасибо! ![]() Буду разбираться. Отпишусь о результате. Посмотрел ![]() теперь вопрос ![]() PS: была бы возможность поставил плюс! имхо, ограничение в 100 сообщений - совсем лишее. |
Автор: GremlinProg 21.4.2009, 20:11 |
ну, это немного другой вопрос буферизировать, конечно, реально но эффект от этого будет не полный, поскольку на WS_EX_TRANSPARENT об этой буферизации ни чего не знает хотя в XP этот недочет можно устранить: поставь родительскому окну стиль WS_EX_COMPOSITED, при создании (это встроенная буферизация) после этого, дополнительно, ни чего буферизировать не потребуется |
Автор: Emura 21.4.2009, 20:18 |
Ага, заработало. GremlinProg, Спасибо! А какой негатив от WS_EX_COMPOSITED может проявится? На Висту эта опция распространяется? |
Автор: GremlinProg 21.4.2009, 20:35 | ||
негатива 2 штуки: 1. не видно некоторых операций с мышью, при которых какие-нибудь кнопки меняют состояние 2. подержка этого флага только в XP (и более ни где) по сути, WS_EX_TRANSPARENT с ним и должен использоваться, но раз в последующих версиях WS_EX_COMPOSITED удален, а WS_EX_TRANSPARENT остался, то можно предположить, что эту проблему:
там решили, т.е. в последующих ручная двойная буферизация будет работать полноценно я не тестировал это в висте, точно не скажу, может есть люди, готовые проверить? пример на оба варианта дам, нужно будет только зафиксировать между ними визуальную разницу есть желающие? |
Автор: GremlinProg 21.4.2009, 20:56 |
похоже, есть еще один негатив, с AlphaBlend: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100477 |
Автор: Emura 21.4.2009, 21:10 |
Да уж.. не обнадеживает. Чтож так все антипрозрачно с этой прозрачностью. Кстати а можно на лету вкл\ выкл WS_CLIPCHILDREN ? Если можно, то к примеру 1. при показе родителя WS_CLIPCHILDREN выкл, 2. копируем фон родителя 3. вкл WS_CLIPCHILDREN 4. используем скопируемый фон для отрисовки потомков как душе угодно или это бред? |
Автор: GremlinProg 21.4.2009, 21:18 | ||
если нужна двойная буферизация, то делай как советовал Andrey44, возможно даже не придется отключать WS_CLIPCHILDREN (если копировать фон не с родителя, а с самого себя) Добавлено через 4 минуты и 39 секунд хотя сечас вот, засомневался если WS_CLIPCHILDREN не убирать, то все равно придется фон родителя воспроизводить на прозрачном окне по-новой (хотя это и не проблема, если фон известен, например: статическая картинка) Добавлено через 10 минут и 43 секунды
а, без разницы, сам подумай, если использовать экран в качестве буфера заднего фона, то он в любом случае ОБНОВИТСЯ ДВАЖДЫ: 1. прорисуется родитель 2. прорисуется дочерний, затирая родителя даже если это обновление будет не частым, моргание будет видно |
Автор: Emura 21.4.2009, 21:29 | ||||
GremlinProg Да,я тоже сомневаюсь. Andrey44:
Взять область при WS_CLIPCHILDREN не получится. Она то как раз и вырезана, там нет фона из-за WS_CLIPCHILDREN. А использовал он WS_CLIPCHILDREN или нет я так и не понял, скорее всего нет, если у него получилось то, что он описал.
возможно, а если она стретчится. в зависимости о размера окна это не вариант.. проблем нет если родитель одноцветен. аа понял, впринципе да, согласен на счет картинки. точно! А вот если градиент программно рисуем? то тут нифига. |
Автор: GremlinProg 21.4.2009, 21:37 | ||||
я конкретно в таком случае использовал IPicture::Render, т.е. именно воспроизвожу статический рисунок (с растяжкой) прекрасно работало, попробуй Добавлено через 2 минуты и 28 секунд родитель же известен, следовательно его координаты - тоже можно спокойно идентифицировать свой участок фона, даже с учетом масштабирования Добавлено через 7 минут
да, похоже, область будет прозрачна вплоть до первого пра-родителя, с включенным WS_CLIPCHILDREN, а при отсутствии таковых - будет светиться десктоп и все, что на нем в данный момент |
Автор: GremlinProg 21.4.2009, 21:55 |
вообще, я уже писал про WM_PRINT и WM_PRINTCLIENT - очень удобно, и воспроизводить по- сути - ни чего не нужно, и поддержка этих сообщений уже встроена на уровне системных компонент (EDIT, COMBO, TOOLBAR, и т.п.) рисование второго буфера тогда сводится к посылке самому себе WM_PRINT/CLIENT, то же самое касается и родителя (WS_CLIPCHILDREN используется только в BeginPaint, так что буфера в памяти это не каснется) чтобы получить часть родителя, достаточно создать девайс в памяти и послать его с WM_PRINT/CLIENT, а дальше - действительно - делай шо хошь |
Автор: Emura 22.4.2009, 03:09 |
на счет WM_PRINT и WM_PRINTCLIENT попробовал стащить битмап с родителя, что-то не вышло (если имелось ввиду это) . Видимо от того что я отрисовываю в WM_PAINT или фиг знает.. С помощью WM_PRINT можно получить hdc окна без вырезок под контролы-потомки? GremlinProg, разъясни пожалуйста. ps. по сути если использовать картинку для фона то тогда практически в любых ситуациях можно сотворить прозрачность. но хочется без лишних ресурсов обойтись. у кого виста под рукой протестите пожалуйста: http://forum.vingrad.ru/index.php?showtopic=255037&view=findpost&p=1848827 |
Автор: Andrey44 22.4.2009, 07:43 | ||
WS_CLIPCHILDREN я не использовал, и WS_EX_TRANSPARENT тоже. |
Автор: GremlinProg 22.4.2009, 11:57 | ||
с WM_PRINT'ом и с двойным буфером, это будет выглядеть так:
Добавлено через 12 минут и 39 секунд WS_EX_TRANSPARENT этот пример конечно не касается, он здесь не используется, просто забыл заголовки поправить, но, тем не менее, этот пример переносим на любую ось, а эффект такой же, как и с WS_EX_TRANSPARENT | WS_EX_COMPOSITED (если, конечно неклиентскую область рисовать так же, через буфер) т.е., все негативы снимаются, кроме главного, сопутствующего вообще двойным буферам: при большом количестве таких дочерних компонент, будет заметно общее притормаживание вывода графики (хотя это вопрос оптимизации GUI, т.е. грамотного планирования интерфейса: не должно у пользователя перед глазами маячить сотни кнопок на одной форме, для него это комфорту не прибавит) |
Автор: Emura 22.4.2009, 14:45 | ||
Andrey44
Спасибо за уточнения! ![]() ![]() GremlinProg, Сейчас посмотрим. |
Автор: Emura 22.4.2009, 15:50 | ||||||
Такс, посмотрел код. GremlinProg, очередной респект. вопрос: Как я понял отрисовывается так: а). родитель отрисовывается, путем отсылки самому себе WM_PRINTCLIENT. Вся отрисовка находится в WM_PRINTCLIENT. а в WM_PAINT только двойная буферизация и вывод. б). контрол отрисовывается таким же способом, но перед отрисовкой в WM_PRINTCLIENT отсылаем еще и родителю сообщение WM_PRINTCLIENT, который отрисовывает сам себя и возвращает нам hdc. который мы используем, чтобы сделать контрол "прозрачным". Так ли я понял? ![]() Кстати, можно ведь попробовать обойтись и без WM_PRINTCLIENT. Создаем например: 1. метод который рисует контрол, например DrawBuffer(), возвращающий тотже hdc или bitmap, даже параметры для метода замутить, чтото вроде (_возвращаем всю область || _возвращаем нужный квадрат) 2. метод который выводит, например Draw().
3. и при отрисовки потомка обращаемся к методу родителя DrawBuffer(), и получаем то что хотели
Правильно мыслю? Поправьте если что не так. Естесственно это относится в большей степени к самописным контролам.
Согласен, само собой. ps наконец-то проблема вроде решается причем без негативных моментов и сложного то ничего нет, всё просто до безобразия ![]() |
Автор: GremlinProg 22.4.2009, 16:27 | ||||||
в том-то и дело, что родителю, ровным счетом, все равно на чем рисовать, он не возвращает девайс, а использует тот, что ему передается в параметре WPARAM тут есть еще 2 возможных варианта рисования фона: 1. рисовать фон родителя прямо в WM_PAINT, перед посылкой WM_PRINTCLIENT 2. рисовать фон родителя как он сейчас и рисуется, в WM_PRINTCLIENT оба визуально делают одно и то же, но с точки зрения повторного использования WM_PRINTCLIENT прозрачного окна, сильно различаются: если использовать первый вариант, и при этом, на прозрачном контроле создать еще один прозрачный контрол, то этот дополнительный контрол уже не будет видеть то, что находится на непрозрачном, т.е. на пра-родителе т.о., по возможности, следует использовать второй вариант
ну конечно, если у тебя прозрачное окно четко привязано к родителю
именно так WM_PRINT - универсальный вариант, если на него опираться во всех контролах проекта, то можно спокойно решать сложные полиморфные граф. задачи, разделяя функционал по классам и наследуя один от другого (именно для этого и производится полноценная посылка сообщений "самому-себе", т.е. не завершаем класс, а позволяем его продолжить, перекрыть) |
Автор: Emura 22.4.2009, 16:35 | ||||
именно, опечатался.
да, пока именно так. остоется эксперементировать с полученной информацией и выбирать подходящий вариант. GremlinProg, огромное спасибо за участие в дискуссии и за помощь в разрешении проблемы! ![]() |
Автор: Andrey44 23.4.2009, 07:18 | ||
А какая мельтешня что-то я не понял?Никаких морганий и чего-то подобного нет. Вот попробую собрать маленький пример завтра, тогда и покажу. |
Автор: Emura 25.5.2009, 21:40 |
эх, практически любимая тема ![]() с прозрачностью контролов и способами ее реализации разобрались. GremlinProg, Andrey44 спасибо за помощь, это тема еще многим ищущим будет полезна! а вот теперь я взялся пытать форму 1) хочется сделать чтото вроде прямоугольника(естесственно), только с верхними закругленными краями. да так, чтобы ресайзить можно было. 2) по возможности сделать тень если делать регионом то как возможно реализовать ресайз? подкиньте пожалуйста мыслей для решения задачи. |
Автор: GremlinProg 25.5.2009, 22:50 |
в этой теме и так решается уже более одного вопроса если так дальше ее нагружать, она будет нечитабельной создай новую тему |