Поддержка Delphi для Aero Glass и свойство DoubleBuffered - что происходит и как мы их используем?

Меня смущает, что Delphi 2009/2010 поддерживает функции Aero Theme Glass в Windows, и что именно означает DoubleBuffered, и что он имеет отношение к Aero glass. Я обнаружил, что DoubleBuffered является не только свойством в VCL, но и в .net WinForms. Сначала я задавался вопросом, установил ли он какой-нибудь бит стиля окна, используемый библиотекой общих элементов управления, или как. Почему он используется и когда его следует использовать?

[Обновление: я должен заявить, что я знаю, что такое "двойная буферизация", как общая методика уменьшения мерцания, что меня удивило: почему у него НИЧЕГО связано с элементами рендеринга на панели Aero Glass в Windows Vista/Windows 7, и, в частности, почему КНОПКА всех вещей должна иметь значение двойной буферизации для работы над стеклом?. Пост в блоге, указанный ниже, кажется наиболее информативным.]

В частности, меня смущает свойство DoubleBuffered, и я хочу знать, почему оно существует и каковы его отношения между опорой стекла и свойством двойной буферизации в форме и элементе управления. Когда вы читаете такие статьи на C++, как эта, вы видите, что там нет упоминаний о двойной буферизации.

[Обновление 2: следующее содержало некоторые фактические ошибки и было исправлено:]

Я обнаружил, что некоторые разработчики на C++ говорят о том, как они могут вызывать SetLayeredWindowAttributes, чтобы избежать сбоя "черный цвет становится стеклянным", который вызывает компоновка DWM/Aero при его включении в классическом приложении Win32 [однако ссылка на блог ниже говорит мне, что это больше не работает в Windows 7, и фактически ненадолго работал в Vista, пока Microsoft не заблокировала его]. [Начните НЕПРАВИЛЬНУЮ идею] Разве мы не должны использовать какой-то другой цвет, например, ярко-пурпурный, и превратить его в цвет прозрачности стекла? [Конец НЕПРАВИЛЬНАЯ идея]

Каковы правила, когда DoubleBuffered должен быть установлен и не установлен, и почему DoubleBuffered был добавлен в VCL в первую очередь? Когда это вызовет проблемы при установке? (Похоже, что удаленный рабочий стол - это один случай, но разве это единственный случай?), И когда он не установлен, мы отключаем отрисовку текста кнопки, скорее всего потому, что кажется, что Delphi не меняет значение по умолчанию, "рендеринг черного цвета как стекла" "в Aero DWM.

Мне кажется, что рендеринг Aero Glass в основном делается странным или трудным для понимания способом [самой Windows, а не Delphi, которая просто оборачивает эту функциональность], и что много внутреннего исходного кода VCL в 2009/2010 в классы в StdCtrls должны выполнять много сложной логики, чтобы правильно отображать вещи в Aero Glass, и все же у него все еще много проблем, и мне кажется, что это сделано неправильно, и что это может быть связано с этим связанным вопросом и проблемой qc. [Обновление 3: Многие сбои рендеринга на стекле, в VCL, делают рендеринг неправильно в общих элементах управления, которые, похоже, Microsoft не заботится об исправлении. Короче говоря, исправления кода Delphi VCL не могут исправить тот факт, что древняя библиотека общих элементов управления Windows и современная [но изворотливая] функция композитинга Aero Glass не очень любят друг друга и не особенно хорошо работают вместе. Спасибо Microsoft за создание такой высококачественной технологии и ее распространение в мире.]

И если это еще не было достаточно весело; Почему у нас есть ParentDoubleBuffered?

[Обновление от 30 июля. Этот вопрос интересен для меня, потому что я думаю, что он показывает, что работа над Windows API для решения этой проблемы, когда у вас есть большой VCL-фреймворк, является сложной и трудной проблемой.]

4 ответа

Решение

О DoubleBuffer

У.NET может быть один, и он может иметь то же имя и ту же цель, что и у Delphi, но Delphi реализует DoubleBuffer с нуля, и я предполагаю, что.NET делает то же самое. Для реализации этого не используются биты стиля окна.

DoubleBuffer и Glass Aero

Довольно просто: не устанавливайте DoubleBuffer для элементов управления, расположенных на стекле. Чтобы DoubleBuffering работал, нужно уметь инициализировать "Buffer" - но чем его инициализировать для Glass? DoubleBuffering не требуется для стандартных элементов управления Windows (включая TButton). Для новых элементов управления, которым требуются как прозрачные поверхности, так и поведение, подобное двойному буферу, можно использовать API слоистых окон.

Получение управления для работы на стекле

Шаг 1:

TForm1 = class(TForm)
...
protected
  procedure CreateWindowHandle(const Params: TCreateParams); override;
...
end;

procedure TForm15.CreateWindowHandle(const Params: TCreateParams);
begin
  inherited;
  SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
  SetLayeredWindowAttributes(Handle, RGB(60, 60, 60), 0, LWA_COLORKEY);
end;

Шаг 2, это должен быть обработчик OnPaint вашей формы:

procedure TForm15.FormPaint(Sender: TObject);
var rClientRect:TRect;
begin
  if GlassFrame.Enabled then
  begin
    rClientRect := ClientRect;

    Canvas.Brush.Color := RGB(60, 60, 60);
    Canvas.Brush.Style := bsSolid;
    Canvas.FillRect(rClientRect);

    if not GlassFrame.SheetOfGlass then
    begin
      rClientRect.Top := rClientRect.Top + GlassFrame.Top;
      rClientRect.Left := rClientRect.Left + GlassFrame.Left;
      rClientRect.Right := rClientRect.Right - GlassFrame.Right;
      rClientRect.Bottom := rClientRect.Bottom - GlassFrame.Bottom;
      Canvas.Brush.Color := clBtnFace;
      Canvas.FillRect(rClientRect);
    end;
  end;
end;

Шаг 3: Установите GlassFrame.Enabled = True; Установите все остальные свойства стекла, добавьте элементы управления в форму, где бы они вам ни понравились. Может быть на стекле или где-нибудь еще. Убедитесь, что элементы управления не имеют "DoubleBuffered = True". Вот и все, наслаждайтесь. Я тестировал с TButton, TCkBox и TEdit.

... РЕДАКТИРОВАТЬ...

К сожалению, при использовании этого метода "стекло" рассматривается как 100% прозрачная поверхность, и это не так - выглядит как стекло, но не ведет себя как стекло. Проблема со 100% -ной прозрачностью заключается в том, что если вы щелкнете по этой прозрачной области, ваш щелчок перейдет к окну позади вашего окна. Какой ужас.

На момент написания этой статьи я почти уверен, что нет API, который бы мог изменить цвет клавиши BLACK по умолчанию для оригинального стекла (Google находит бесчисленные посты в блогах и на форумах о том, как вам нужно использовать пользовательский рисунок для элементов управления, расположенных на стекле, и нет функция, чтобы изменить это в списке функций DWM на MSDN). Без изменения цвета по умолчанию ЧЕРНЫЙ большинство элементов управления не могут отображаться должным образом, потому что они пишут текст, используя clWindowText, и это ЧЕРНЫЙ. Один из предложенных трюков, найденных на нескольких форумах, заключается в изменении цвета прозрачности с помощью API SetLayeredWindowAttributes. И это работает! Как только это сделано, черный текст на элементах управления показывает бросок, но, к сожалению, стекло больше не стекло, стекло выглядит как стекло, но ведет себя как 100% прозрачность. Это в значительной степени лишает законной силы это решение и показывает двойной стандарт на стороне Microsoft: оригинальный ЧЕРНЫЙ не ведет себя как 100% прозрачность, но если мы изменим его на что-то лучшее, он будет вести себя как 100% прозрачность.

На мой взгляд, распространенное мнение об использовании пользовательских элементов управления на Glass неверно. Это единственное, что может работать, но это неправильно, потому что мы должны использовать элементы управления, которые являются согласованными на всей платформе: предложение пользовательских элементов управления открывает двери для непоследовательных, похожих на winamp приложений, где каждый пользователь заново создает колесо для устраивать это художественные идеи. Даже если разработчику удается точно воссоздать любой заданный элемент управления Windows и заставить его работать на стекле, "исправление" является только временным и его необходимо заново создать для следующей версии окон. Не говоря уже о том, что, вероятно, должно быть несколько вариантов для существующих версий Windows.

Другое решение состоит в том, чтобы использовать Многослойные окна с UpdateLayeredWindow. Но это боль по ооочень многим причинам.

Это тупик для меня. Но я задам вопрос "любимый" флаг, если что-то получится лучше, я бы хотел об этом узнать.

Ваш вопрос вызвал сообщение в блоге CR на Delphi Haven...

Глядя на переполнение стека, я только что заметил довольно подробный вопрос (на самом деле, набор вопросов) об стекле Aero.

DoubleBuffered - это стандартная графическая техника, используемая для уменьшения мерцания. По сути, вы рисуете новую версию своей формы на втором холсте, а затем меняете ее на текущую. Этот обмен происходит быстро, даже если процесс рисования идет медленно. Там нет прямой связи между этим и Aero - вы можете использовать один или оба независимо. Двойная буферизация в Delphi была очень долгое время, но теперь у нас намного больше процессорных циклов на обновление экрана, это менее необходимо. Возможно, поэтому вы не слышали об этом.

Двойная буферизация - это то, что вы должны использовать только реактивно - если вы видите мерцание, когда ваше приложение перерисовывает экран, включите его и посмотрите, что произойдет. В этом случае, хотя вашим первым выходом будет DisableUpdates/EnableUpdates (см. Справку по Delphi) и Windows API LockWindowUpdate (то же самое).

ParentDoubleBuffered, как и большинство свойств Parent..., сообщает вам, будет ли эта форма использовать свойство DoubleBuffered от своего родителя. Это позволяет вам установить свойство один раз в главной форме вашего приложения и влиять на каждую создаваемую вами форму. Или нет, если вы установите для этого свойства значение false.

Это типичная ситуация, когда у вас есть обратно совместимый код - там есть вещи, которые редко используются сегодня, но все еще работают (и иногда все еще необходимы), хотя большинству людей никогда не нужно беспокоиться о них. Для большинства людей они просто есть, и вы можете их игнорировать, но для некоторых из нас они крайне необходимы (у нас есть пара действительно очень сложных форм, которые мы иногда перерисовываем в сложных схемах, чтобы остановить мерцание)

Хорошо, я постараюсь немного исправить ситуацию.

Прежде всего, двойная буферизация является очень стандартной техникой, когда дело доходит до экранного рендеринга. Я использую это все время, например, в моем компоненте текстового редактора. Представьте, что текст должен быть перерисован. Проще говоря, я сначала очищаю весь клиент прямо, более или менее FillRect(ClientRect)Затем я рисую линии, от первого до последнего видимого, каждый от первого символа до последнего видимого. Но это будет выглядеть очень уродливо для конечного пользователя, имеющего несколько миллисекунд или около того с очищенным дисплеем, между двумя состояниями почти одного и того же текстового содержимого.

Решение состоит в том, чтобы сделать все рисование за пределами экранного растрового изображения и просто нарисовать закадровое растровое изображение на экране, когда оно будет завершено. Затем, если предыдущий и новый кадры идентичны, с дисплеем ничего не произойдет, в отличие от случая без двойной буферизации, где на экране будет отображаться пустой белый прямоугольник в течение нескольких миллисекунд, т.е. будет мерцать Я всегда использую двойную буферизацию для всех своих визуальных элементов управления, и это значительно улучшает их качество и восприятие. В современной системе с гигабайтами памяти (RAM) увеличение использования памяти ни в коем случае не является проблемой. И почти во всех случаях замена буферов происходит более чем достаточно быстро (хотя для копирования достаточно нескольких пикселей).

Часто вы можете наблюдать отсутствие двойной буферизации при изменении размеров окон. Иногда они просто мерцают как ч ** л. Также может быть интересно отметить, что такие технологии, как OpenGL, по своей сути имеют двойную буферизацию (по крайней мере, в большинстве случаев).

Таким образом, двойная буферизация не имеет ничего общего с листами стекла. На самом деле большинство потомков Дельфи TWinControl имеет DoubleBuffered а также ParentDoubleBuffered свойства ( ссылка).

ParentDoubleBuffered собственность соотносится с DoubleBuffered так же, как ParentColor относится к Color, ParentShowHint в ShowHint, ParentFont в Fontи т. д. Он просто решает, должен ли элемент управления наследовать значение параметра из своего родительского окна.

Теперь к вопросу о стекле. Ну, это общеизвестно, что вообще неудобно добавлять элементы управления на лист стекла (или стеклянную раму), по крайней мере, в приложении VCL. Кто-то должен написать длинную статью в блоге, обсуждая, как сделать это правильно...

Другие вопросы по тегам