Tracking Window Numbers in MDI Editors

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
acorioso@earthlink.net


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.

Code:

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.
These are:

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
initialized.

TFrameForm
  ...
var
  ...
  EditTag: longInt;
  OpenFiles: TstringList;

Initialization
...
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);
begin
  LockWindowUpdate(Handle);
  EditTag := MDIChildCount + 1;
  TEditForm.Create(Self);
  LockWindowUpdate(0);
end;

procedure TFrameForm.Open1Click(Sender: TObject);
var
  i: integer;

begin
  if OpenFileDialog.Execute then
  LockWindowUpdate(Handle);
  For i := 0 to OpenFileDialog.Files.count - 1 do
    begin
      EditTag := MDIChildCount +1;
      with TEditForm.Create(Self) do
      Open(OpenFileDialog.Files[i])
    end;
  LockWindowUpdate(0);
end;

In TeditForm (MDIEdit.pas), all the tracking is taken care of. In
FormCreate, copy EditTag into Tag:

procedure TEditForm.FormCreate(Sender: TObject);
begin
  PathName := DefaultFileName;
  Tag := EditTag;
end;

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);
var
  i, j: LongInt;
  CloseTag: integer;

begin
  CloseTag := Tag;
  for j := 0 to (FrameForm.MDIChildCount - 1) do
  with FrameForm.MDIChildren[j] as TEditForm do
    begin
      if Tag > CloseTag then
      Tag := Tag - 1;
    end;
  for i := 0 to OpenFiles.Count - 1 do
    if OpenFiles[i] = Pathname then
      begin
       OpenFiles.Delete(i);
       break;
      end;
  Action := caFree;
end;

procedure TEditForm.Saveas1Click(Sender: TObject);
begin
  SaveFileDialog.FileName := PathName;
  if SaveFileDialog.Execute then
  begin
    PathName := SaveFileDialog.FileName;
    Caption := ExtractFileName(PathName);
    OpenFiles.Insert(Tag, Pathname); // list new Pathname
    Save1Click(Sender);
  end;
end;

View Results:

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
Name: WinNumList1

Tab to Events and double-click OnClick. Then, fill in
the event handler to create this routine:

procedure TFrameForm.WinNumList1Click(Sender: TObject);
var
  i, j: integer;
  List: tstringList;
  S: string;

begin
  // 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
    Begin
      S := 'Window Number ' + IntToStr(MDIChildren[i].Tag);
      if MDIChildren[i].Caption = DefaultFileName then
        begin
          S := S + ' ' + MDIChildren[i].Caption;
          List.Add(S);
        end
      else
        begin
        for j := 0 to (OpenFiles.Count - 1) do
          if pos(MDIChildren[i].Caption, OpenFiles.strings[j]) <> 0 then
            begin
              S := S + ' ' + OpenFiles.Strings[j];
              List.Add(S);
             break
           end;
        end;
    end;
  messageDlg(List.Text, mtInformation, [mbOK],0);
  List.Free
end;

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.
Interlaced Bibliography
I began ad-libbing these articles on doing some of the things I do
 in eWriter in the Delphi demo TextEdit (from which I built eWriter).
 It's natural to accumulate all these in one copy of TextEdit. And
 you might have to go back and forth to fill in new, missed, or
 changed support routines. Boxed notes appear most places. Figure
 it's on-going "shop" conversation...
  1. Programming System/Next (Prev) in MDI editors


    http://www.HowToDoThings.com/showarticle.asp?article=143

  2. Selective Tiling in MDI Editors


    http://www.HowToDoThings.com/showarticle.asp?article=147

  3. Tracking Window Numbers in MDI Editors


    http://www.HowToDoThings.com/showarticle.asp?article=154

  4. Paragraph "pouring" from a text editor


    http://www.HowToDoThings.com/showarticle.asp?article=178

 

Share this article!

Follow us!

Find more helpful articles: