Title: Resizable forms and size grip - Part 3
Question: How to implement the size grip beavior without additional components
Answer:
After some digging around I found a simpler way to handle resing without using an additional component. The solution was so simple that I wonder why I didn't think out before.
To find where the mouse pointer is placed over a form (and change the cursor shape accordingly) Windows uses the WM_NCHITTEST message. Normally this message is handled by the default window procedure and returns a value that identifies the region under the pointer. Intercepting this message and altering the result will force the OS to believe the pointer is in a different region than the real one. (For a complete list of the return values check the MSDN Library documentation)
You can add a message handler to your form in this way:
TMyForm = class(TForm)
...
private
procedure WMNCHitTest(var Msg: TWMNChittest); message WM_NChittest;
...
end;
procedure TMyForm.WMNCHitTest(var Msg: TWMNChittest);
var
rectBounds: TRect;
begin
inherited;
rectBounds := Self.BoundsRect;
with rectBounds do
begin
Left := Right - GetSystemMetrics(SM_CXVSCROLL);
Top := Bottom - GetSystemMetrics(SM_CYVSCROLL);
end;
if(PtInRect(rectBounds, Point(Msg.XPos, Msg.YPos))) then
Msg.Result := HTBOTTOMRIGHT;
end;
The last line of the procedure does the real work by reporting a value indicating the bottom-left corner; this changes the cursor shape to crSizeNWSE and let the OS think that you are resizing the window if you drag from that point.
A comment to my first article of this series (thanks to Kevin Gallagher) pointed out that the grip area will not be any color than gray.
In effect the API is used internally by the OS to draw the interface elements therefore the colors are the ones of the current color scheme, but using a simple trick is possible to mimic the API behavior with different color.
To achieve this result you must use the Canvas.TextOut method after changing the font to 'Marlett'. This is a TrueType graphic font and the characters are glyphs for the various graphical interface components and their respective shadows; you can find check boxes, radio buttons, crosses, arrows and, of course, size grips! In particular the characters 'o' and 'p' are the glyphs of the size grip.
If you change the color of font prior to draw the text you can obtain a result similar to the one you get with the API but customized with colors of your choice. If you need larger glyphs you can simply change the size of the font.
This is the code I used. Remark the use of Brush.Style property:
procedure TMyForm.FormPaint(Sender: TObject);
var
rectBounds: TRect;
begin
rectBounds := Self.ClientRect;
with rectBounds do
begin
Left := Right - GetSystemMetrics(SM_CXVSCROLL);
Top := Bottom - GetSystemMetrics(SM_CYVSCROLL);
end;
with Self.Canvas do
begin
Brush.Style := bsClear;
Font.Name := 'Marlett';
Font.Size := 8;
Font.Color := clGray;
TextOut(rectBounds.left, rectBounds.top, 'o');
Font.Color := clWhite;
TextOut(rectBounds.left, rectBounds.top, 'p');
end;
end;
Enjoy!