Examples Delphi

"How to" program the system menu in the MDI child windows
of an MDI text editor or textwriter to change Next and Prev
from z-stack running to useful writing/editing tasks
Programming System/Next (Prev) in MDI editors
By Gene Fowler
acorioso@earthlink.net
Writing extended Notepads is a common practice and the new Notepad
is almost always an MDI application. TextEdit is a "sample" or
"demo" that has been in every Delphi package. I wrote this for my
own extended Notepad which started in TextEdit back in 1997, so
I didn't even have to change the unit names for you to put the code
into TextEdit's source, compile and run your tests.
The MDI child's System menu Next has been unchanged since time
immemorial. It's a programmer's "test run" of the z-stack of open
windows (editors, in our case). Open a number of files or editors.
Keep hitting System/Next or Ctrl+F6 and you keep putting the top
card at the bottom of the stack. Use the (hidden) System/Prev by
hitting Shift+Ctrl+F6 and do a reverse run by bringing the bottom
card to the top. Useful in alpha testing. It is not useful in an
editor. After jumping among windows for a time, the z-stack no
longer reflects the load (or window number) order and you have
a kind of random window access.
What would be useful for a writer or editor would be to keep
swapping the top two windows and, after jumping to another window
or opening a new one, to return to those two and go on swapping.
The code below implements this. System/Next or Ctrl+F6 will do
the swapping by bringing the next-to-top to the top. The last
two positions are remembered after every use of Next and, if
positions are shifted, Shift+Ctrl+F6 will restore the two to
their positions after the last System/Next or Ctrl+F6. This will
work in any 32-bit Delphi.
If you are compiling TextEdit in Delphi 5.0 or (after applying
the Update Pack) 5.01, you will have an unstable TextEdit to put
this into. Any MDI program like TextEdit using merged menus will
break and lock up when you switch maxed windows. In Delphi 1
through 4 a less serious result occurred. The [x] button of
the new top editor would be grayed, but functional. This was
because no "Restore ... Maximize" bracketed the switch. These were
tacked on as an afterthought to force the menu into a useable
state. In 5.0, the "forcing code" was removed. But no bracketing
was inserted. Hence, the total crash. Solutions for the D4 problem
appeared in the Delphi Bug list (not Borland's). One of those
solutions will solve the D5 problem. This URL will take you to
item 0372 in the Delphi Bug list:
http://www.jrsoftware.org/buglist/generated/entry0372.htm
Copy Greg Chapman's procedure (TCustomForm.MergeMenu) into a
file and save it. Make a copy of forms.pas and replace that
procedure in forms.pas with Chapman's. Put the altered forms.pas
into the TextEdit project directory and do a build of TextEdit.
I've read that supplied VCL source does not always match the
DCU, but this seems not to cause any problems here. Still, it is
a good idea to confine the altered unit to individual MDI project
directories and not use it generally as a new forms.pas on your
library path.
The code below is a message handler to place in MDIEdit.pas
and two response routines to place in MDIFrame.pas. The declarations
are also here.
Code:
{ This message handler is in the MDIEdit.pas unit of the
Borland demo TextEdit used as a test-bed for this project.
}
type
TEditForm = class(TForm)
...
private
...
procedure WMSysCommand(var Msg: TWMSysCommand);
message WM_SYSCOMMAND;
...
procedure TEditForm.WMSysCommand(var Msg: TWMSysCommand);
begin
Case Msg.CmdType of
SC_NextWindow:
begin
FrameForm.GetNext;
end;
SC_PREVWINDOW:
begin
FrameForm.GetPrev;
end
else inherited;
end;
end;
{ These two routines are in the MDIFrame.pas unit of the
Borland demo TextEdit used as a test-bed for this project.
}
type
TFrameForm = class(TForm)
...
procedure GetNext;
procedure GetPrev;
...
var
...
IsMaxed: boolean;
F6One: string;
F6Two: string;
implementation
procedure TFrameForm.GetNext;
begin
if MDIChildCount < 2 then
begin
messageBeep(0);
Exit;
end;
LockWindowUpdate(Handle);
F6One := ActiveMDIChild.Caption;
if ActiveMDIChild.WindowState = wsMaximized then
begin
IsMaxed := True;
ActiveMDIChild.WindowState := wsNormal;
end;
MDIChildren[1].BringToFront;
if IsMaxed then
begin
IsMaxed := False;
ActiveMDIChild.WindowState := wsMaximized;
end;
F6Two := ActiveMDIChild.Caption;
LockWindowUpdate(0);
end;
procedure TFrameForm.GetPrev;
var
i: integer;
begin
if MDIChildCount < 2 then
begin
messageBeep(0);
Exit;
end;
LockWindowUpdate(Handle);
if ActiveMDIChild.WindowState = wsMaximized then
begin
IsMaxed := True;
ActiveMDIChild.WindowState := wsNormal;
end;
for i := 0 to MDIChildCount - 1 do
if MDIChildren[i].Caption = F6One then
MDIChildren[i].BringToFront;
for i := 0 to MDIChildCount - 1 do
if MDIChildren[i].Caption = F6Two then
MDIChildren[i].BringToFront;
if IsMaxed then
begin
IsMaxed := False;
ActiveMDIChild.WindowState := wsMaximized;
end;
LockWindowUpdate(0);
end