10

私は、Delphi 2010 で Aero を使用して見栄えの良いデザインを見つけようとしています。明らかな用途の 1 つは、ガラス フレームを拡張して、画面の下部に [OK]/[キャンセル] ボタンを含めることです。ただし、Delphi 2010 ではこれが正しく表示されないことに気付きました。各ボタンの周りに白い境界線があります。

この画像は問題を示しています。上の 3 つのボタンはアプリからのもので、下の 2 つのボタンは Paint.NET の [レイヤー プロパティ] ダイアログから取得したものです。

Delphi コントロールの周りの白い枠

DoubleBuffered のさまざまな組み合わせと、最初にコントロールを他のコントロールに配置するいくつかの組み合わせを試しましたが、問題は残ります。何か案は?

4

4 に答える 4

5

誰もクリーンな解決策を持っていない場合は、回避策として を使用TBitBtnDoubleBuffered = falseます。

于 2010-07-26T14:28:26.707 に答える
2

Roy Klever による Glass Button を確認するか、以下にリンクされている QC エントリに記載されているように、DoubleBuffered=false を指定した TBitBtn を確認してください。この質問。

これは、Windows Aero DWM のバグ、または Windows コモン コントロールのバグ、または VCL クラス階層がコモン コントロール ウィンドウ メッセージとガラスにペイントする際のペイントを処理する方法のバグです。つまり、Windows の共通コントロールがガラスに適切に描画されないか、DWM 構成 (Aero) が壊れています。びっくりサプライズ。

標準の VCL ボタン コンポーネントは、Windows コモン コントロールの Window クラス BUTTON を使用します。

TSpeedButton は Windows コモン コントロールを使用しないため、この問題は発生しないことに注意してください。ただし、フォーカスも受け付けません。

Embarcadero はこの問題を認識しているようです。これはQC # 75246であり、実際にはコモン コントロール ライブラリのバグであり、修正されないため、TBitBtn を使用するよう提案されているため、クローズされています。ボタンは単独ではありません。これは、パネルやその他の一般的なコントロールを含む QC レポートのグループの一部です。

ただし、キーボードフォーカスを受け入れ、このグリッチを描画しない商用の TcxButton (開発者エクスプレスコンポーネントの一部) があります。Win32 コモン コントロール ボタン コントロールを使用するすべてのコードには、この問題があるようです。低レベルの Win32 API ハッカーがこれに対する回避策を見つける可能性があります。私はそれを調べています。この回答は、私が理解した場合に更新されます。

1 つの興味深い詳細: TcxButton には、cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard} という 3 つの描画スタイルがあります。lfOffice11 を選択すると、このグリッチが再び追加されます。これは、Vista/Win7 のエアロのガラス機能と、共通のコントロール/xptheme ボタン描画コードとの間の奇妙な相互作用のように見えます。

唯一の回避策は、完全にアプリで描画されたボタン コントロールを使用し、Windows 共通コントロール ボタン、または XP テーマ エンジンに依存してボタンを描画するボタン コントロールを Aero ガラス ペインで使用しないことです。

編集: 7 月 28 日、Embarcadero の誰かが上記の QC エントリを閉じましたが、これは間違いでした。これが実際にコモン コントロール dll の Windows バグであるかどうかを明確にするためだけに、私は彼らにそれを再度開くように促しています。

試してみたい場合は、StdCtrls から TButton および TCustomButton クラスの VCL ソース コードのコピーを作成します。ここで行ったように、CNCtlColorBtn を変更して、PerformEraseBackground、DrawParentBackground、または継承の 3 つのいずれかを強制的に発生させます。そして結果を見る。興味深いもの。

procedure TCustomGlassButton.CNCtlColorBtn(var Message: TWMCtlColorBtn);
begin
  PerformEraseBackground(Self, Message.ChildDC);
  Message.Result := GetStockObject(NULL_BRUSH);
(*
  with ThemeServices do
    if ThemesEnabled then
    begin
      if (Parent <> nil) and Parent.DoubleBuffered then
        PerformEraseBackground(Self, Message.ChildDC)
      else
        DrawParentBackground(Handle, Message.ChildDC, nil, False);
      { Return an empty brush to prevent Windows from overpainting we just have created. }
      Message.Result := GetStockObject(NULL_BRUSH);
    end
    else

      inherited;
  *)
end;

Vista 時代の Glass/DWM/aero API に関する興味深い資料 (C++ 開発者ブログ)

于 2010-07-27T20:23:38.167 に答える
1

ここでは、Glass で TButton を正しく表示するコードをいくつか提供します。残念ながら、それはフォームを「クリックスロー」にするので、良い考えではないと思います。しかし、フォームの「クリックスロー」を修正する方法を見つけることができるかもしれません。

于 2010-07-30T08:36:53.133 に答える
0

win32 api を使用できる場合は、NM_CUSTOMDRAW 通知 (ownerdraw ではない) を利用してみてください (はい、ボタンはラジオやチェックボックスを含めて送信します。ただし、WM_CTLCOLORSTATIC を使用するのが最善です)。これは C++ で行う方法ですが、考え方は同じです。私の考えは良いですが、ボタンがカスタムドローされ、それらの上にマウスを置いて再び表示する必要がある場合、ウィンドウからプログラムを実行するたびにボタンが一度消えることがあります。そういうわけで、私はまだこれに対するコメントを探しています。ワンフォームアプリケーションで消えるボタンを再現するのは非常に難しいことに注意してください。ただし、すべてのプロジェクトでこの動作が発生しています。

case WM_NOTIFY:
  switch(((LPNMHDR)lParam)->code){
  case NM_CUSTOMDRAW:
    {
       NMHDR *nmh=(NMHDR*)lParam;
       //these 6000 through 6004 are button identifiers assigned by me
       if(nmh->idFrom >= 6000 && nmh->idFrom <= 6004){
         switch(((LPNMCUSTOMDRAW)nmh)->dwDrawStage){
           case CDDS_PREERASE:
             //BackgroundBrush is a HBRUSH used also as window background
             FillRect(((LPNMCUSTOMDRAW)nmh)->hdc, &((LPNMCUSTOMDRAW)nmh)->rc, BackgroundBrush);
             break;
         }
    }
    break;
}
break;
于 2011-07-03T09:05:10.060 に答える