Windows 8の子ウィンドウのWS_EX_LAYEREDスタイル

Windowsでは、半透明のコントロールを作成することはできません;すべてのコントロール(Qt、FMX)を自分で描画するか、必然的にブレーキにつながるDrawThemeParentBackgroundを使用する必要があります。

ここの地域は役に立ちません。 部分的な透明度はサポートされていません。

WS_EX_LAYEREDスタイルのウィンドウ(個々のピクセルのアルファ透明度をサポートする「レイヤード」ウィンドウ)を使用すると便利ですが、 Windowsはトップレベルウィンドウに対してのみこのスタイルをサポートします。 そのため Windows 8が登場する前、半世紀も経たないうちについにこのスタイルを子ウィンドウに割り当てることが可能になりました。



それは何を与えますか? 最初に頭に浮かぶのは、ビデオカードがウィンドウの構成を処理することです。これにより、パフォーマンスが向上します。



catの下で、 Windows 8のこの機能について少し調査します



すべてのコード例はDelphiで提示されますが、他の言語でも同様のアプローチを使用できます。



このような半透明のボタンを作成してみましょう。



簡単にするために、 GDI +を使用して描画するのではなく、既製の32ビットBitMapを使用します。



新しいVclアプリケーションを作成し、 TImageをフォームに追加して、32ビットBitMapをアップロードします。

また、フォームにボタンを追加します。クリックすると、100個の「ボタン」が作成されます。



LayeredコンポーネントをTButtonの後継とします 。このコンポーネントでは、ボタンの画像を含む32ビットBitMapを受け入れ、ウィンドウの作成を担当するCreateWndプロシージャをオーバーライドするコンストラクタを追加します。

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;
      
      







ボタンのハンドラーに100個の子レイヤードウィンドウを作成しましょう。

 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;
      
      







アプリケーションを起動し、ボタンをクリックします。



...そして、何らかの理由でWS_EX_LAYEREDスタイルが子ウィンドウに適用されなかったことに注意してください。



判明したように、全体的なポイントは、アプリケーションマニフェストでWindows 8サポートを指定するまで( msdnで明示的に示されていない)、この機能が機能しないことです。

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> </application> </compatibility>
      
      







これらの行をマニフェストに追加し、プロジェクトに接続し、再度実行して、ボタンをクリックします。



やれやれ!



しかし、すべてがバラ色ではありません...

最初に目を引くのは、そのようなウィンドウの作成が非常に遅く、通常よりも約10倍遅いことです。

2つ目は、ウィンドウの基本的なドラッグアンドドロップでさえ、サイズ変更は言うまでもなく遅くなり始めたということです。この場合、素晴らしいアーティファクトを見ることができます(スクリーンから写真をおaびしますが、そのようなウィンドウでのWindowsの特定の操作により、アーティファクトはスクリーンショットに表示されません):



これは必見です。怠けてはならず、例を試してください。



ボタンを数回押すと、アプリケーションがフリーズするだけでなく、システム全体もフリーズします。これは通常のウィンドウを作成するときに発生しません。

これは、 残念ながら、そのような素晴らしい機会は高品質で実装されておらず、実際のアプリケーションでの使用は不可能であるという結論につながります



もう1つの実験、システム全体を中断する方法について(最初にすべてのデータを保存するだけです)。

フォームにボタンをもう1つ追加し、ハンドラーでこのような無限ループを作成します。

 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;
      
      





ボタンをクリックすると、 Windowsレイヤードウィンドウの作成でビジー状態になり、それ以上何もせず、 Ctrl + Alt + Delにも応答しません:)



GitHubプロジェクト: https : //github.com/errorcalc/LayeredTest



All Articles