Здравствуйте, okon, Вы писали:
O>там цвет кнопки и все остальное , в том числе лейаут контролов, менять ощутимо проще.
Что неудивительно — весь WPF построен на owner draw. Там и HWND как таковых-то и нету, кроме внешнего контейнера.
O>Необходимость в использовании сторонних компонент как правило отпадает, кастомные писать получаетя не так сложно и не дорого.
Зависит от ситуации, причём сильно. Помнится, при нетривиальной интерактивности, когда контрол (точнее, их группу в листбоксе) надо было перекрашивать исходя из текущих активностей мышки юзера, там начали лезть неиллюзорные уши "Win32 mouse capture API". Но в большинстве ситуаций да, надо отдать должное команде WPF — они запилили весьма достойный фреймворк.
Здравствуйте, c-smile, Вы писали:
CS>Если нужно выделить как-то выбор то идеологически правильно использовать BS_DEFPUSHBUTTON тип:
DEFPUSHBUTTON предназначен для выделения кнопки по умолчанию. А мне нужно просто подчеркнуть, что есть основания нажать эту кнопку (по которой откроется одно из окон системных настроек), чтобы восстановить работоспособность программы, нарушенную виндовой политикой.
CS>Ну или BS_OWNERDRAW если уж совсем припекло.
Здравствуйте, wildwind, Вы писали:
W>Да просто рамки или подчеркивания системного цвета должно быть достаточно.
Оказалось, что еще и рамку-то нарисовать непросто. В обработке WM_NOTIFY и соответствующем контексте можно рисовать только в пределах самой кнопки — например, занять рамкой часть тени, но это выглядит некрасиво. Если же рисовать вокруг кнопки, то это нужно делать в контексте диалогового окна, а вот когда? WM_PAINT диалогам не посылается. Если снова в обработке WM_NOTIFY, то оно посылается только при перерисовке кнопки или ее части — если аккуратно мазнуть по рамке краем другого окна, не задев области кнопки, то WM_NOTIFY не будет, а рамка испортится.
Обрабатывать WM_ERASEBKGND, заливать фон диалога и тут же рисовать в нужном месте рамку — как-то вообще коряво.
Пока получилось только с фиктивным owner-drawn элементом (Button или Static), причем непременно подложенным под кнопку (определенным раньше нее в списке ресурсов диалога), иначе фон этого псевдоэлемента перекрывает кнопку, независимо от WS_EX_TRANSPARENT.
Блин, что ж у них все так через задницу-то... Не зря меня судьба двадцать пять лет хранила от тонкостей GDI...
Здравствуйте, Pavel Dvorkin, Вы писали:
ЕМ>>В случае рамки, как оказалось, и сабклассинг не поможет — WM_PAINT и его производные вызываются только для области самой кнопки.
PD>WM_NCPAINT
А толку? Область вокруг стандартной кнопки не принадлежит окну, представляющему эту кнопку. То есть, рисовать нужно или по WM_ERASEBKGND для всего диалога, или подкладывать под кнопку фиктивный элемент чуть большего размера, а для стирания рамки еще и добывать текущий/стандартный фон диалога.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>А толку? Область вокруг стандартной кнопки не принадлежит окну, представляющему эту кнопку. То есть, рисовать нужно или по WM_ERASEBKGND для всего диалога, или подкладывать под кнопку фиктивный элемент чуть большего размера, а для стирания рамки еще и добывать текущий/стандартный фон диалога.
Что-то не понял. Ты вроде кнопку хотел перерисовать. При чем тут область вокруг кнопки на диалоге ? Такой задачи не ставилось. А рамка кнопки все же принадлежит ей, а не диалогу.
Здравствуйте, Евгений Музыченко, Вы писали: ЕМ>В случае рамки, как оказалось, и сабклассинг не поможет — 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. Для первого способа в шаблоне диалога надо предусматривать место под статик, а для второго — увеличивать размер самой кнопки,
чтобы текст помещался в клиентскую область.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ты вроде кнопку хотел перерисовать.
От этой идеи я уже отказался — тогда пришлось бы отслеживать, как кнопка выглядит в текущей теме, чтобы выделение не делало ее хуже видимой, или плохо читаемой. Остановился на рисовании рамки вокруг кнопки.
PD>При чем тут область вокруг кнопки на диалоге ?
А где еще рисовать рамку?
PD>А рамка кнопки все же принадлежит ей, а не диалогу.
У стандартных кнопок нет рамок — только их собственные границы.
Здравствуйте, Евгений Музыченко, Вы писали:
По WM_DRAWITEM просто рисую рамку через FrameRgn, красным — для выделения, фоновым — для стирания.
При использовании визуальных тем нет единого фонового цвета.
Диалог или property page может использовать (и в реальности использует) текстуру/градиент.
Чтобы правильно эмулировать отсутствие рамки надо вызывать DrawThemeParentBackground.
Или еще проще.
Когда рамка не нужна — удаляем статик (или просто не создаем).
Статик всегда рисует одним цветом (красным, например).
Т.е. функция установки рамки для кнопки:
— берет четырехугольник кнопки
— расширяет его во все стороны
— создает статик и устанавливает z-order "под кнопкой"
Для статика можно еще сделать таймер, чтобы оттенки красного
циклически менялись для большей заметности.
Необходимость подсветки кнопки, насколько я понял, выясняется в рантайм,
а не при рисовании формы в редакторе ресурсов.
Соответственно, в обработчике WM_INITDIALOG при необходимости
зовем функцию создания статика для нужной кнопки.
Здравствуйте, qaz77, Вы писали:
Q>Диалог или property page может использовать (и в реальности использует) текстуру/градиент. Q>Чтобы правильно эмулировать отсутствие рамки надо вызывать DrawThemeParentBackground.
Фон может определяться более, чем одной кистью? Я в прошлом варианте применил FrameRgn как раз для того, чтобы рисовать кистью, а кисть добывал из WNDCLASS::hbrBackground.
Q>Или еще проще. Когда рамка не нужна — удаляем статик (или просто не создаем).
Или делаем невидимым. Сегодня переделал на этот вариант, чтобы отвязаться от необходимости работы с фоном.
Q>Необходимость подсветки кнопки, насколько я понял, выясняется в рантайм
Более того — она может возникнуть в любой момент, так что условия приходится анализировать в WM_TIMER.
Здравствуйте, CaptainFlint, Вы писали:
CF>Исходя из этого, есть у меня сильное подозрение, что стандартные контролы, вид которых управляется темой, нельзя просто так взять и поменять. Конечно, остаётся ещё вероятность, что существуют какие-то хитрые вызовы; или что тогда их не было, а теперь появились (всё-таки много времени прошло)…
Всё сложнее. Авторы(Windows), когда делали кнопку, сильно оптимизировали. Т.е. нельзя просто перехватить WM_PAINT у кнопки и рисовать туда. Смена состояний, например, тоже вызывает внутреннюю функцию отрисовки, но делает это мимо WM_PAINT.
Если всё-таки сильно хочется, я могу выложить примерный каркас кода для обработчика кнопки, который работает. Мы сабклассили кнопку в промышленных масштабах Правда, у нас была полностью своя отрисовка, но нет особых проблем с тем, чтобы просто поменять тон, сделать grayscale, потом colorize над HDC, тоже могу дать код. Но, моё мнение: это слишком. Я там ниже плюсанул за рамку, сам тоже так делал, когда надо было выделить кнопку. Там есть один момент, под XP+Luna отрисовка кнопки немного захватывает область вокруг себя, так что рамку надо рисовать хотя бы в 2-3 пикселя.
Здравствуйте, okon, Вы писали:
ЕМ>>Все действительно настолько плохо, или я где-то чего не догоняю? O>Потом народ спрашивает а чем WPF лучше.
Чем голое WinAPI? Скинь ссылку, кто так спрашивает, не верю.
Чаще всего WPF просто не появляется в контексте замены WinAPI, потому что придётся менять сразу всё. А WinAPI подразумевает, что приложение компактное и быстрое.
Здравствуйте, Евгений Музыченко, Вы писали: ЕМ>Фон может определяться более, чем одной кистью? Я в прошлом варианте применил FrameRgn как раз для того, чтобы рисовать кистью, а кисть добывал из WNDCLASS::hbrBackground.
Все эти hbrBackground, WM_CTLCOLOR и т.п. были актуальны до Win XP.
Тем не менее, они продолжают поддерживаться и могут в каких-то ограниченных сценариях использоваться, когда все прямоугольное и одного цвета.
Для полноценного использования стандартных контролов Windows из commctl32 надо использовать ее 6-ую версию, т.е. добавить соотв. инфу в манифест приложения.
Для их полноценной кастомизации — использовать uxtheme.dll API.
Здравствуйте, CEMb, Вы писали:
CEM>под XP+Luna отрисовка кнопки немного захватывает область вокруг себя, так что рамку надо рисовать хотя бы в 2-3 пикселя.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>DEFPUSHBUTTON предназначен для выделения кнопки по умолчанию. А мне нужно просто подчеркнуть, что есть основания нажать эту кнопку (по которой откроется одно из окон системных настроек), чтобы восстановить работоспособность программы, нарушенную виндовой политикой.
CS>>Ну или BS_OWNERDRAW если уж совсем припекло.
ЕМ>Тогда кнопка будет выпадать из стиля темы.
1. Показать баллон у этой кнопки при необходимости с поясняющим текстом.
2. Рядом с кнопкой поставить статик с картинкой (стрелка, восклицательный знак, радиация, SOS, ...) и при необходимости показывать.