Author: Peter Below
What's the best windows message to check if the Form's position is beyond the
desktop area, when the user is moving it? How can I prevent the form/ mouse from
moving when that happens?
Answer:
Solve 1:
You need a message that is send to the form before it moves and allows you to
modfify the position it is about to move to before it actually does move. WM_MOVING
or WM_WINDOWPOSCHANGING fit that bill. I would use the second, WM_MOVING will not
be send if the user has switched off the "drag full window" option.
Limit a form to the screens workarea:
1 { Private declarations }
2
3 procedure WMWINDOWPOSCHANGING(var msg: TWMWINDOWPOSCHANGING);
4 message WM_WINDOWPOSCHANGING;
5
6 procedure TForm1.WMWINDOWPOSCHANGING(var msg: TWMWINDOWPOSCHANGING);
7 var
8 r: TRect;
9 begin
10 if ((SWP_NOMOVE or SWP_NOSIZE) and msg.WindowPos^.flags) < > (SWP_NOMOVE
11 or SWP_NOSIZE) then
12 begin
13 {Window is moved or sized, get usable screen area}
14 SystemParametersInfo(SPI_GETWORKAREA, 0, @r, 0);
15 {Check if operation would move part of the window out of this area.
16 If so correct position and, if required, size, to keep window fully inside
17 the workarea. Note that simply adding the SWM_NOMOVE and SWP_NOSIZE flags
18 to the flags field does not work as intended if full dragging of windows is
19 disabled. In this case the window would snap back to the start position instead
20 of stopping at the edge of the workarea, and you could still move the
21 drag rectangle outside that area. }
22 with msg.WindowPos^ do
23 begin
24 if x < r.left then
25 x := r.left;
26 if y < r.top then
27 y := r.top;
28 if (x + cx) > r.right then
29 begin
30 x := r.right - cx;
31 if x < r.left then
32 begin
33 cx := cx - (r.left - x);
34 x := r.Left;
35 end;
36 end;
37 if (y + cy) > r.bottom then
38 begin
39 y := r.bottom - cy;
40 if y < r.top then
41 begin
42 cy := cy - (r.top - y);
43 y := r.top;
44 end;
45 end;
46 end;
47 end;
48 inherited;
49 end;
Delphi 4.03 does not recognize TWMMOVING, because there is no message record type
declared for it for some reason. That is easily fixed, however:
50 type
51 TWmMoving = record
52 Msg: Cardinal;
53 fwSide: Cardinal;
54 lpRect: PRect;
55 Result: Integer;
56 end;
Solve 2:
You can get this behaviour by handing the WM_MOVING message in the form. The
message is send to the form before it actually moves, so you can modify the
rectangle with the new form position before you pass the message on to the
inherited handler.
For some reason messages.pas declares no message record for this message.
57 type
58 TWmMoving = record
59 Msg: Cardinal;
60 fwSide: Cardinal;
61 lpRect: PRect;
62 Result: Integer;
63 end;
64
65 //Add a handler to your forms private section:
66
67 procedure WMMoving(var msg: TWMMoving); message WM_MOVING;
68
69 //Implement it as:
70
71 procedure TFormX.WMMoving(var msg: TWMMoving);
72 var
73 r: TRect;
74 begin
75 r := Screen.WorkareaRect;
76 {Compare the new form bounds in msg.lpRect^ with r and modify it if necessary}
77 if msg.lprect^.left < r.left then
78 OffsetRect(msg.lprect^, r.left - msg.lprect^.left, 0);
79 if msg.lprect^.top < r.top then
80 OffsetRect(msg.lprect^, 0, r.top - msg.lprect^.top);
81 if msg.lprect^.right > r.right then
82 OffsetRect(msg.lprect^, r.right - msg.lprect^.right, 0);
83 if msg.lprect^.bottom > r.bottom then
84 OffsetRect(msg.lprect^, 0, r.bottom - msg.lprect^.bottom);
85 inherited;
86 end;
|