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

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

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

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

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

Я обнаружил, что некоторые разработчики на 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 ]

15 голосов
/ 29 июля 2010

О DoubleBuffer

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

DoubleBuffer и Glass Aero

Довольно просто: не устанавливайте DoubleBuffer для элементов управления, расположенных на Glass.Чтобы 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 : Set GlassFrame.Enabled = True;Установите все остальные свойства стекла, добавьте элементы управления в форму, где бы они вам ни понравились.Может быть на стекле или где-нибудь еще.Убедитесь, что элементы управления не имеют «DoubleBuffered = True».Вот и все, наслаждайтесь.Я тестировал с TButton, TCkBox и TEdit.

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

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

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

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

Другое решение заключается в использовании многослойных окон с UpdateLayeredWindow.Но это БОЛЬНО по ооочень многим причинам.

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

7 голосов
/ 29 июля 2010

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

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

3 голосов
/ 29 июля 2010

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

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

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

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

1 голос
/ 29 июля 2010

ОК, я попытаюсь немного уладить ситуацию.

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

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

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

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

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

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

...