MDI Forms

Hiding MDI Child Forms

Ian Foster wrote:
>
> Can anyone help me with a way to hide MDIChild forms in an MDI application. 
Ideally I would not like to have a minimised form on the parent form as the default, 
but perhaps have an icon displayed on the parent form.

This is a feature of Win 95. It's how minimized MDI childs are supposed to look.

But, try to override WM_PAINT (or maybe you need WM_NCPAINT), check IsIconized, and draw your icon as you please.

> Currently if I just try to hide the child, I get an error that tells me  that it's an invalid method on a child form.

Try ShowWindow(MdiChild1.Handle, SW_HIDE), and see what happens.

Just 1 MDI-childwindow ?

Solution 1

From: billb@imed.omen.org (Bill Brown)

If you want to limit an MDI application to only one child window open at any given time, look at the MDIChildCount property of the MDI parent form. If it is greater than 0, don't create the new child.

If you want to allow multiple MDI children forms but no duplicates of any particular type of form (ie: only one invoice form, only one sales rep form, etc.), you will could loop through the MDI children to see if the one about to be created already exists. Again, the key to this is in the MDI parent form. Example code:


  ChildIndex := 0
  while (ChildIndex < frmMDIParent.ChildCount) and
          (frmMDIParent.MDIChildren[ChildIndex].Name <> frmNewChild.Name) do
    Inc(ChildIndex);
  if ChildIndex = frmMDIParent.ChildCount then
    {create new child here}
    begin
       Create it...
       if no exception occurred, then show it...
    end
  else
    {child form already exists so just bring it to the top}
    frmMDIParent.MDIChildren[ChildIndex].BringToFront;

Solution 2

From: "Carl Clark" <cclark@IAfrica.com>

How about,


	if Form1 <> nil then
	begin
		Form1 := TForm1.Create(Application);
		Form1.Show;
	end;

Then in Form1's OnClose:


	Action := caFree;
	Form1	 := nil;

Making MDI Forms 'more' 3D

From: kim.greve@dkb.dk (KIM GREVE)

CF>How do I make an MDI Form appear 'more' 3D (like M$ progs)?
This is from the Tips & Tricks section in The Delphi Magazine.


constructor TMainForm.Create(AOwner: TComponent);
begin
  Inherited Create(AOwner);
  SetWindowLong(ClientHandle, GWL_EXSTYLE,
  GetWindowLong(ClientHandle,
    GWL_EXSTYLE) or WS_EX_CLIENTEDGE);
  SetWindowPos(ClientHandle, 0, 0, 0, 0, 0,
    swp_DrawFrame or swp_NoMove or swp_NoSize
    or swp_NoZOrder);
end;

Tile Image in a MDI Form

Michael Ax <ax@HREF.COM>

>Hello to All!
>
>Does somebody know how to put an image in a MDI form and make
>Tile with her?
yes. that's the easy part..


procedure TForm.OnPaint(Sender: TObject);

  procedure Tile(c:TCanvas;b:TBitMap);
  var
    x,y,h,w,i,j:integer;
  begin
    with b do begin
      h:=b.height;
      w:=b.width;
      end;
    y:=0;
    with c.Cliprect do begin
      i:=bottom-top-1; //height
      j:=right-left-1; //width
      end;
    while y<i do begin
      x:=0;
      while x<j do begin
        c.draw(x,y,b);
        inc(x,w);
        end;
      inc(y,h);
      end;
  end;

begin
  if Sender is TForm then
    Tile(TForm(Sender).Canvas,fTileWith);
end;

Remove title bar in MDI child form

Solution 1

From: tnomad@digital.net

We were able to kill the title bar of an MDI child by doing the following:


type
  TForm2 = class(TForm)
	{ other stuff above }
	procedure CreateParams(var Params: TCreateParams); override;
	{ other stuff below }
  end;


procedure TForm2.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.Style := Params.Style and not WS_OVERLAPPEDWINDOW or WS_BORDER
end;

Solution 2

From: amcfarl@ndlc.occ.uky.edu (Andy McFarland)

For an MDI child form, setting the BorderStyle to bsNone does NOT remove the title bar. (This is mentioned in the help). This does it:


Procedure tMdiChildForm.CreateParams( var Params : tCreateParams ) ;
Begin
   Inherited CreateParams( Params ) ;
   Params.Style := Params.Style and (not WS_CAPTION) ;
End ;

MDI Children Menus

From: johan@lindgren.pp.se

You can set a number to indicate the position of the menu in the new menu bar that is compiled from the menues in the MDI form and the menues in the child form.
This is called the group index. It only works for the menu items visible on the menu line.

So for example if your MDI menu has:
File View About (with the group index values of 1 5 10) (It does not matter exactly what numbers you chose, they are only used for sorting.)

And your child menu has:
File Edit (and they have the values 1 and 3)

When you open a child window the child File menu item will replace the MDI form menu item. The Edit menu item will be inserted before View and About from the MDI form.

This is quite useful since you can have lesser choices on the File menu of the MDI form compared to what should be there when you have a child window open.
You do not need Save or Close on the MDI form File menu but you need Open and New for example.
But you have to enter all menu lines on the File menu in the child menu control since that will replace the File menu from the MDI parent.
You can still use the code from the parent in the child.

So if you have a procedure "parent.open1click"
You can call that from the child file menu open event.

MDIChild Close problem

From: jennings@meltech.com (Roy H. Jennings, Jr.)

Don't attempt to destroy the form from within itself. Setting action to caFree in the form close event will cause the parent window to destroy the form.

You probably need to implement the closequery event to prevent the form from closing when table1 is in edit mode or at least all the user the option of abandoning changes.

The MDIparent window should have a menu option that closes the currently active mdi child window. If not you can add one and execute the following from the click method:


 ActiveMDIChild.Close;

Try something like the following:


procedure TFrmServers.FormClose(Sender:TObject; var
Action:TCloseAction);
begin
        Action := caFree;
end;

procedure TFrmServers.FormDestroy
begin
        Table1.Close;
end;

procedure TFrmServers.FormCloseQuery
begin
        if table1.state in [dsEdit,dsInsert]  then
        begin
                // warn user that changes will be lost and
                // ask if ok to close
                if not UserSaysOk then CanClose := False;
        end;
end;

MDI Parent Background

From: Dave Horacek <dhoracek@swbell.net>

Here's some code that may prove useful. It is for either a normal form or an MDI form and tiles a bitmap or produces gradients. The only tricky part is establishing the window message handler for the ClientHandle of the window that actually manages the child forms. That's where the bitmaps and graphics actually appear in an MDI form. Just load a bitmap into imgTile at design time and you're ready to go.


unit UMain;

interface

uses
  Windows, Messages, Classes, SysUtils, Graphics, Controls, Forms,
Dialogs,
  ExtCtrls, Menus;

type
  TfrmMain = class(TForm)
    mnuMain: TMainMenu;
    mnuFile: TMenuItem;
    mnuExit: TMenuItem;
    imgTile: TImage;
    mnuOptions: TMenuItem;
    mnuBitmap: TMenuItem;
    mnuGradient: TMenuItem;
    procedure mnuExitClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure mnuBitmapClick(Sender: TObject);
    procedure mnuGradientClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormResize(Sender: TObject);
    procedure FormPaint(Sender: TObject);
  private
    { Private declarations }
    MDIDefProc:pointer;
    MDIInstance:TFarProc;
    procedure MDIWndProc(var prmMsg:TMessage);
    procedure CreateWnd;override;
    procedure ShowBitmap(prmDC:hDC);
    procedure ShowGradient(prmDC:hDC;prmRed,prmGreen,prmBlue:byte);
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;
  glbImgWidth:integer;
  glbImgHeight:integer;

implementation

{$R *.DFM}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
 glbImgHeight:=imgTile.Picture.Height;
 glbImgWidth:=imgTile.Picture.Width;
end;

procedure TfrmMain.FormResize(Sender: TObject);
begin
 FormPaint(Sender);
end;

procedure TfrmMain.MDIWndProc(var prmMsg:TMessage);
begin
 with prmMsg do
  begin
   if Msg=WM_ERASEBKGND then
    begin
     if mnuBitmap.Checked then
      ShowBitmap(wParam)
     else
      ShowGradient(wParam,255,0,0);
     Result:=1;
    end
   else
    Result:=CallWindowProc(MDIDefProc,ClientHandle,Msg,wParam,lParam);
  end;
end;

procedure TfrmMain.CreateWnd;
begin
 inherited CreateWnd;
 MDIInstance:=MakeObjectInstance(MDIWndProc); { create wrapper }
 MDIDefProc:=pointer(SetWindowLong(ClientHandle,GWL_WNDPROC,
     longint(MDIInstance)) );
end;

procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose:
Boolean);
begin
 { restore default window proc }
 SetWindowLong(ClientHandle,GWL_WNDPROC,longint(MDIDefProc));
 { dispose of instance }
 FreeObjectInstance(MDIInstance);
end;

procedure TfrmMain.mnuExitClick(Sender: TObject);
begin
 close;
end;

procedure TfrmMain.mnuBitmapClick(Sender: TObject);
 var
  wrkDC:hDC;
begin
 wrkDC:=GetDC(ClientHandle);
 ShowBitmap(wrkDC);
 ReleaseDC(ClientHandle,wrkDC);
 mnuBitmap.Checked:=true;
 mnuGradient.Checked:=false;
end;

procedure TfrmMain.mnuGradientClick(Sender: TObject);
 var
  wrkDC:hDC;
begin
 wrkDC:=GetDC(ClientHandle);
 ShowGradient(wrkDC,0,0,255);
 ReleaseDC(ClientHandle,wrkDC);
 mnuGradient.Checked:=true;
 mnuBitMap.Checked:=false;
end;

procedure TfrmMain.ShowBitmap(prmDC:hDC);
 var
  wrkSource:TRect;
  wrkTarget:TRect;
  wrkX:integer;
  wrkY:integer;
begin
 {tile bitmap }
 if FormStyle=fsNormal then
  begin
   wrkY:=0;
   while wrkY < ClientHeight do    { go from top to bottom.. }
    begin
     wrkX:=0;
     while wrkX < ClientWidth do   { ..and left to right. }
      begin
       Canvas.Draw(wrkX,wrkY,imgTile.Picture.Bitmap);
       Inc(wrkX,glbImgWidth);
      end;
     Inc(wrkY,glbImgHeight);
    end;
  end
 else if FormStyle=fsMDIForm then
  begin
   Windows.GetClientRect(ClientHandle,wrkTarget);
   wrkY:=0;
   while wrkY < wrkTarget.Bottom do
    begin
     wrkX:=0;
     while wrkX < wrkTarget.Right do
      begin
       BitBlt(longint(prmDC),wrkX,wrkY,imgTile.Width,imgTile.Height,
                imgTile.Canvas.Handle,0,0,SRCCOPY);
       Inc(wrkX,glbImgWidth);
      end;
     Inc(wrkY,glbImgHeight);
    end;
  end;
end;

procedure TfrmMain.ShowGradient(prmDC:hDC;prmRed,prmGreen,prmBlue:byte);
 var
  wrkBrushNew:hBrush;
  wrkBrushOld:hBrush;
  wrkColor:TColor;
  wrkCount:integer;
  wrkDelta:integer;
  wrkRect:TRect;
  wrkSize:integer;
  wrkY:integer;
begin
 { gradient routine }
 wrkDelta:=255 div (1+ClientHeight); { number of shades desired }
 if wrkDelta=0 then wrkDelta:=1;     { yes, usually 1 }
 wrkSize:=ClientHeight div 240;      { size of blended bars }
 if wrkSize=0 then wrkSize:=1;
 for wrkY:=0 to 1+(ClientHeight div wrkSize) do
  begin
   wrkColor:=RGB(prmRed,prmGreen,prmBlue);
   wrkRect:=Rect(0,wrkY*wrkSize,ClientWidth,(wrkY+1)*wrkSize);
   if FormStyle=fsNormal then
    begin
     Canvas.Brush.Color:=wrkColor;
     Canvas.FillRect(wrkRect);
    end
   else if FormStyle=fsMDIForm then
    begin
     wrkBrushNew:=CreateSolidBrush(wrkColor);
     wrkBrushOld:=SelectObject(prmDC,wrkBrushNew);
     FillRect(prmDC,wrkRect,wrkBrushNew);
     SelectObject(prmDC,wrkBrushOld);
     DeleteObject(wrkBrushNew);
    end;
   if prmRed >wrkDelta then Dec(prmRed,wrkDelta);
   if prmGreen > wrkDelta then Dec(prmGreen,wrkDelta);
   if prmBlue  > wrkDelta then Dec(prmBlue,wrkDelta);
  end;
end;

procedure TfrmMain.FormPaint(Sender: TObject);
begin
 if FormStyle=fsNormal then
  if mnuBitMap.Checked then
   mnuBitMapClick(Sender)
  else
   mnuGradientClick(Sender);
end;

end.



Please email me and tell me if you liked this page.

This page has been created with