Obsługa Delphi dla Aero Glass i właściwości DoubleBuffered - co się dzieje i jak z nich korzystać?

Jestem zdezorientowany przez obsługę Delphi 2009/2010 dla funkcji Aero Theme Glass w Windows, i przez co, dokładnie DoubleBuffered oznacza, i co to ma wspólnego z Aero glass. Odkryłem, że DoubleBuffered jest nie tylko właściwością w VCL, ale także w . NET WinForms . Początkowo zastanawiałem się, czy ustawia jakiś bit stylu okna używany przez common controls library, czy co. Dlaczego jest stosowany i kiedy powinien być stosowany?

[Update: powinienem stwierdzić, że wiem co "podwójne buforowanie" jest, jako ogólna technika redukcji migotania, co zastanawiałem się, dlaczego ma to coś wspólnego z kontroli renderowania na szybie Aero w systemie Windows Vista / Windows 7,a w szczególności dlaczego przycisk wszystkich rzeczy musi mieć podwójne buforowanie ustawione true, aby pracować nad szkłem?. Poniższy post na blogu wydaje się najbardziej pouczający.]

W szczególności, jestem zdezorientowany przez DoubleBuffered własności, i chcę wiedzieć, dlaczego istnieje, i co jego związek między wspornikiem szklanym a dwukierunkową właściwością w formie i sterowaniu ustawione są. Kiedy czytasz Artykuły C++ takie jak ten widzisz, że nie ma wzmianki o podwójnym buforowaniu.

[Update2: poniższy tekst zawiera kilka błędów rzeczowych i został zmieniony:]

Znalazłem kilku programistów C++ mówiących o tym, jak mogą wywoływać SetLayeredWindowAttributes, aby uniknąć usterki "black becomes glass", która powoduje DWM/Aero compositing po włączeniu go w swoim klasyczna aplikacja Win32 [jednak poniższy link na blogu mówi mi, że to już nie działa w Windows 7, a właściwie tylko krótko działało w Vista, dopóki Microsoft go nie zablokował]. Nie powinniśmy użyć innego koloru, takiego jak Jasna magenta i zmienić go w kolor przezroczystości szkła? [End WRONG Idea]

Jakie są zasady, kiedy DoubleBuffered powinien być ustawiony, a nie ustawiony, i dlaczego DoubleBuffered został dodany do VCL w pierwszej kolejności? Kiedy spowoduje to problemy Po ustawieniu? (Wygląda na to, że zdalny pulpit to jeden przypadek, ale czy to jedyny przypadek?) a gdy nie jest ustawione, dostajemy usterkę renderowania tekstu przycisku, najprawdopodobniej dlatego, że wygląda na to, że Delphi nie zmienia domyślnego "render black as glass" w Aero DWM.

Wydaje mi się, że renderowanie Aero Glass odbywa się zasadniczo w dziwny lub trudny do zrozumienia sposób [przez Sam Windows, a nie przez Delphi, które tylko zawija tę funkcjonalność], i że wiele wewnętrznego kodu źródłowego VCL w 2009/2010 w klasach w StdCtrls musi zrobić wiele skomplikowanej logiki, aby renderować rzeczy poprawnie na Aero Glass, a mimo to nadal ma wiele problemów i wygląda mi na to, że zrobił to źle, i że to może być za tym {17]}związane pytanie i kwestia qc. [Update3: wiele błędów renderowania na szkle, w VCL są renderowanie wykonane źle wewnątrz wspólnych kontrolek, co wydaje się, Microsoft nie obchodzi się na naprawie. Krótko mówiąc, poprawki kodu Delphi VCL nie mogą naprawić faktu, że starożytne okna często biblioteka sterowania i nowoczesna [ale dziwaczna] funkcja kompozytowania szkła Aero nie lubią się zbytnio i nie współpracują ze sobą szczególnie dobrze. Dziękujemy Microsoftowi za zbudowanie tak wysokiej jakości technologii i uwolnienie jej na świecie.]

A jeśli jeszcze nie było wystarczająco zabawnie, to po co nam rodzice?

[aktualizacja 30 lipca: to pytanie jest dla mnie interesujące, ponieważ myślę, że pokazuje, że praca na Windows API, aby rozwiązać ten problem, gdy masz duży istniejący framework VCL, to trudny problem.]

Author: Community, 2010-07-29

4 answers

O DoubleBuffer

. Net może mieć taką samą nazwę i ten sam cel, co Delphi, ale Delphi implementuje DoubleBuffer od podstaw i zakładam, że. NET robi to samo. Nie są używane żadne bity stylu okna.

DoubleBuffer i Glass Aero

Dość proste: nie ustawiaj Doublebuffera na elementy sterujące siedzące na szkle. Aby DoubleBuffering działał, trzeba być w stanie zainicjować "bufor" - ale czym go zainicjować Dla szkła? Podwójne buforowanie nie jest wymagane dla standardowych kontrolek systemu Windows (w tym TButton). W przypadku nowych kontrolek, które wymagają zarówno przezroczystych powierzchni, jak i zachowania przypominającego doublebuffer, można użyć warstwowego interfejsu API systemu windows.]}

Uzyskanie kontroli do pracy na szkle

Krok 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;

Krok 2 , to powinien być program obsługi OnPaint twojego formularza:

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;

Krok 3 : Ustaw Szkiełko.Enabled = True; Ustaw wszystkie inne właściwości szkła, dodaj kontrolki do formularza, gdzie tylko zechcesz. Może być na szkle lub gdziekolwiek indziej. Upewnij się, że elementy sterujące nie mają "DoubleBuffered = True". To jest to, smacznego. Testowałem z TButton, TCkBox i TEdit.

... Edycja ...

Niestety przy użyciu tej metody "szkło" jest traktowane jako w 100% przezroczysta powierzchnia i nie jest-wygląda jak szkło, ale nie zachowuje się jak szkło. Problem ze 100% przezroczystością polega na tym, że kliknięcie na tym przezroczystym obszarze przechodzi do okna za oknem. Straszne.

W momencie pisania tego tekstu jestem prawie pewien, że nie ma API, które zmieniłoby domyślny kolor czarnego klucza dla oryginalnego szkła (google znajduje niezliczone posty na blogu i forum na temat tego, jak należy używać niestandardowego rysunku dla kontrolek, które siedzą na szkle i nie ma funkcji, która zmieniłaby to w lista funkcji DWM na MSDN ). Bez zmiany domyślnego koloru czarnego większość kontrolek nie może renderować poprawnie, ponieważ zapisują tekst za pomocą clWindowText i to jest czarny. Jedna z propozycji sztuczka znaleziona na kilku forach polega na zmianie koloru przezroczystości za pomocą interfejsu API SetLayeredWindowAttributes. I to działa! Gdy już to zrobisz czarny tekst na kontrolkach pokazuje rzut, ale niestety szkło nie jest już szkłem, szkło wygląda jak szkło, ale zachowuje się jak 100% przezroczystość. To praktycznie unieważnia To rozwiązanie i pokazuje podwójny standard po stronie Microsoftu: oryginalna czerń nie zachowuje się jak 100% przezroczystości, ale jeśli zmienimy ją na coś lepszego, zachowuje się jak 100% przejrzystość.

Moim zdaniem powszechne myślenie o stosowaniu niestandardowych kontrolek na szkle jest błędne. To jedyna rzecz, która może działać, ale jest błędna, ponieważ powinniśmy używać kontrolek, które są spójne na całej platformie: sugerowanie niestandardowych kontrolek otwiera drzwi do niespójnych, podobnych do Winampa aplikacji, gdzie każdy użytkownik odtwarza koło, aby pasowało do jego artystycznych pomysłów. Nawet jeśli deweloperowi uda się wiernie odtworzyć dowolną kontrolę systemu windows i sprawić, że będzie działać na szkle, "fix" jest tylko tymczasowy i musi zostać ponownie utworzony dla następnej wersji systemu windows. Nie wspominając o tym, że prawdopodobnie należy mieć wiele wariantów dla istniejących wersji systemu windows.

Innym rozwiązaniem jest użycie warstwowych okien z UpdateLayeredWindow. Ale to ból z wielu powodów.

To dla mnie ślepy zaułek. Ale zadam pytanie" ulubiona " flaga, Jeśli pojawi się coś lepszego chciałbym się o tym dowiedzieć.
 15
Author: Cosmin Prund,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-30 06:43:02

Twoje pytanie wywołało wpis na blogu CR o Delphi Haven...

Patrząc na Stack Overflow, właśnie zauważyłem dość szczegółowe pytanie (naprawdę, zestaw pytań) o Aero szkło.

 7
Author: Roddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-29 10:49:00

DoubleBuffered jest standardową techniką graficzną stosowaną w celu zmniejszenia migotania. Zasadniczo rysujesz nową wersję formularza na drugim kanwie, a następnie zamieniasz ją na bieżącą. Ta zamiana jest szybka, nawet jeśli proces rysowania jest powolny. Nie ma bezpośredniego związku między tym a Aero - możesz używać obu lub obu niezależnie. Podwójne buforowanie istnieje już bardzo długo w Delphi, ale teraz mamy dużo więcej cykli procesora na odświeżanie ekranu jest mniej konieczne. Które może dlatego o tym nie słyszałeś.

Podwójne buforowanie to coś, czego powinieneś używać tylko reaktywnie - jeśli widzisz migotanie, gdy aplikacja przemalowuje ekran, włącz go i zobacz, co się stanie. W takim przypadku, chociaż pierwszym rozwiązaniem byłoby DisableUpdates/EnableUpdates (zobacz Pomoc Delphi dla tych) i LockWindowUpdate API systemu Windows (ditto).

ParentDoubleBuffered, jak większość rodziców... właściwości, mówi, Czy ten formularz będzie używał właściwości DoubleBuffered z jego rodzic. Pozwala to ustawić właściwość raz w głównym formularzu aplikacji i mieć wpływ na każdy utworzony formularz. Lub nie, jeśli ustawisz tę właściwość na false.

Jest to typowa sytuacja, gdy masz wstecznie kompatybilny kod - są tam rzeczy, które są rzadko używane dzisiaj, ale nadal działają (i czasami są nadal potrzebne), mimo że większość ludzi nigdy nie musi się o nie martwić. Dla większości ludzi są po prostu tam i można je zignorować, ale dla niektórych z nas są desperacko potrzebne (mamy kilka bardzo, bardzo złożonych form, które przerysowujemy w okazjonalnie złożone wzory, aby zatrzymać migotanie)

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-29 06:08:32

Ok, postaram się trochę to wyprostować.

Po pierwsze, podwójne buforowanie jest bardzo standardową techniką, jeśli chodzi o renderowanie na ekranie. Używam go cały czas, na przykład w moim komponencie edytora tekstu. Wyobraź sobie, że tekst musi zostać przerysowany. Bardzo prosto mówiąc, najpierw wyczyszczę cały rect klienta, mniej więcej przez FillRect(ClientRect), a następnie narysuję linie, od pierwszego do ostatniego widocznego, każdy od pierwszego znaku do ostatniego widocznego. Ale to będzie wyglądać bardzo brzydko do końca użytkownik, mający kilka milisekund lub tak z wyczyszczonym wyświetlaczem, między dwoma stanami prawie tej samej treści tekstowej.

Rozwiązaniem jest wykonanie wszystkich rysunków na poza ekranem bitmapy i po prostu narysowanie bitmapy poza ekranem na ekranie po jej zakończeniu. Następnie, jeśli poprzednia i nowa ramka są identyczne, nic się nie stanie z wyświetlaczem, w przeciwieństwie do nie-buforowanej obudowy, gdzie ekran wyświetli pusty, biały prostokąt przez kilka milisekund, czyli ekran będzie migotał. Zawsze używam podwójnego buforowania dla wszystkich moich wizualnych kontrolek, a to naprawdę poprawia ich jakość i odczucie, znacznie. W nowoczesnym systemie z gigabajtami pamięci (RAM) zwiększone zużycie pamięci nie stanowi bynajmniej problemu. W prawie wszystkich przypadkach wymiana buforów jest wystarczająco szybka (chociaż do skopiowania jest sporo pikseli).

Często można zaobserwować brak podwójnego buforowania podczas zmiany rozmiaru okien. Czasami po prostu migoczą jako h * * l. interesujące może być również zauważenie, że technologie takie jak OpenGL są z natury podwójnie buforowane (przynajmniej w większości przypadków).

Więc podwójne buforowanie nie ma nic wspólnego z arkuszami szkła. W rzeczywistości większość dekabrystów Delphi TWinControl ma właściwości DoubleBuffered i ParentDoubleBuffered (Referencja ).

Właściwość ParentDoubleBuffered jest zrównana z DoubleBuffered w taki sam sposób jak ParentColor jest związana z Color, ParentShowHint na ShowHint, ParentFont do Font, itp. Informatyka po prostu decyduje, czy kontrolka powinna dziedziczyć wartość parametru ze swojego okna nadrzędnego.

A teraz pytanie o szkło. Cóż, powszechnie wiadomo, że ogólnie jest niewygodne dodawanie kontrolek do tafli szkła( lub szklanej ramki), przynajmniej w aplikacji VCL. Ktoś powinien napisać długi artykuł na blogu omawiający, jak to zrobić poprawnie...
 1
Author: Andreas Rejbrand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-29 12:22:04