Подтвердить что ты не робот

Поддержка 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, и я хочу знать, почему он существует и какова его связь между поддержкой стекла и двойным буферизацией в форме и элементе управления. Когда вы читаете статьи на С++, подобные этому, вы видите, что нет упоминания о двойной буферизации.

[Update2: Ниже приведены некоторые фактические ошибки и были изменены:]

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

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

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

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

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

4b9b3361

Ответ 1

О DoubleBuffer

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

DoubleBuffer и Glass Aero

Довольно просто: не устанавливайте DoubleBuffer для элементов управления, которые сидят на стекле. Для DoubleBuffering для работы нужно иметь возможность инициализировать "Буфер" - но что инициализировать его для 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.

... EDIT...

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

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

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

Другое решение - использовать слоистые окна с UpdateLayeredWindow. Но это PAIN для sooo многих причин.

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

Ответ 2

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

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

Ответ 3

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

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

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

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

Ответ 4

Хорошо, я попытаюсь немного разобраться.

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

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

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

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

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

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