Indeed, you have to draw the border in a WM_NCPAINT
message handler. The device context you obtain with GetWindowDC
is relative to the control, while the rectangle you obtain with GetWindowRect
is relative to the screen.
The correct rectangle is gotten e.g. by SetRect(R, 0, 0, Width, Height);
Subsequently, set BorderWidth
as your wish and ClientRect
should follow accordingly. If not, then compensate by overriding GetClientRect
. Here are a few examples.
Call the inherited chain of message handlers before your own code, so the scroll bars (when needed) will be drawn correctly. All in all, it should look like:
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;