Кнопки Delphi показывают белую рамку на стекле Aero
Я пытался найти красивый дизайн, используя Aero в Delphi 2010. Одно из очевидных применений, которое можно увидеть, - это когда стеклянная рамка расширяется, чтобы включать кнопки OK/Cancel в нижней части экрана. Однако я заметил, что в Delphi 2010 это выглядит не совсем правильно - вокруг каждой кнопки есть белая рамка.
Это изображение показывает проблему: верхние 3 кнопки были из моего приложения, а две нижние были взяты из диалога свойств слоя в Paint.NET.
Белые границы вокруг элементов управления Delphi http://i30.tinypic.com/1zzqfm0.png
Я пробовал различные комбинации DoubleBuffered и несколько комбинаций размещения элементов управления на других элементах управления в первую очередь, но проблема остается. Есть идеи?
4 ответа
Если ни у кого нет чистого решения, в качестве обходного пути TBitBtn
с DoubleBuffered = false
,
Похоже, что единственный обходной путь - это рисование владельцем или стороннее управление кнопкой. Проверьте Glass Button Роя Клевер или, как указано в записи QC, связанной ниже, TBitBtn с DoubleBuffered=false, что было принято выше для ответа на этот вопрос.
Это ошибка в Windows Aero DWM или ошибка общих элементов управления Windows или ошибка, связанная с тем, что иерархия классов VCL обрабатывает сообщения общего окна управления и рисование при рисовании на стекле. Короче говоря, общие элементы управления окна не рисуют себя должным образом на стекле, или, скорее, композиция DWM (Aero) не работает. Сюрприз Сюрприз.
Стандартный компонент кнопки VCL использует КНОПКУ Класса Окна из Windows Common Controls.
Обратите внимание, что TSpeedButton не использует общий элемент управления Windows и не имеет этой проблемы. однако, это также не принимает фокус.
Похоже, что Embarcadero знает об этой проблеме, это QC# 75246, которая закрыта, потому что это действительно ошибка в библиотеке общих элементов управления, как не будет исправлено, с предложением использовать TBitBtn. Кнопки не одиноки, это часть группы отчетов о контроле качества, включая панели и другие общие элементы управления.
Однако у меня есть коммерческий TcxButton (часть компонентов разработчика Express), который принимает фокус клавиатуры и не рисует этот глюк. Любой код, который использует элемент управления общей кнопки управления Win32, кажется, имеет эту проблему. Возможно, что хакер низкого уровня Win32 API найдет обходной путь для этого. Я смотрю на это. Этот ответ будет обновлен, если я это выясню.
Одна интересная деталь: TcxButton имеет три стиля рисования: cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard}. Выбор lfOffice11 добавляет этот глюк обратно. Это выглядит как странное взаимодействие между функцией "стекло" в aero в Vista/Win7 и общим кодом рисования кнопки control/xptheme.
Может случиться так, что единственный обходной путь - это использовать полностью нарисованный приложением элемент управления кнопками и не использовать кнопки общих элементов управления Windows или любой элемент управления кнопками, использующий механизм тем XP для рисования кнопок, на панели Aero Glass.
Изменить: 28 июля, кто-то на Embarcadero закрыл вышеуказанный вход QC, что было ошибкой. Я призываю их снова открыть его, хотя бы для того, чтобы уточнить, действительно ли это ошибка Windows в dll общих элементов управления.
Если вы хотите поиграть, сделайте копию исходного кода VCL для классов TButton и TCustomButton из StdCtrls, как я уже здесь сделал, измените CNCtlColorBtn, чтобы заставить одну из трех вещей произойти - PerformEraseBackground, DrawParentBackground или унаследованный, и посмотреть результаты. Интересные вещи.
procedure TCustomGlassButton.CNCtlColorBtn(var Message: TWMCtlColorBtn);
begin
PerformEraseBackground(Self, Message.ChildDC);
Message.Result := GetStockObject(NULL_BRUSH);
(*
with ThemeServices do
if ThemesEnabled then
begin
if (Parent <> nil) and Parent.DoubleBuffered then
PerformEraseBackground(Self, Message.ChildDC)
else
DrawParentBackground(Handle, Message.ChildDC, nil, False);
{ Return an empty brush to prevent Windows from overpainting we just have created. }
Message.Result := GetStockObject(NULL_BRUSH);
end
else
inherited;
*)
end;
Интересное чтение по API эпохи Vista / Glass/DWM/ Aero (блог разработчиков на C++)
Здесь я предоставляю код, который заставляет TButton выглядеть прямо на Glass. К сожалению, это делает форму "click-throw", поэтому я не думаю, что это хорошая идея. Но, возможно, вы можете найти способ исправить "щелчок-бросок" формы.
Если вы можете использовать Win32 API, попробуйте использовать уведомление NM_CUSTOMDRAW (не владелец draw), как я (да, кнопки отправляют его, включая радио и флажки. Для них лучше использовать WM_CTLCOLORSTATIC.) Вот как это делается в C++, но идея та же. Хотя моя идея хороша, так получилось, что мои кнопки отключаются один раз за выполнение программы из окна, когда они настраиваются, и мне нужно навести на них указатель мыши, чтобы они снова были видны. Вот почему я все еще ищу комментарии для этого. Обратите внимание, что действительно трудно воспроизвести исчезающие кнопки в приложениях с одной формой. Я испытываю такое поведение в каждом проекте.
case WM_NOTIFY:
switch(((LPNMHDR)lParam)->code){
case NM_CUSTOMDRAW:
{
NMHDR *nmh=(NMHDR*)lParam;
//these 6000 through 6004 are button identifiers assigned by me
if(nmh->idFrom >= 6000 && nmh->idFrom <= 6004){
switch(((LPNMCUSTOMDRAW)nmh)->dwDrawStage){
case CDDS_PREERASE:
//BackgroundBrush is a HBRUSH used also as window background
FillRect(((LPNMCUSTOMDRAW)nmh)->hdc, &((LPNMCUSTOMDRAW)nmh)->rc, BackgroundBrush);
break;
}
}
break;
}
break;