Multiple Document Interface (MDI)


This document describes how to use the MDI classes for Smalltalk Express. MDI is a user interface standard for presenting and manipulating multiple documents within a single application. The MDI functionality is defined and implemented in Windows 3.x. For more information about MDI, please refer to the Microsoft documentation. The Smalltalk Express MDI classes fully support MDI capabilities as defined by Microsoft.

MDI (along with StatusPane and ToolPane) can be installed by filing in "mdi.st" in "extras\mdi" subdirectory.

For an example, look in the extras\mdi\mdidemo directory. Two examples are provided: SysEdit and MDIDemo.

Smalltalk Express will also run in MDI mode as well as in its standard non-MDI configuration. To change to MDI mode, select the File menu and the MDI Mode menu item. For more information, see the section "Important" at the bottom of this page.

Programming Interface


New classes that have been introduced are:

MDIChild

MDIClient

MDIFrame

MDIMenu

MDITranscript

MDISystem

MDIViewManager

Developing an MDI application


An MDI application must first create an MDIFrame Window. The MDIFrame window is the main window of your application. It encapsulates all the documents of your application (MDIChild). Both MDIFrame and MDIChild classes are subclasses of TopPane. Their protocol is fully compatible with their superclass TopPane.

An MDI application class should be under MDIViewManager, which is itself a subclass of ViewManager.

The MDI classes use the ViewManager Model (event-driven, multiple views on the same model, clear separation between the GUI and the application). Please refer to the Smalltalk documentation for more information about ViewManager.

Create an MDIFrame window


The creation of an MDIFrame window is usually accomplished by sending the message "open" to a new instance of the MDIViewManager subclass. The window opening method initializes the label for the MDIFrame window and registers events such as:

#mdiMenuBuilt

#menuBuilt

The MDIClient subpane (MDIClient subpane is the client window of the MDIFrame window) is automatically created by the MDIFrame class and shouldn't be created by the MDIViewManager subclass.

Create an MDIChild


Since MDIChild window is created in the same way as TopPane window, all existing ViewManager subclasses can be used in an MDI application without modifying their code. MDIChild replaces the functionality of TopPane for an MDI application.

The following is an example code that creates an MDIChild window.

self addView:(MDIChild new frame:self frame;

owner:self;

label:'Example Child 1').

The only major difference between the creation of MDIChild and TopPane window is that the "frame" must be specified for the MDIChild window.

MDIChild class


MDIChild class is responsible for creating MDI documents and manage its subpanes. It responds to the system MDI messages and allows applications to set event hooks.

MDIChild Instance methods:


close

"Close the receiver and all its children."

disableSystemMenuItemClose

"Disable the receiver's 'close' system menu item."

frame

"Answer the receiver's frame."

frame:aFrame

"Set the receiver's frame to aFrame."

frameRectangle

"Answer the receiver's frame area

as a rectangle."

isMDIChild

"Answer true if receiver is an instance of class

MDIChild, else answer false."

label:aString

"Set the receiver's label without the Smallalk/V prefix to aString"

MDIChild Class methods:


supportedEvents

"Answer the Set of events that MDIChild instances can notify their owners about."

MDIChild Supported events:


#toggleKey

Notify the owner that one of the toggle keys (NumLockKey,

InsertKey, CapitalKey) has been pressed.

MDIFrame class


MDIFrame class is responsible for creating MDI frame window and managing its subpanes. It responds to the system MDI messages and allows applications to set event hooks. Typical subpanes of an MDI frame window are MDIClient, StatusPane and ToolPane. The MDIFrame class creates the MDIClient subpane.

MDIFrame instance methods:


activeTextPane

"Answer the subpane of the active MDIChild that has the typing focus."

checkItem:itemName forAllMDIChildMenus:menuName

"Check the itemName of the menuName.

This menu item will be checked for all MDI documents"

close

"The receiver is being closed Answer nil if one of the receiver's documents has not been closed"

disableItem:itemName forAllMDIChildMenus:menuName

"Disable the itemName of the menuName. This menu item will be disabled for all MDI documents"

enableItem:itemName forAllMDIChildMenus:menuName

"Enable the itemName of the menuName. This menu item will be enabled for all MDI documents"

isMDIFrame

"Answer true if receiver is an instance of class MDIFrame, else answer false."

mdiArrange

"Arrange the MDI documents"

mdiCascade

"Cascade the MDI documents"

mdiChildren

"Answer a collection of the currently opened MDI documents"

mdiCloseAll

"Close all the MDI documents which are not minimized"

mdiGetActive

"Answer the MDI active document if any, else answer nil"

mdiMenuWindow

"Answer the MDI menu window. It contains the menus at the right side of the menu bar, after the menus specific to the MDI document"

mdiTile

"Tile the MDI documents"

uncheckItem:itemName forAllMDIChildMenus:menuName

"Uncheck the itemName of the menuName. This menu item will be unchecked for all the MDI documents"

MDIFrame class methods:


supportedEvents

"Answer the Set of events that MDIFrames can notify their owners about."

MDIFrame Supported events:


#mdiMenuBuilt

Notify the owner that it can create menus. These menus are common to all the MDI documents and come after the menus specific to each documents.

#toggleKey

Notify the owner that one of the toggle keys (NumLockKey, InsertKey, CapitalKey) has been pressed.

#childActivate

Notify the owner that an MDI document has been activated.

#childDeactivate

Notify the owner that an MDI document has been deactivated.

#childClose

Notify the owner that an MDI document has been closed. Remark: When the user closes the last MDI document, the owner will not receive a childDeactivate event. The owner will only receive the childClose event.

MDIViewManager class


The owner of an MDIFrame class should be an MDIViewManager class. An MDIViewManager subclass is primarily responsible for

MDIViewManager instance methods:


activeTextPane

"Answer the active textPane of the active MDI document"

frame

"Answer the receiver's frame"

frame:

"Set the receiver's frame"

mdiArrange

"Arrange the MDI documents"

mdiCascade

"Cascade the MDI documents"

mdiCloseall

"Close all MDI documents which are not minimized"

mdiNewWindow

"Create a new TextWindow MDI document from the active TextPane"

mdiTile

"Tile the MDI documents"

MDIMenu class


This class is used to create the standard MDI "Window" menu for arranging the MDI workspace. Its protocol is fully compatible with its superclass Menu. This class should be used only to create the MDI "Window" menu and only for that purpose.

Define the menus for MDIFrames

The menus of an MDIFrame window are created using

two events:

#menuBuilt

#mdiMenuBuilt

The menus created upon the receptions of these events will be common to all the MDI documents.

The #menuBuilt event is used to create the menus which are on the left side of the menu bar. If the owner responds to that event, the MDI frame will not get the standard default Smalltalk file menu.

The #mdiMenuBuilt is used to create the menus which are on the right side of the menu bar. At least, the frame owner has to create the standard MDI "Window" menu which is used to manage the MDI workspace.

Example:

MDIDemo>>open

self addView:(

self frame:(MDIFrame new

owner:self;

when: #menuBuilt perform: #menu:;

when: #mdiMenuBuilt perform:#mdiMenu:;

labelWithoutPrefix:'MDI Demo')).

MDIDemo>>menu:anMDIFrame

"Private - Build the file menu"

anMDIFrame menuWindow addMenu: self fileMenu owner:self.

MDIDemo>>mdiMenu:anMDIFrame

"Private - Build the standard MDI Window menu"

anMDIFrame mdiMenuWindow addMenu:self class mdiMenu owner:self.

MDIDemo>>fileMenu

"Private - Answer the receiver's fileMenu"

^Menu new

appendItem: '&Green document' selector: #doc1 ;

appendItem: '&Yellow document' selector: #doc2;

appendSeparator ;

appendItem: '&Exit' selector: #exit ;

title: '&Demo'.

MDIDemo class>>mdiMenu

^MDIMenu new

appendItem: '&New Window' selector:#mdiNewWindow accelKey:$n accelBits:AfControl;

appendItem: '&Cascade Shift+F5' selector: #mdiCascade accelKey: VkF5 accelBits:

AfVirtualkey|AfShift ;

appendItem: '&Tile Shift+F4' selector: #mdiTile accelKey: VkF4 accelBits: AfVirtualkey|AfShift ;

appendItem: 'Arrange &Icons' selector: #mdiArrange;

appendItem: 'Close &All' selector: #mdiCloseall;

title: '&Window'.

Important:


For the standard MDI "Window" menu, it is necessary to use the MDIMenu class instead of the normal Menu class to create a menu object. The protocol of the MDIMenu class is fully compatible with its superclass Menu.

MDISystem and MDITranscript classes

MDISystem and MDITranscript classes are used to encapsulate the Smalltalk/V development tools in an MDIFrame window. The implementation of MDISystem class demonstrates that all existing ViewManager subclasses can be used in an MDI application without modifying their code.

The user can switch back and forth between the MDI mode and non MDI mode through the "Switch to MDI" and "Quit MDI"options in the Transcript File menu.

The user can also switch to an MDI mode by evaluating the following expression:

MDISystem activate

Note: Switching to MDI will close all currently open windows. You will not be prompted to save edited TextPanes. The Transcript will be re-opened in MDI with the original text intact.

The user can swich to non MDI mode by evaluating the following expression:

MDISystem deactivate

Note: Switching to non-MDI mode will not restore the image to the state it was in before starting MDI.

Only applications using the ViewManager compatibility with ApplicationWindow will be encapsulated in the MDIFrame window.

If you don't want your application to be an MDI document, you can overwrite ViewManager>>topPaneClass in your subclass to always answer TopPane.


[top][index]