我正在尝试创建一个带有扁平边框的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,看起来非常糟糕。
答案 0 :(得分:5)
实际上,您必须在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;