4

In another question near this, i get the answer to get modal forms to keep inside a workarea inside the mainform. The way i can accomplish that (thanks to David again) is catching WMSizing, WMMoving, WMGetMaxMinInfo, and for my porpuose WMShowwindow messages. I am not closed to messages handling and i think it is likely the way i manage messages the cause that i am not getting the result i needed.

All the forms in my application are modal. But you can open a lot in the same execution thread. (Mainform, form1, form2, form3... formN). All form(1..N) move inside a workarea in my mainform. Maximize, restore, size, move... all between limits of that workarea.

But i cannot manage how to minimize the whole application from then click on active modal form minimize button, and from click on taskbar button. The application will be used in XP and W7... i am developing in DelphiXE.

The project can be downloaded from here (Project files - Mainform, panel, button, SecondaryForm, unit, nothing more), just to see that i try all the suggestions i found before asking here.

This is the source code of the original unit that keeps the modal forms inside the workarea.

unit uFormularios;

interface

uses Classes, SysUtils, Windows, Messages, Forms, DBGrids, StdCtrls, Menus, Graphics, ComCtrls, Math;

type
  TForm_en_ventana = class(TForm)
  private
    inicializada: boolean;
    bCentrada     : boolean;
    bMaximizada   : boolean;
    ancho_original: integer;
    alto_original : integer;
    procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
    procedure WMSizing(var msg: TMessage); message WM_SIZING;
    procedure WMMoving(Var msg: TMessage); message WM_MOVING;
    procedure WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
  public
    constructor Create(AOwner: TComponent); override;
    property centrada: boolean read bCentrada write bCentrada;
    property maximizada: boolean read bMaximizada write bMaximizada;
  end;

procedure MaximizarFormulario(var F; MaximaAltura: integer = 0; MaximoAncho: integer = 0; Centrado: boolean = TRUE);
procedure InicializarVentanaTrabajo(const izq, der, arr, aba: integer);

var
  ESPACIO_DE_TRABAJO, VENTANA_DE_TRABAJO: TRect;

implementation

constructor TForm_en_ventana.Create(AOwner: TComponent);
begin
  inherited;
  centrada     := TRUE;
  maximizada   := false;
  inicializada := false;
end;

Procedure TForm_en_ventana.WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo);
begin
  inherited;
  with msg.MinMaxInfo^.ptMaxPosition do
    begin
      x := VENTANA_DE_TRABAJO.Left;
      y := VENTANA_DE_TRABAJO.Top;
    end;
  with msg.MinMaxInfo^.ptMaxSize do
    begin
      x := VENTANA_DE_TRABAJO.Right - VENTANA_DE_TRABAJO.Left;
      y := VENTANA_DE_TRABAJO.Bottom - VENTANA_DE_TRABAJO.Top;
    end;
  with msg.MinMaxInfo^.ptMaxTrackSize do
    begin
      x := VENTANA_DE_TRABAJO.Right - VENTANA_DE_TRABAJO.Left;
      y := VENTANA_DE_TRABAJO.Bottom - VENTANA_DE_TRABAJO.Top;
    end;
  with msg.MinMaxInfo^.ptMinTrackSize do
    begin
      x := ancho_original;
      y := alto_original;
    end;
end;

procedure TForm_en_ventana.WMSizing(var msg: TMessage);
var
  R: PRect;
begin
  R        := PRect(msg.LParam);
  R.Left   := Max(R.Left, VENTANA_DE_TRABAJO.Left);
  R.Right  := Min(R.Right, VENTANA_DE_TRABAJO.Right);
  R.Top    := Max(R.Top, VENTANA_DE_TRABAJO.Top);
  R.Bottom := Min(R.Bottom, VENTANA_DE_TRABAJO.Bottom);
  Caption  := 'Ancho: ' + inttostr(ancho_original) + ' - Alto: ' + inttostr(alto_original);
end;

procedure TForm_en_ventana.WMMoving(var msg: TMessage);
var
  R     : PRect;
  dx, dy: integer;
begin
  R  := PRect(msg.LParam);
  dx := 0;
  dy := 0;
  if R.Left < VENTANA_DE_TRABAJO.Left then
    dx := VENTANA_DE_TRABAJO.Left - R.Left;
  if R.Right > VENTANA_DE_TRABAJO.Right then
    dx := VENTANA_DE_TRABAJO.Right - R.Right;
  if R.Top < VENTANA_DE_TRABAJO.Top then
    dy := VENTANA_DE_TRABAJO.Top - R.Top;
  if R.Bottom > VENTANA_DE_TRABAJO.Bottom then
    dy := VENTANA_DE_TRABAJO.Bottom - R.Bottom;
  OffsetRect(R^, dx, dy);
end;

procedure TForm_en_ventana.WMShowWindow(var Message: TWMShowWindow);
begin
  if inicializada then
    Exit;
  inicializada          := TRUE;
  ancho_original        := Width;
  alto_original         := Height;
  Constraints.MinHeight := Height;
  Constraints.MinWidth  := Width;
  if centrada then
    begin
      Left := (((VENTANA_DE_TRABAJO.Right - VENTANA_DE_TRABAJO.Left) - Width) div 2) + VENTANA_DE_TRABAJO.Left;
      Top  := (((VENTANA_DE_TRABAJO.Bottom - VENTANA_DE_TRABAJO.Top) - Height) div 2) + VENTANA_DE_TRABAJO.Top;
    end;
  if maximizada then
    SendMessage(Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
end;

procedure InicializarVentanaTrabajo(const izq, der, arr, aba: integer);
begin
  VENTANA_DE_TRABAJO.Left   := izq;
  VENTANA_DE_TRABAJO.Right  := der;
  VENTANA_DE_TRABAJO.Top    := arr;
  VENTANA_DE_TRABAJO.Bottom := aba;
end;

procedure MaximizarFormulario(var F; MaximaAltura: integer = 0; MaximoAncho: integer = 0; Centrado: boolean = TRUE);
begin
  LockWindowUpdate(TForm(F).Handle);
  TForm(F).Left := ESPACIO_DE_TRABAJO.Left;
  if MaximoAncho = 0 then
    TForm(F).Width := ESPACIO_DE_TRABAJO.Right
  else
    begin
      if ESPACIO_DE_TRABAJO.Right < MaximoAncho then
        TForm(F).Width := ESPACIO_DE_TRABAJO.Right
      else
        TForm(F).Width := MaximoAncho;
    end;
  TForm(F).Top := ESPACIO_DE_TRABAJO.Top;
  if MaximaAltura = 0 then
    TForm(F).Height := ESPACIO_DE_TRABAJO.Bottom
  else
    begin
      if ESPACIO_DE_TRABAJO.Bottom < MaximaAltura then
        TForm(F).Height := ESPACIO_DE_TRABAJO.Bottom
      else
        TForm(F).Height := MaximaAltura;
    end;
  if ((MaximoAncho <> 0) or (MaximaAltura <> 0)) and (Centrado) then
    begin
      TForm(F).Left := (ESPACIO_DE_TRABAJO.Right - TForm(F).Width) div 2;
      TForm(F).Top  := (ESPACIO_DE_TRABAJO.Bottom - TForm(F).Height) div 2;
    end;
  LockWindowUpdate(0);
end;

initialization

SystemParametersInfo(SPI_GETWORKAREA, 0, @ESPACIO_DE_TRABAJO, 0);
VENTANA_DE_TRABAJO := ESPACIO_DE_TRABAJO;

end.

Thanks to anybody who can help me!

Speaker
  • 189
  • 2
  • 10
  • I think this is inevitable if you have a modal form. The main form is disabled and can't be minimized by UI actions. I must ask what sort of UI you are trying to make here. Your problems all seem to stem from the fact that you are fighting against the system. You aren't meant to make windows behave like this. – David Heffernan Jan 27 '12 at 11:05
  • I need that whole application minimize (application and all open forms, dispite they are active or not) when user try to minimize the active form. I try as you say, to catch WMSIZE message to capture SIZE_MINIMIZING. – Speaker Jan 27 '12 at 14:19
  • Perhaps, manage a global list that keep track of open forms (main, form1, form2, form3, form_active). And hide, show... catching wmshowwindow message (on sc_minimize anf sc_restore)? can this be a "good" way to reach my needs? – Speaker Jan 27 '12 at 14:20
  • What is the motivation for your UI choice? Why don't you do something standard? – David Heffernan Jan 27 '12 at 14:40
  • @DavidHeffernan "Why don't you do something standard?" - What would Steve Jobs or Edison think about your words... jeje. – Speaker Jan 27 '12 at 18:12
  • I have a big application that is working and growing for 12 years. The time has come to change database, and UI. There are modules that are all related, but has different final porpouses. – Speaker Jan 27 '12 at 18:12
  • So i think in making a separated application for each module. As most of the form will be more likely to be tall than wide, then i think on putting the main menu of each module (as a outlook bar or something) to the left. Inside that module all forms will be modal (as they are now). The forms will float over the work area, leaving the menú always visible. If i minimize that module, clicking on windows taskbar button, or minimizing a modal form, or minimizing the main form, the whole module (application) must be minimized. – Speaker Jan 27 '12 at 18:13
  • My users, like this behaviour (or hate that they couldn't minimize any form in actual version, and hate the fact that they couldn't do two unrelated task over the same database: enter data, bill/charge, etc). I can by now, accomplish all what i need, but i cannot minimize the whole module (application). That is this question for... – Speaker Jan 27 '12 at 18:14
  • Steve Jobs is an interesting example. His policies enforced uniformity of ui on apples platforms. – David Heffernan Jan 27 '12 at 18:24
  • Jeje... yes... but he created a new one first... i am just joking. – Speaker Jan 27 '12 at 18:40
  • He just stole the best ideas from parc – David Heffernan Jan 27 '12 at 18:41
  • Ok... delete Steve Jobs... bad sample... keep Edison... – Speaker Jan 27 '12 at 18:46
  • What I don't understand is why minimizing a child form would lead to the main form being minimized. If the user wants to minimize the main form then they should minimize the main form. – David Heffernan Jan 27 '12 at 18:57
  • But they couldn't. All forms are modal. They have to close all forms and then main form to minimize the module, i want they to remain where they are, with the same data they have. – Speaker Jan 27 '12 at 19:09
  • close it from taskbar is the standard – David Heffernan Jan 27 '12 at 19:22
  • I can do that if none modal form is open... dispite that, take in account that i have a lot of users in different customers, and none of them is friend of software, PCs, or nothing that takes in technology. – Speaker Jan 27 '12 at 19:28
  • What is more... most of them don't know that "show desktop" button even exists! – Speaker Jan 27 '12 at 19:34
  • @DavidHeffernan Have you any other idea? – Speaker Jan 30 '12 at 22:55

3 Answers3

2

Simply catch the Minimize and Restore messages in the Modal Form and do this ...

procedure TTheModalForm.WMSysCommand(var Msg: TWMSysCommand);
begin
  if (fsModal in FormState) or not Application.MainForm.Visible then
  begin
    case Msg.CmdType of
      SC_MINIMIZE:
      begin
        ShowWindow(Application.Handle, SW_SHOWMINNOACTIVE);
      end;

      SC_RESTORE:
      begin
        ShowWindow(Application.Handle, SW_SHOWNORMAL);
        inherited;
      end;

    else
      inherited;
    end;
  end
  else
    inherited;
end;
JFGravel
  • 21
  • 2
2

I needed this too, and I tried the other answer but it's not working. Fortunately I managed to make it work, like this:

procedure TFoodsForm.WMSysCommand(var Msg: TWMSysCommand);
begin
 if (fsModal in FormState) and (Msg.CmdType and $FFF0 = SC_MINIMIZE)
  then Application.MainForm.WindowState:= wsMinimized
  else inherited;
end;
Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55
1

Thank you, JFGravel! This worked great for me, but I could never get the SC_RESTORE to get caught here, but restore works fine without, so here's my short version:

  if (Message.CmdType and $FFF0) = SC_MINIMIZE then
    ShowWindow(Application.Handle, SW_SHOWMINNOACTIVE)
  else
    inherited;
Kevin Berry
  • 151
  • 5