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

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

[Update: я должен заявить что я знаю, что такое "двойная буферизация", как общий метод уменьшения мерцания, я задался вопросом, почему это имеет какое-либо отношение к элементам управления рендерингом на стеклянной панели Aero в Windows Vista/Windows 7 и, в частности, почему кнопка всех вещей должна иметь двойную буферизацию, чтобы работать над стеклом?. Сообщение в блоге, связанное ниже, кажется наиболее информативным.]

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

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

Я нашел некоторых разработчиков C++, говорящих о том, как они могут вызывать SetLayeredWindowAttributes, чтобы избежать сбоя" черный становится стеклом", который DWM / Aero compositing причины, когда вы включаете его в своем классическом приложении Win32 [однако ссылка на блог ниже говорит мне, что это больше не работает в Windows 7, и на самом деле только ненадолго работал в Vista, пока Microsoft не заблокировала его]. [Begin WRONG Idea] разве мы не должны использовать какой-то другой цвет, например ярко-пурпурный, и превратить его в цвет прозрачности стекла? [Конец неправильной идеи]

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

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

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

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

4 ответов


О DoubleBuffer

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

DoubleBuffer и Стекло Aero

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

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

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

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

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

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

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

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

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


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

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


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

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

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

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


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

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

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

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

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

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

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