WS_EX_LAYERED-Stil für untergeordnete Windows in Windows 8

  • Tutorial
Unter Windows können Sie nicht nur ein durchsichtiges Steuerelement erstellen, sondern müssen entweder alle Steuerelemente selbst zeichnen (Qt, FMX) oder DrawThemeParentBackground verwenden , was unweigerlich zu Bremsen führt.
Die Regionen hier werden nicht helfen. Sie unterstützen keine teilweise Transparenz.
Es wäre praktisch, Fenster mit dem WS_EX_LAYERED- Stil ("Layered" -Fenster, die die Alphatransparenz einzelner Pixel unterstützen) zu verwenden, aber Windows unterstützt diesen Stil nur für Fenster der obersten Ebene. So war es vor Windows 8, in dem es nach weniger als einem halben Jahrhundert endlich möglich war, diesen Stil Kinderfenstern zuzuweisen.

Was gibt es? Das erste, was mir einfällt, ist, dass die Grafikkarte die Zusammensetzung der Fenster berücksichtigt, was zu einer Leistungssteigerung führt.

Unter cat wird ein wenig über diese Funktion von Windows 8 geforscht .

Alle Codebeispiele werden in Delphi vorgestellt , ein ähnlicher Ansatz kann jedoch auch in anderen Sprachen verwendet werden.

Versuchen wir, eine solche durchsichtige Schaltfläche zu erstellen: Der

Einfachheit halber werden wir sie nicht mit GDI + zeichnen , sondern einfach die vorgefertigte 32-Bit-BitMap verwenden.

Erstellen wir eine neue Vcl- Anwendung, fügen dem Formular ein TImage hinzu und laden dort unsere 32-Bit-BitMap hoch.
Wir fügen dem Formular auch eine Schaltfläche hinzu. Wenn Sie darauf klicken, werden 100 "Schaltflächen" erstellt. Wir werden

unsere Layered- Komponente zu einem Nachfolger von TButton machen , indem wir einen Konstruktor hinzufügen, der eine 32-Bit-Bitmap mit dem Bild unserer Schaltfläche akzeptiert und die CreateWnd- Prozedur überschreibt , die für die Erstellung des Fensters verantwortlich ist:
  TWin8Control = class(TButton)
  private
    WinBitMap: TBitMap;
  public
    procedure CreateWnd; override;
    constructor Create(AOWner: TComponent; BitMap: TBitMap);
  end;
// ...
constructor TWin8Control.Create(AOWner: TComponent; BitMap: TBitMap);
begin
  inherited Create(AOwner);
  WinBitMap := BitMap;
end;
procedure TWin8Control.CreateWnd;
var
  bf: TBlendFunction;
  BitmapSize: TSize;
  BitmapPos:Tpoint;
begin
  inherited;
  if Assigned(WinBitMap) then
  begin
    // убедимся в том что у нас Premultiplied битмап
    WinBitMap.AlphaFormat := afPremultiplied;
    bf.BlendOp := AC_SRC_OVER;
    bf.BlendFlags := 1;
    bf.AlphaFormat := AC_SRC_ALPHA;
    bf.SourceConstantAlpha := 255;
    // получаем размеры BitMap
    BitmapSize.cx := WinBitMap.Width;
    BitmapSize.cy := WinBitMap.Height;
    BitmapPos.X := 0;
    BitmapPos.Y := 0;
    // добавляем "слоистый" стиль окна
    SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
    UpdateLayeredWindow(
      Handle,
      0,
      nil,
      @BitmapSize,
      WinBitMap.Canvas.Handle,
      @BitmapPos,
      0,
      @bf,
      ULW_ALPHA
    );
  end;
end;


Lassen Sie uns nun 100 untergeordnete Fenster mit Ebenen im Handler unserer Schaltfläche erstellen :
procedure TfrmMain.btnAdd100Click(Sender: TObject);
var
  i: Integer;
  Win8Control: TWin8Control;
begin
  for i := 0 to 99 do
  begin
    Win8Control := TWin8Control.Create(Self, Image.Picture.Bitmap);
    Win8Control.Parent := Self;
    Win8Control.Top := Random(400);
    Win8Control.Left := Random(400);
  end;
end;


Starten Sie die Anwendung und klicken Sie auf die Schaltfläche:

... und beachten Sie, dass der WS_EX_LAYERED- Stil aus irgendeinem Grund nicht für die untergeordneten Fenster gilt .

Wie sich herausstellte, funktioniert diese Funktion nur, wenn Sie die Windows 8-Unterstützung im Anwendungsmanifest angeben (was in msdn nicht explizit angegeben ist ):


Fügen Sie diese Zeilen zum Manifest hinzu, verbinden Sie es mit dem Projekt, führen Sie es erneut aus und klicken Sie auf die Schaltfläche:

Hurra, es funktioniert!

Allerdings ist nicht alles so rosig ...
Das erste, was auffällt, ist, dass solche Fenster sehr langsam erstellt werden, etwa zehnmal langsamer als gewöhnlich.
Zweitens ist es das , was war sogar elementare Schleppen Fenster zu verlangsamen, nicht die Größe ändern zu erwähnen, wobei bemerkenswerte Artefakte (sorry für das Foto auf dem Bildschirm, aber aufgrund der spezifischen Arbeit gesehen werden kann von Windows solche Fenster in den Screenshots Artefakte ist nicht sichtbar):

Dies ist ein Muss, seien Sie nicht faul und spielen Sie mit einem Beispiel.

Wenn Sie die Taste mehrmals drücken, friert nicht nur die Anwendung ein, sondern auch ... das gesamte System, was beim Erstellen von normalen Fenstern nicht der Fall ist.
Dies führt zu dem Schluss, dass leider eine so große Chance nicht qualitativ umgesetzt wurde und deren Einsatz in realen Anwendungen nicht möglich ist .

Und noch ein Experiment, wie man das gesamte System ausschaltet (speichern Sie einfach zuerst alle Ihre Daten).
Fügen Sie dem Formular eine weitere Schaltfläche hinzu, und erstellen Sie im Handler eine Endlosschleife:
procedure TfrmMain.LoopClick(Sender: TObject);
var
  Win8Control: TWin8Control;
begin
  while True do
  begin
    Win8Control := TWin8Control.Create(Self, Image.Picture.Bitmap);
    Win8Control.Parent := Self;
    Win8Control.Top := Random(400);
    Win8Control.Left := Random(400);
  end;
end;

Nach einem Klick auf Windows - nur durch die Schaffung besetzt werden Layered Fenster und nichts mehr wird nicht einmal reagieren auf die Strg + Alt + Del :)

Projekt auf GitHub: https://github.com/errorcalc/LayeredTest

Jetzt auch beliebt: