4

醜い「Ctl3D」の代わりにフラットボーダーのTScrollBoxを作成しようとしています。

これが私が試したものですが、境界線は表示されません。

type
  TScrollBox = class(Forms.TScrollBox)
  private
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
  protected
  public
    constructor Create(AOwner: TComponent); override;
  end;

...

constructor TScrollBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  BorderStyle := bsNone;
  BorderWidth := 1; // This will handle the client area
end;

procedure TScrollBox.WMNCPaint(var Message: TWMNCPaint);
var
  DC: HDC;
  R: TRect;
  FrameBrush: HBRUSH;
begin
  inherited;
  DC := GetWindowDC(Handle);
  GetWindowRect(Handle, R);
  // InflateRect(R, -1, -1);
  FrameBrush := CreateSolidBrush(ColorToRGB(clRed)); // clRed is here for testing
  FrameRect(DC, R, FrameBrush);
  DeleteObject(FrameBrush);
  ReleaseDC(Handle, DC);
end;

私は何が間違っているのですか?


境界線の色と幅をカスタマイズして使用できないBevelKind = bkFlatようにしたいのですが、それに加えbkFlatてRTL BidiModeで「切れ目」があり、見た目が非常に悪いです。

4

1 に答える 1

5

実際、WM_NCPAINTメッセージ ハンドラーで境界線を描画する必要があります。取得するデバイス コンテキストGetWindowDCはコントロールに対して相対的ですが、取得する四角形GetWindowRectは画面に対して相対的です。

正しい長方形は、たとえば次のように取得されますSetRect(R, 0, 0, Width, Height);

その後、BorderWidthあなたの希望に応じて設定し、ClientRectそれに応じて従う必要があります。そうでない場合は、オーバーライドして補正しますGetClientRect。以下にいくつかの例を示します。

独自のコードの前に継承されたメッセージ ハンドラーのチェーンを呼び出して、スクロール バー (必要な場合) が正しく描画されるようにします。全体として、次のようになります。

type
  TScrollBox = class(Forms.TScrollBox)
  private
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
  protected
    procedure Resize; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

...    

constructor TScrollBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  BorderWidth := 1;
end;

procedure TScrollBox.Resize;
begin
  Perform(WM_NCPAINT, 0, 0);
  inherited Resize;
end;

procedure TScrollBox.WMNCPaint(var Message: TWMNCPaint);
var
  DC: HDC;
  B: HBRUSH;
  R: TRect;
begin
  inherited;
  if BorderWidth > 0 then
  begin
    DC := GetWindowDC(Handle);
    B := CreateSolidBrush(ColorToRGB(clRed));
    try
      SetRect(R, 0, 0, Width, Height);
      FrameRect(DC, R, B);
    finally
      DeleteObject(B);
      ReleaseDC(Handle, DC);
    end;
  end;
  Message.Result := 0;
end;
于 2012-11-26T13:57:19.007 に答える