【问题标题】:TScrollBox with customized flat border color and width?具有自定义平面边框颜色和宽度的 TScrollBox?
【发布时间】:2012-11-13 22:06:23
【问题描述】:

我正在尝试创建一个带有扁平边框的 TScrollBox,而不是丑陋的“Ctl3D”。

这是我尝试过的,但边框不可见:

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 一起“中断”,看起来真的很糟糕。

【问题讨论】:

  • 我其实很喜欢经典的 Windows 3D 风格。让我想起了更简单的日子。
  • 我认为你必须模仿TWinControl.WMNCPaint

标签: delphi delphi-5


【解决方案1】:

确实,您必须在WM_NCPAINT 消息处理程序中绘制边框。使用GetWindowDC 获得的设备上下文是相对于控件的,而使用GetWindowRect 获得的矩形是相对于屏幕的。

得到正确的矩形,例如SetRect(R, 0, 0, Width, Height);

随后,将BorderWidth 设置为您的愿望,ClientRect 应相应地遵循。如果不是,则通过覆盖GetClientRect 进行补偿。这是few examples

在您自己的代码之前调用继承的消息处理程序链,以便正确绘制滚动条(在需要时)。总而言之,它应该是这样的:

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;

【讨论】:

  • +1!!! MapWindowPoints form TWinControl.WMNCPaint 给了我使用错误坐标的想法。 SetRect(R, 0, 0, Width, Height) 成功了。 ps:我应该先inhrited,还是应该像你一样返回Message.Result := 0;
  • 在前面调用继承的消息处理程序,因为这是绘制滚动条的地方。处理后返回零。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-25
  • 2019-02-24
  • 2015-08-23
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
相关资源
最近更新 更多