Re: WMSysCommand canceling move



battles wrote:
I am having to capture the WMSysCommands and it is apparently
capturing the ability to move the form by the title bar. Does anyone
know the way to get the move to work again? Thanks.

Call inherited.

procedure TForm1.WMSysCommand;
begin

if (Msg.CmdType = SC_MOVE) then <---- something like this?

Something like that. Check the documentation about wm_SysCommand to learn how to interpret the wParam parameter of that message. *Never* skip the "remarks" section.

...

if Msg.CmdType = SC_CLOSE then //close doesn't work
without this
Close;

It doesn't work because you're doing it wrong. See below.

if (Msg.CmdType = SC_MINIMIZE) or // - button (upper
right of form next to X button)
(Msg.CmdType = SC_MAXIMIZE) or // single pane button
(Msg.CmdType = SC_RESTORE) then begin // double pane button
if EncartaButton5.Caption = 'Start' then begin

You're basing your program logic on the string contents of a UI control. This will be a major pain if you ever want to release your product in multiple languages. Or if you ever change the caption of the control in the Object Inspector and forget that other pieces of code were relying on that value.

Keep a Boolean flag in your program that determines whether it's in "start" mode. Check that flag here. Also, assign a TAction to your button, and then handle the action's OnUpdate event. In the event handler, assign the action's Caption property according to the current state of the "start" flag. Assigning the action's properties will automatically assign any connected controls' properties, including the button's caption. (That's assuming that TEncartaButton's author bothered to handle actions. If not, dump that control and find one with a more competent author.)

Also, I strongly encourage you to give your controls meaningful names. Does the purpose of that control really have any relation to the fact that it is the fifth TEncartaButton that you dropped on your form in the Form Designer? I doubt it.

Mouse.CursorPos := (Point( (Screen.DesktopWidth div 2) -
25,
(Screen.DesktopHeight div 2) +
35));

What's with the magic numbers?

I suspect you're trying to "help" the user by moving the cursor to some place related to the place you expect the dialog box to appear. Is that right? Stop that. Moving the cursor around can confuse the user. There is already an OS feature that the user can choose to enable that moves the cursor to the default button when a dialog box appears.

When there are multiple monitors, are DesktopHeight and DesktopWidth really what you want to use anyway?

case MessageDlg('Monitoring suspended. Start monitoring?',
mtConfirmation, [mbYes, mbNo], 0) of
mrYes : begin
RxTrayIcon1.Icon :=
RxTrayIcon1.Icons.Icons[0];
Button5Click(nil);

I refer to my comment about meaningful names.

end;

mrNo : RxTrayIcon1.Icon :=
RxTrayIcon1.Icons.Icons[2];
end;
end;

Form1.Hide;

Really? Pressing the form's maximize button causes it to disappear?

Also, if you have two instances of the TForm1 class, pressing the caption buttons of *either* form will always cause the same *single* form to disappear. If you want to act one whichever form whose message handler is running, then omit the receiver of the method call. That causes the call to be directed to the default Self value instead.

end;

//// DefaultHandler(Msg); //take this out to stop min/max/stop
action
end;

You're commenting out the wrong call. You shouldn't be calling DefaultHandler in the first place. You should be calling inherited. DefaultHandler calls the default handler for the given message, but inherited will call the handler of the immediate ancestor. That may or may not be the same as the default handler.

Your code could be made much cleaner:

begin
case Msg.CmdType and $fff0 of
sc_Minimize, sc_Maximize, sc_Restore: begin
Msg.Result := 0;
if InStartMode then begin
if MessageDlg('Monitoring is suspended; start monitoring?',
mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin
StartMonitoring;
end else begin
DoNotStartMonitoring;
end;
Hide;
end;
end;
else
inherited;
end;
end;

procedure TForm1.StartMonitoring;
begin
RxTrayIcon1.Icon := RxTrayIcon1.Icons.Icons[0];
Button5Click(Self);
end;

procedure TForm1.DoNoStartMonitoring;
begin
RxTrayIcon1.Icon := RxTrayIcon1.Icons.Icons[2];
end;

Key differences:

Minimal reliance of the current names of UI controls.

Doesn't move the mouse cursor to a place the user didn't put it.

Allows for the possibility of the user closing the dialog without pressing either button. In that case, its modal result is mrCancel, which I assume you would want to treat the same as mrNo.

Gives names to actions performed in response to user actions. Still to do: Figure out better names for DoNoStartMonitoring and Button5Click.

Passes a useful Sender parameter to Button5Click, in case the method cares who called it. (If it doesn't care, then maybe there should be a separate no-parameter method for StartMonitoring to call instead, and then Button5Click can call that no-parameter method as well.)

Sets the result of the message, like MSDN instructs.

Masks out the lower four bits of the command, like MSDN instructs.

Defers to higher up the inheritance chain for commands this class doesn't care about, including sc_Close, sc_Move, sc_HScroll, sc_MonitorPower, sc_ScreenSave, and sc_TaskList.

--
Rob
.


Quantcast