MDI DEVELOPMENT IN DELPHI. Part II.
Creating a multiple document interface graphic file viewer.
In the previous article we constructed the basic MDI application with a MDI parent window and one-type MDI child. Some of the basic MDI programming issues were discussed such as MDI main menu and arranging child forms. In this article, we'll expand our MDI application with some real code to open and display a graphic file.
Components on a MDI child form
At design time, child forms are not restricted to the area inside the MDI parent form. We can add components, set properties, write code, and design the features of child forms just as we would with any other Delphi form. Child forms can contain any components like Grids, Memos and Pictures. Traditionally, objects like status bars and toolbars usually appear in the MDI parent window.
Follow these steps to enable our child form for displaying bitmap files:
- Start with the MDI application (forms and code) from the previous article.
- Select the Child form (frChild) and insert an Image component (Additional palette).
- Set the Image1's Align property to AlClient, so that it fills the window. Make sure that the Stretch property is True.
That's it for the child form. Only one component, but enough to understand MDI programming principals.
Note: avoid dropping components into the main form (MDI parent). Controls like TLabel wont be displayed at all, and TButton might not work correctly. Status bars, toolbars and alligned panels are acceptable, of course.
Display picture
Since we have the ability to display graphic files in the child form, we need some code to open (and display) desired graphics in the TImage component. Naturally, we'll add a menu item to the MainManu of the MDI parent, that will do the work.
Select the MainMenu component on the MDI parent form (frMain), and invoke the menu designer by double clicking it. Add the "Load picture" menu item, and let it appear under the "New child" menu item.
Next, add the following code to the LoadPictureClick event handler ("Load picture" menu item):
procedure TfrMain.LoadPictureClick(Sender: TObject); begin if ActiveMDIChild <> nil then TfrChild(ActiveMDIChild).LoadPicture; end; |
Note: you should always place programming code specific to the child form in the child's unit. Therefore, the LoadPicture procedure is declared in the uChild.unit (that is: the code is in the child form's unit).
LoadPicture procedure displays the standard Open Picture Dialog, and enables the user to select one image to be displayed in the TImage component of a child window.
uses ExtDlgs; ... procedure TfrChild.LoadPicture; var OpenPicDlg : TOpenPictureDialog; begin OpenPicDlg := TOpenPictureDialog.Create(Self); if OpenPicDlg.Execute then begin Image1.Picture.LoadFromFile(OpenPicDlg.FileName); end; OpenPicDlg.Free; end; |
LoadPicture procedure should be declared in the public section of the TChild form, so that it can be visible by the MDI parent (and called by the LoadPictureClick event handler).
...
type
TfrChild = class(TForm)
...
private
public
procedure LoadPicture;
end;
...
|
Note 1: LoadPicture procedure creates Open Picture Dialog box at runtime without the need to place an OpenPictureDialog component on the form. To learn more about working with standard Windows dialogs in Delphi, read the Working with common dialog boxes article.
Note 2: In order to use OpenPictureDialog we have to include ExtDlgs unit in the uses clause of the child unit.
ActiveMDIChild
Strictly speaking, ActiveMDIChild is a read-only TForm property which is nil if the TForm is not an MDIParentForm (that is: form that is not a MDI parent, FormStyle <> fsMDIform), or a pointer to the current TForm child window which has input focus in an MDI application.
Use the ActiveMDIChild MDI parent's property to perform operations on the current child window. Before using the ActiveMDIChild always check that this property is not nil, like in the LoadPictureClick event handler.
Since ActiveMDIChild returns a pointer to the form, unless we are using an inherited method or property such as Close, we need to type cast the ActiveMDIChild to call methods in our child class. Notice the TfrChild(ActiveMDIChild).LoadPicture command.
MDI parent form Main Menu, again
The Window menu of an MDI application should also include a list of the MDI child windows. As everything in Delphi, this is easy to accomplish. Assume that we have a menu item named ChildList on a MDI form. To add the list of MDI child windows, set:
frMain.WindowMenu := ChildList; |
Delphi will automatically display the list of the MDI child form captions, and even put a check mark next to the one that most recently was active.
Note: In Delphi 5, there is a known bug with WindowMenu property (captions won't display). Work around: set AutoHotkeys and AutoLineReduction properties to maManual, the maAutomatic value seems to interfere with the way Windows handles the Window menu in MDI apps. For some reason if you have a separator on that menu, it won't work at all (from what I remember) and the list gets a little weird when you change the form's caption at runtime, the MDI children disappear until another form is made.
More child-parent window behaviour
If we maximize a child form (it can only be maximized inside a MDI parent), its caption is added to the caption of the MDI parent form, and looks like "MDI parent caption - [Child caption]". After maximizing one child form - all child forms have the WindowState property set to wsMaximized, that is: all child forms are maximized also.
The following code could be used to perform a "Minimize All" child windows:
procedure TfrMain.MinimizeAl1Click(Sender: TObject); var i: integer; begin for i:= MdiChildCount - 1 downto 0 do MDIChildren[i].WindowState := wsMinimized; end; |
When the parent window is minimized or closed, all child windows are minimized or closed with it.
When the MDI form is minimized, the MDI form and all of its child forms are represented by a single icon on the task bar. When the MDI form is restored, the MDI form and all the child forms are displayed in the same state they were in before being minimized.
Menu switching
One of the default features of Delphi's MDI forms is that the menus of the MDI parent form change according to which child form has the focus. This let's us work with specific menus for each child form (if we have different-type child forms).
The active child form's menus (if any) are displayed on the MDI form's menu bar, not on the child form. In particular, the user only sees the menu for the child form when that child form is active.
That's it
This concludes (at least for now) our trip to MDI development in Delphi. Don't forget to download this project.
Related
Need forms that keep proportionality when being resized manually? And also when being Maximized or Tiled/Cascaded? Forms for both MDI and SDI type applications? TNFormSizing is all you need for that. Just put the TNFormSizing on your form and choose an option for ProportionType - its only published property. Free with code.


