Window-handling is important in any complex MDI "editor." You need a
stable and updated window number list. The default pick-list on
the Window menu is unstable if you have more than ten files open. It
makes sense to build your own tracking system.
Tracking Window Numbers in MDI Editors
By Gene Fowler
Warning: The test-bed for this code is Borland's TextEdit demo that comes with Delphi. If you are compiling in Delphi 5 or 5.01, you will need the modified forms.pas which I direct you to in my earlier article, Programming System/Next (Prev) in MDI editors.
In the description above, I say that the Window menu pick-list is unstable when more than ten windows are open. I'm referring to the fact that any file beyond the ninth, when picked, becomes the ninth. A user isn't going to regularly have ten or more windows open and isn't likely to pay much attention to the numbers on the list, anyway. But Microsoft's notion of users mental abilities is not complimentary. The numbers on that list seem to be only an artifact of a numbered list. And only nine are numbered, the ninth one "changing" as the dialog comes up and others are picked. When a window is up there is nothing to identify its position in any order, let alone the load-order. System/Next (and Prev) flips through the z-stack (order) which changes from moment to moment.
In eWriter, my MDI textwriter (the software descendant of the old hardware typewriter), I put a window number (assigned on loading and updated when a file with a lower number is closed) on the status bar, along with the file's byte size. Clicking the status bar will get the "next" file in the load-order (the next higher window number). For jumping, I use the old Turbo Alt+TopNum# for window #1..#9. Alt+TopNum#0 gets a dialog I have on the Window menu (above the default pick list). This dialog gives full pathnames and is a pick list. If the user isn't sure which Alt+# he or she wants, Alt+0 and a click on the pathname and another on the Go button doesn't slow the jump much.
The code below implements (in TextEdit) a simple tracking system that keeps track of window numbers and the files attached. I've put in a simple viewer so you can "check" the window numbers after your opens, closes, and shuffling. I don't know why z-stack order would be useful, but you can see that the simplest way of checking the file/number connection also reflects z-order in the viewer.
|Note: In the setup for the Tile Top 2 of N Windows in my Selective Tiling in MDI Editors, I did not put in any handling for "untitled" files either before or after Saving which puts in a pathname. In SavingAs1Click, I did not add the new file to OpenFiles. And I nowhere did anything about a "Untitled" that has no path. If the "Untitled" is one of the top two, it causes no problem. In the code below, I include a SaveAs1Click that can be included in the Tiling article's code. If you save the new file it is placed in the OpenFiles and is included in all processing. If you have an unsaved "Untitled" File, however, you will have strange effects (as you do now, whether the file is saved or not). The Tile Top 2 of N windows will ignore it. It will show up in the tiling. The loss of Restore sizing is not one of the strange effects. That is caused by Tile1Click which I call in Tile Top 2 of N windows.
In using TextEdit as a test-bed for the MDI Text Editor development
I am doing in these articles, some properties need to be set.
|TOpenDialog Options/ofAllowMultiSelect: True
|TEditForm WindowState: wsmaximized
In MDIFrame.pas, declare a global (Interface section) variable named
EditTag that is used in the modified versions of New1Click and
Open1Click. OpenFiles, used later, is also declared and is
OpenFiles := TStringList.Create;
OpenFiles.Text := '';
The Open1Click and New1Click routines provide a value for EditTag
before each opening. The value will be put into EditForm's tag
variable (In its FormCreate routine). This will insure that each
editor will have a window number.
procedure TFrameForm.New1Click(Sender: TObject);
EditTag := MDIChildCount + 1;
procedure TFrameForm.Open1Click(Sender: TObject);
if OpenFileDialog.Execute then
For i := 0 to OpenFileDialog.Files.count - 1 do
EditTag := MDIChildCount +1;
with TEditForm.Create(Self) do
In TeditForm (MDIEdit.pas), all the tracking is taken care of. In
FormCreate, copy EditTag into Tag:
procedure TEditForm.FormCreate(Sender: TObject);
PathName := DefaultFileName;
Tag := EditTag;
EditTag is the (load sequence) Window Number. This will be kept in
EditForm's Tag variable. These stored numbers will be "moved down"
when an editor with a lower number is closed. Now, we build in our
real tracking engine using TEditForm.Close. This routine uses the
OpenFiles stringlist I declared in MDIFrame.pas.
procedure TEditForm.FormClose(Sender: TObject; var Action: TCloseAction);
i, j: LongInt;
CloseTag := Tag;
for j := 0 to (FrameForm.MDIChildCount - 1) do
with FrameForm.MDIChildren[j] as TEditForm do
if Tag > CloseTag then
Tag := Tag - 1;
for i := 0 to OpenFiles.Count - 1 do
if OpenFiles[i] = Pathname then
Action := caFree;
procedure TEditForm.Saveas1Click(Sender: TObject);
SaveFileDialog.FileName := PathName;
if SaveFileDialog.Execute then
PathName := SaveFileDialog.FileName;
Caption := ExtractFileName(PathName);
OpenFiles.Insert(Tag, Pathname); // list new Pathname
|Note: The viewer menu item set out below seems to cause the default pick list to drop out, at least in Delphi 5. I have fiddled with Selectors in and out. You might want to fiddle with it and see if you can get TextEdit's pick-list for shuffling the z-stack before viewing tracked windows. You might have to Restore windows to small size to shuffle the z-order by pulling windows up. This is probably only in D5 (not D2-D4) which handles menu-building in a way I havn't quite got the hang of. I certainly rebuild the Window menu above the default pick-list in eWriter first written in Delpi 3 and migrated through Delphi 4 to 5.
We want a "viewer" to see the results of our assigning and tracking
of Window Numbers as we open, close, and shuffle (z-stack) windows.
At the bottom of the Window menu items-list, add a new menu item:
|Caption: Window Number Assignment List
Tab to Events and double-click OnClick. Then, fill in
the event handler to create this routine:
procedure TFrameForm.WinNumList1Click(Sender: TObject);
i, j: integer;
// This routine is a bit convoluted to catch "New Files"
List := TSTringList.Create;
List.Add('Outermost Window at top, Z-stack order'#13);
For i := 0 to (MDIChildCount - 1) do
S := 'Window Number ' + IntToStr(MDIChildren[i].Tag);
if MDIChildren[i].Caption = DefaultFileName then
S := S + ' ' + MDIChildren[i].Caption;
for j := 0 to (OpenFiles.Count - 1) do
if pos(MDIChildren[i].Caption, OpenFiles.strings[j]) <> 0 then
S := S + ' ' + OpenFiles.Strings[j];
messageDlg(List.Text, mtInformation, [mbOK],0);
Here's a look at the result:
|Note: To see the uses of this window number tracking in the complex tapestry of real-world window-handling, you might play with my eWriter textwriter. It is not only freeware, but doesn't install itself in the fabric of a system. It's easy to play with. Every open editor has its Window Number on the status bar. Clicking the status bar gets the next higher window number editor. Alt+TopNum# (1..9) gets the window numbered 1..9. Alt+TopNum0 gets a full pathname pic list though the default caption-only pick list is on the Window menu for slightly quicker picking. (The full path pick list is above it on the menu.) 0.C, due out in June, 2001 will have window numbers in the pathname pick list as a result of my writing this article.