Re[4]: Как изменить цвет кнопки?
От: Mr.Delphist  
Дата: 22.10.19 13:05
Оценка:
Здравствуйте, okon, Вы писали:

O>там цвет кнопки и все остальное , в том числе лейаут контролов, менять ощутимо проще.


Что неудивительно — весь WPF построен на owner draw. Там и HWND как таковых-то и нету, кроме внешнего контейнера.

O>Необходимость в использовании сторонних компонент как правило отпадает, кастомные писать получаетя не так сложно и не дорого.


Зависит от ситуации, причём сильно. Помнится, при нетривиальной интерактивности, когда контрол (точнее, их группу в листбоксе) надо было перекрашивать исходя из текущих активностей мышки юзера, там начали лезть неиллюзорные уши "Win32 mouse capture API". Но в большинстве ситуаций да, надо отдать должное команде WPF — они запилили весьма достойный фреймворк.
Re: Как изменить цвет кнопки?
От: c-smile Канада http://terrainformatica.com
Дата: 05.11.19 19:34
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Все действительно настолько плохо, или я где-то чего не догоняю?


Кнопки рисуются uxtheme.dll как составное изображение. Нет там background color как такового.

Если нужно выделить как-то выбор то идеологически правильно использовать BS_DEFPUSHBUTTON тип:

https://docs.microsoft.com/en-us/windows/win32/controls/button-types-and-styles#button-types-and-styles

Ну или BS_OWNERDRAW если уж совсем припекло.
Re[2]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 05.11.19 19:39
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Если нужно выделить как-то выбор то идеологически правильно использовать BS_DEFPUSHBUTTON тип:


DEFPUSHBUTTON предназначен для выделения кнопки по умолчанию. А мне нужно просто подчеркнуть, что есть основания нажать эту кнопку (по которой откроется одно из окон системных настроек), чтобы восстановить работоспособность программы, нарушенную виндовой политикой.

CS>Ну или BS_OWNERDRAW если уж совсем припекло.


Тогда кнопка будет выпадать из стиля темы.
Re[8]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 17.11.19 13:05
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Да просто рамки или подчеркивания системного цвета должно быть достаточно.


Оказалось, что еще и рамку-то нарисовать непросто. В обработке WM_NOTIFY и соответствующем контексте можно рисовать только в пределах самой кнопки — например, занять рамкой часть тени, но это выглядит некрасиво. Если же рисовать вокруг кнопки, то это нужно делать в контексте диалогового окна, а вот когда? WM_PAINT диалогам не посылается. Если снова в обработке WM_NOTIFY, то оно посылается только при перерисовке кнопки или ее части — если аккуратно мазнуть по рамке краем другого окна, не задев области кнопки, то WM_NOTIFY не будет, а рамка испортится.

Обрабатывать WM_ERASEBKGND, заливать фон диалога и тут же рисовать в нужном месте рамку — как-то вообще коряво.

Пока получилось только с фиктивным owner-drawn элементом (Button или Static), причем непременно подложенным под кнопку (определенным раньше нее в списке ресурсов диалога), иначе фон этого псевдоэлемента перекрывает кнопку, независимо от WS_EX_TRANSPARENT.

Блин, что ж у них все так через задницу-то... Не зря меня судьба двадцать пять лет хранила от тонкостей GDI...
Re[2]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 18.11.19 11:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>В крайнем случае сабклассинг этой кнопки


В случае рамки, как оказалось, и сабклассинг не поможет — WM_PAINT и его производные вызываются только для области самой кнопки.
Re[3]: Как изменить цвет кнопки?
От: Pavel Dvorkin Россия  
Дата: 18.11.19 12:04
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>В случае рамки, как оказалось, и сабклассинг не поможет — WM_PAINT и его производные вызываются только для области самой кнопки.


WM_NCPAINT
With best regards
Pavel Dvorkin
Re[4]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 18.11.19 12:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

ЕМ>>В случае рамки, как оказалось, и сабклассинг не поможет — WM_PAINT и его производные вызываются только для области самой кнопки.


PD>WM_NCPAINT


А толку? Область вокруг стандартной кнопки не принадлежит окну, представляющему эту кнопку. То есть, рисовать нужно или по WM_ERASEBKGND для всего диалога, или подкладывать под кнопку фиктивный элемент чуть большего размера, а для стирания рамки еще и добывать текущий/стандартный фон диалога.
Re[5]: Как изменить цвет кнопки?
От: Pavel Dvorkin Россия  
Дата: 18.11.19 13:17
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>А толку? Область вокруг стандартной кнопки не принадлежит окну, представляющему эту кнопку. То есть, рисовать нужно или по WM_ERASEBKGND для всего диалога, или подкладывать под кнопку фиктивный элемент чуть большего размера, а для стирания рамки еще и добывать текущий/стандартный фон диалога.


Что-то не понял. Ты вроде кнопку хотел перерисовать. При чем тут область вокруг кнопки на диалоге ? Такой задачи не ставилось. А рамка кнопки все же принадлежит ей, а не диалогу.
With best regards
Pavel Dvorkin
Re[3]: Как изменить цвет кнопки?
От: qaz77  
Дата: 18.11.19 14:42
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>В случае рамки, как оказалось, и сабклассинг не поможет — WM_PAINT и его производные вызываются только для области самой кнопки.

Способ 1.
Если не трогать саму кнопку, то можно динамически создавать статик нужного размера и цвета.
Через SetWindowPos ставить ему Z-ордер "под кнопкой" и еще добавить стиль clip siblings, чтобы кнопка не мерцала при перерисовке.

Способ 2.
Как предложили уже — использовать не клиентскую область окна.
У стандартной кнопки не клиентская область не используется (в отличие от edit, например).
Чтобы ее задействовать нужно реализовать обработчик WM_NCCALCSIZE, где указать желаемый размер не клиентской области.
В обработчике WM_NCPAINT — залить нужным цветом.
Если состояние кнопки меняется и нужно перерисовать не клиентскую область, то нужно звать SetWindowPos с флагом SWP_FRAMECHANGED.

Способ 2а.
Упрощенный вариант 2. Вместо обработки WM_NCCALCSIZE ставим кнопке стиль WS_EX_CLIENTEDGE и получаем готовую рамку толщиной 2 пикселя.
Заменяем обработчик WM_NCPAINT — вместо рисования "утопленной" рамки, заливаем нужным цветом.
Вместо WS_EX_CLIENTEDGE можно поставить WS_EX_STATICEDGE, тогда будет рамка толщиной 1 пиксель.
С масштабом экрана (non 96 DPI) толщина таких рамок не дружит, если чо.

P.S. Для первого способа в шаблоне диалога надо предусматривать место под статик, а для второго — увеличивать размер самой кнопки,
чтобы текст помещался в клиентскую область.
Re[6]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 18.11.19 22:09
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ты вроде кнопку хотел перерисовать.


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

PD>При чем тут область вокруг кнопки на диалоге ?


А где еще рисовать рамку?

PD>А рамка кнопки все же принадлежит ей, а не диалогу.


У стандартных кнопок нет рамок — только их собственные границы.
Re[4]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 18.11.19 22:17
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Если не трогать саму кнопку, то можно динамически создавать статик нужного размера и цвета.


Это самый простой, я именно так и сделал. По WM_DRAWITEM просто рисую рамку через FrameRgn, красным — для выделения, фоновым — для стирания.
Re[5]: Как изменить цвет кнопки?
От: qaz77  
Дата: 19.11.19 08:23
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:
По WM_DRAWITEM просто рисую рамку через FrameRgn, красным — для выделения, фоновым — для стирания.

При использовании визуальных тем нет единого фонового цвета.
Диалог или property page может использовать (и в реальности использует) текстуру/градиент.
Чтобы правильно эмулировать отсутствие рамки надо вызывать DrawThemeParentBackground.
Re[6]: Как изменить цвет кнопки?
От: qaz77  
Дата: 19.11.19 08:34
Оценка:
Или еще проще.
Когда рамка не нужна — удаляем статик (или просто не создаем).
Статик всегда рисует одним цветом (красным, например).

Т.е. функция установки рамки для кнопки:
— берет четырехугольник кнопки
— расширяет его во все стороны
— создает статик и устанавливает z-order "под кнопкой"

Для статика можно еще сделать таймер, чтобы оттенки красного
циклически менялись для большей заметности.

Необходимость подсветки кнопки, насколько я понял, выясняется в рантайм,
а не при рисовании формы в редакторе ресурсов.
Соответственно, в обработчике WM_INITDIALOG при необходимости
зовем функцию создания статика для нужной кнопки.
Отредактировано 19.11.2019 8:36 qaz77 . Предыдущая версия .
Re[6]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 19.11.19 16:18
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Диалог или property page может использовать (и в реальности использует) текстуру/градиент.

Q>Чтобы правильно эмулировать отсутствие рамки надо вызывать DrawThemeParentBackground.

Фон может определяться более, чем одной кистью? Я в прошлом варианте применил FrameRgn как раз для того, чтобы рисовать кистью, а кисть добывал из WNDCLASS::hbrBackground.

Q>Или еще проще. Когда рамка не нужна — удаляем статик (или просто не создаем).


Или делаем невидимым. Сегодня переделал на этот вариант, чтобы отвязаться от необходимости работы с фоном.

Q>Необходимость подсветки кнопки, насколько я понял, выясняется в рантайм


Более того — она может возникнуть в любой момент, так что условия приходится анализировать в WM_TIMER.
Re[2]: Как изменить цвет кнопки?
От: CEMb  
Дата: 20.11.19 02:41
Оценка:
Здравствуйте, CaptainFlint, Вы писали:

CF>Исходя из этого, есть у меня сильное подозрение, что стандартные контролы, вид которых управляется темой, нельзя просто так взять и поменять. Конечно, остаётся ещё вероятность, что существуют какие-то хитрые вызовы; или что тогда их не было, а теперь появились (всё-таки много времени прошло)…


Всё сложнее. Авторы(Windows), когда делали кнопку, сильно оптимизировали. Т.е. нельзя просто перехватить WM_PAINT у кнопки и рисовать туда. Смена состояний, например, тоже вызывает внутреннюю функцию отрисовки, но делает это мимо WM_PAINT.
Если всё-таки сильно хочется, я могу выложить примерный каркас кода для обработчика кнопки, который работает. Мы сабклассили кнопку в промышленных масштабах Правда, у нас была полностью своя отрисовка, но нет особых проблем с тем, чтобы просто поменять тон, сделать grayscale, потом colorize над HDC, тоже могу дать код. Но, моё мнение: это слишком. Я там ниже плюсанул за рамку, сам тоже так делал, когда надо было выделить кнопку. Там есть один момент, под XP+Luna отрисовка кнопки немного захватывает область вокруг себя, так что рамку надо рисовать хотя бы в 2-3 пикселя.
Re[2]: Как изменить цвет кнопки?
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 20.11.19 07:02
Оценка:
Здравствуйте, okon, Вы писали:

ЕМ>>Все действительно настолько плохо, или я где-то чего не догоняю?

O>Потом народ спрашивает а чем WPF лучше.

Чем голое WinAPI? Скинь ссылку, кто так спрашивает, не верю.
Чаще всего WPF просто не появляется в контексте замены WinAPI, потому что придётся менять сразу всё. А WinAPI подразумевает, что приложение компактное и быстрое.
Re[7]: Как изменить цвет кнопки?
От: qaz77  
Дата: 20.11.19 09:42
Оценка: -1
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Фон может определяться более, чем одной кистью? Я в прошлом варианте применил FrameRgn как раз для того, чтобы рисовать кистью, а кисть добывал из WNDCLASS::hbrBackground.

Все эти hbrBackground, WM_CTLCOLOR и т.п. были актуальны до Win XP.
Тем не менее, они продолжают поддерживаться и могут в каких-то ограниченных сценариях использоваться, когда все прямоугольное и одного цвета.

Для полноценного использования стандартных контролов Windows из commctl32 надо использовать ее 6-ую версию, т.е. добавить соотв. инфу в манифест приложения.
Для их полноценной кастомизации — использовать uxtheme.dll API.
Re[3]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 20.11.19 13:16
Оценка:
Здравствуйте, CEMb, Вы писали:

CEM>под XP+Luna отрисовка кнопки немного захватывает область вокруг себя, так что рамку надо рисовать хотя бы в 2-3 пикселя.


Я как раз три и сделал.
Re[3]: Как изменить цвет кнопки?
От: VVV Россия  
Дата: 21.11.19 19:26
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>DEFPUSHBUTTON предназначен для выделения кнопки по умолчанию. А мне нужно просто подчеркнуть, что есть основания нажать эту кнопку (по которой откроется одно из окон системных настроек), чтобы восстановить работоспособность программы, нарушенную виндовой политикой.


CS>>Ну или BS_OWNERDRAW если уж совсем припекло.


ЕМ>Тогда кнопка будет выпадать из стиля темы.


1. Показать баллон у этой кнопки при необходимости с поясняющим текстом.
2. Рядом с кнопкой поставить статик с картинкой (стрелка, восклицательный знак, радиация, SOS, ...) и при необходимости показывать.
Re[4]: Как изменить цвет кнопки?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 21.11.19 22:16
Оценка:
Здравствуйте, VVV, Вы писали:

VVV>1. Показать баллон у этой кнопки при необходимости с поясняющим текстом.


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