11

スクロールバーを持つカスタム コントロールのクライアント領域の周りに色付きの境界線を描画しようとしています。このためBorderWidthに、正の整数に設定してWM_NCPAINTメッセージに応答します。これは VCL と Win32 を組み合わせたように聞こえますが、このBorderWidthプロパティによってメッセージが適切に処理されるだけWM_NCCALCSIZEです。

次のコードはSSCCEです。

unit Unit6;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TSample = class(TCustomControl)
  protected
    procedure Paint; override;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
  published
    property BorderWidth;
  end;

  TForm6 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

{ TSample }

procedure TSample.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := Params.Style or WS_VSCROLL or WS_HSCROLL;
end;

procedure TSample.Paint;
begin
  inherited;
  Canvas.Brush.Color := clWhite;
  Canvas.FillRect(ClientRect);
end;
procedure TSample.WMNCPaint(var Message: TWMNCPaint);
var
  dc: HDC;
  R: TRect;
begin
  DefaultHandler(Message);
  dc := GetWindowDC(Handle);
  try
    Brush.Color := clYellow;
    GetWindowRect(Handle, R);
    with R do
      R := Rect(0, 0, Right - Left, Bottom - Top);
    ExcludeClipRect(dc, BorderWidth, BorderWidth,
      R.Right - BorderWidth, R.Bottom - BorderWidth);
    FillRect(dc, R, Brush.Handle);
  finally
    ReleaseDC(Handle, dc);
  end;
end;

procedure TForm6.FormCreate(Sender: TObject);
begin
  with TSample.Create(self) do
  begin
    Parent := Self;
    SetBounds(10, 10, 500, 100);
    BorderWidth := 10;
  end;
end;

end.

結果は次のようになります。

スクリーンショット

これは、右下の正方形を除いて完璧に見えます。その領域は、何かを行うことで簡単に修正できます。この領域は、私が説明しようとしている実際の問題とは何の関係もないため、意図的にペイントしません。ですから、その四角は無視してください。

これで、フォームの右側の境界線をドラッグしてフォームのサイズを変更できるようになりました。サンプル コントロール ウィンドウの垂直スクロール バーが非表示になるように、最初にサイズを小さくします。次に、フォームをゆっくりと拡大して、サンプル コントロールが再び完全に見えるようにします。次に、次のようになります。

スクリーンショット

ここで問題を見ることができます:BorderSize垂直スクロールバーの ~ 左端のピクセルは、オペレーティング システムによって描画されていないように見えます。

いくつかの観察:

  1. inheritedmere の代わりにfull を使用するDefaltHandler(Message)と、問題がさらに悪化します。この場合、フォームが一時的に画面外に移動された後、およびコントロールを遮るフォームの縮小拡大操作の後、黄色の領域はスクロールバーを完全に遮ります。

スクリーンショット

  1. メッセージに一致する応答を実装するWM_NCHITTESTと、コントロールの動作が改善されますが、スクロールバーの描画の問題は解決されません。

  2. スクロールバーのあるコントロールの非クライアント領域内にカスタム境界線を描画する方法を知っていますか? ; この Q への回答はすべて、上記の問題に悩まされています。

Delphi 2009 と Windows 7 Home Premium、64 ビット、Aero 対応を使用しています。

4

0 に答える 0