Mega Code Archive

 
Categories / Delphi / Examples
 

Programming system-next [prev] in mdi editors

"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