天天看點

第15章 内部窗體和桌面窗格

第15章 内部窗體和桌面窗格

  Swing提供實作多文檔界面(MDI)應用程式的一組元件。MDI應用程式(如Microsoft Word和Adobe FrameMaker)是用一個視窗實作的,這個視窗是應用程式中建立的文檔的桌面。

  Swing提供帶桌面的MDI功能和内部窗體,其中桌面由JDesktopPane類表示,内部窗體由JInternalFrame類表示。内部窗體在桌面上,并且可以在桌面内打開、關閉、最大化和圖示化。Swing提供一個DesktopManager類,用這個類來實作桌面上的内部窗體的特定界面樣式行為。

15.1 JInternalFrame

  由于内部窗體是外部窗體的複制品,是以内部窗體也是窗體。由于它們包含在另一個Swing容器中,是以它們是内部的,而這個容器通常是一個桌面窗格。

  内部窗體邊框中所包含的控件與界面樣式有關。标準Swing界面樣式都提供關閉按鈕、最大化按鈕和最小化按鈕,這可以從圖15-1的Metal界面樣式中看到。另外,Metal界面樣式還提供在标題條中的控制條和圖示,如圖15-1最下面的圖檔所示。

  

           圖15-1 運作中的JInternalFrame

  單擊圖15-1所示的小應用程式中的按鈕将産生内部窗體。圖15-1頂層的窗體被選取,此時,這個窗體的邊框是增亮的。

  例15-1列出了圖15-1所示的小應用程式的代碼。

例15-1 運作中的JInternalFrame

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class Test extends JApplet {

        JButton b = new JButton("make frame");

        JDesktopPane desktopPane = new JDesktopPane();

        int windowCount = 1;

        public void init() {

               Container contentPane = getContentPane();

               contentPane.add(b, BorderLayout.NORTH);

               contentPane.add(desktopPane, BorderLayout.CENTER);

               desktopPane.setLayout(new FlowLayout());

               b.addActionListener(new ActionListener() {

                       public void actionPerformed(ActionEvent event) {

                               JInternalFrame jif = new JInternalFrame(

                                       "Internal Frame " + windowCount++, // title

                                       true,  // resizable

                                      true,  // closable

                                       true,  // maximizable

                                       true); // iconifiable

                               jif.setPreferredSize(new Dimension(250, 100));

                               desktopPane.add(jif);

                               jif.show();//新添加一句,原文沒有

                               desktopPane.revalidate();

                       }

               });

        }

}

15.1.1 JInternalFrame屬性

15.1.2 JInternalFrame事件

例15-2 處理内部窗體事件

import java.beans.*;

import javax.swing.event.*;

JDesktopPane desktopPane = new JDesktopPane();

public void init() {

Container contentPane = getContentPane();

contentPane.add(desktopPane, BorderLayout.CENTER);

desktopPane.setLayout(new FlowLayout());

JInternalFrame jif = new JInternalFrame(

"An Internal Frame", // title

false, // resizable

true, // closable

true, // maximizable

true); // iconifiable

jif.setPreferredSize(new Dimension(300, 250));

jif.addInternalFrameListener(new Listener(this));

jif.show();//新添加一句,原文沒有

desktopPane.add(jif);

class Listener implements InternalFrameListener {

private JApplet applet;

public Listener(JApplet applet) {

this.applet = applet;

public void internalFrameActivated(InternalFrameEvent e) {

applet.showStatus("frame activated");

public void internalFrameClosed(InternalFrameEvent e) {

applet.showStatus("frame closed");

public void internalFrameClosing(InternalFrameEvent e) {

applet.showStatus("frame closing");

public void internalFrameDeactivated(InternalFrameEvent e) {

applet.showStatus("frame deactivated");

public void internalFrameDeiconified(InternalFrameEvent e) {

applet.showStatus("frame deiconified");

public void internalFrameIconified(InternalFrameEvent e) {

applet.showStatus("frame iconified");

public void internalFrameOpened(InternalFrameEvent e) {

applet.showStatus("frame opened");

private void sleepForABit() {

try {

Thread.currentThread().sleep(5000);

catch(InterruptedException e) {

e.printStackTrace();

例15-3 否決關閉内部窗體

import java.util.*;

public class Test extends JFrame {

public Test() {

"Some Editor", // title

true); // closable

jif.addVetoableChangeListener(new CloseListener());

jif.show();//新添加的一句,原文沒有

public static void main(String args[]) {

GJApp.launch(new Test(),

"Vetoing Internal Frame Closing",

300,300,450,300);

class CloseListener implements VetoableChangeListener {

private Test applet;

public void vetoableChange(PropertyChangeEvent e)

throws PropertyVetoException {

String name = e.getPropertyName();

if(name.equals(JInternalFrame.IS_CLOSED_PROPERTY)) {

Component internalFrame = (Component)e.getSource();

Boolean oldValue = (Boolean)e.getOldValue(),

newValue = (Boolean)e.getNewValue();

if(oldValue == Boolean.FALSE &&

newValue == Boolean.TRUE) {

int answer = JOptionPane.showConfirmDialog(

internalFrame, // parentComponent

"Save Changes?", // message

"Unsaved Changes", // title

JOptionPane.YES_NO_CANCEL_OPTION);

if(answer == JOptionPane.CANCEL_OPTION) {

throw new PropertyVetoException(

"close cancelled", e);

class GJApp extends WindowAdapter {

static private JPanel statusArea = new JPanel();

static private JLabel status = new JLabel(" ");

static private ResourceBundle resources;

public static void launch(final JFrame f, String title,

final int x, final int y,

final int w, int h) {

launch(f,title,x,y,w,h,null);

final int w, int h,

String propertiesFilename) {

f.setTitle(title);

f.setBounds(x,y,w,h);

f.setVisible(true);

statusArea.setBorder(BorderFactory.createEtchedBorder());

statusArea.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));

statusArea.add(status);

status.setHorizontalAlignment(JLabel.LEFT);

f.setDefaultCloseOperation(

WindowConstants.DISPOSE_ON_CLOSE);

if(propertiesFilename != null) {

resources = ResourceBundle.getBundle(

propertiesFilename, Locale.getDefault());

f.addWindowListener(new WindowAdapter() {

public void windowClosed(WindowEvent e) {

System.exit(0);

});

static public JPanel getStatusArea() {

return statusArea;

static public void showStatus(String s) {

status.setText(s);

static Object getResource(String key) {

if(resources != null) {

return resources.getString(key);

return null;

例15-4 替換一個内部窗體的圖示

"Internal Frame", // title

true, // resizble

jif.setBounds(50, 50, 300, 200);

jif.setFrameIcon(new ImageIcon(this.getClass().getResource("print.gif")));

jif.show();//源添加的一句,原文沒有

15.1.3 AWT相容

例15-5 一個定制的桌面窗格

CustomDesktopPane desktopPane = new CustomDesktopPane();

int frameCount = 1, numFrames = 5, x, y;

setJMenuBar(createMenuBar());

for(int i=0; i < numFrames; ++i) {

"Internal Frame " + frameCount++, // title

true, // resizable

x = (int)(Math.random() * 100);

y = (int)(Math.random() * 100);

jif.setBounds(x, y, 250, 100);

desktopPane.putClientProperty(

"JDesktopPane.dragMode",

"outline");

private JMenuBar createMenuBar() {

JMenuBar menubar = new JMenuBar();

JMenu windowMenu = new JMenu("Window");

windowMenu.add(new OpenAllAction());

windowMenu.add(new CloseAllAction());

windowMenu.add(new CascadeAction());

menubar.add(windowMenu);

return menubar;

class OpenAllAction extends AbstractAction {

public OpenAllAction() {

super("open all");

public void actionPerformed(ActionEvent e) {

desktopPane.openAll();

class CloseAllAction extends AbstractAction {

public CloseAllAction() {

super("close all");

desktopPane.closeAll();

class CascadeAction extends AbstractAction {

public CascadeAction() {

super("cascade");

desktopPane.cascade();

class CustomDesktopPane extends JDesktopPane {

private int xoffset = 20, yoffset = 20, w = 250, h = 350;

public void closeAll() {

JInternalFrame[] frames = getAllFrames();

for(int i=0; i < frames.length; ++i) {

if(!frames[i].isIcon()) {

frames[i].setIcon(true);

catch(java.beans.PropertyVetoException ex) {

System.out.println("iconification vetoed!");

public void openAll() {

if(frames[i].isIcon()) {

frames[i].setIcon(false);

System.out.println("restoration vetoed!");

public void cascade() {

int x = 0, y = 0;

if( ! frames[i].isIcon()) {

frames[i].setBounds(x,y,w,h);

x += xoffset;

y += yoffset;

15.2 JDesktopPane

15.2.1 JDesktopPane屬性

15.2.2 JDesktopPane事件

15.2.3 JDesktopPane類總結

15.2.4 AWT相容

15.3 DesktopManager

例15-6 一個定制的DesktopManager

desktopPane.setDesktopManager(new OutlineManager());

"Outline Drag and Resize", // title

jif.setBounds(10, 10, 250, 100);

jif.show();//新添加的,原文沒有

class OutlineManager extends DefaultDesktopManager {

private Rectangle start, last;

private boolean first = true;

// dragging ...

public void beginDraggingFrame(JComponent frame) {

initializeOutline(frame);

public void dragFrame(JComponent frame, int x, int y) {

updateOutline(frame, x, y, start.width, start.height);

public void endDraggingFrame(JComponent frame) {

endOutline(frame);

// resizing ...

public void beginResizingFrame(JComponent frame, int dir) {

public void resizeFrame(JComponent frame,

int x, int y, int w, int h) {

updateOutline(frame, x, y, w, h);

public void endResizingFrame(JComponent frame) {

// outline ...

private void initializeOutline(final JComponent frame) {

// the call to setVisible() calls repaint, which

// places a paint event on the event queue.

// therefore, the effect of the setVisible() call is

// not apparent until after this method returns

frame.setVisible(false);

start = frame.getBounds();

last = new Rectangle(start);

first = true;

// the Runnable below paints the initial outline

// after the repaint event spawned by setVisible() is

// handled

SwingUtilities.invokeLater(new Runnable() {

public void run() {

updateOutline(frame,start.x,start.y,

start.width,start.height);

private void updateOutline(JComponent frame,

Container container = frame.getParent();

Graphics g = container.getGraphics();

g.setXORMode(container.getBackground());

if( ! first) {

g.drawRect(last.x, last.y,

last.width-1, last.height-1);

g.drawRect(x, y, w-1, h-1);

first = false;

finally {

g.dispose();

last.setBounds(x,y,w,h);

private void endOutline(JComponent frame) {

frame.setVisible(true);

setBoundsForFrame(

frame, last.x, last.y, last.width, last.height);

15.4 本章回顧

  略

繼續閱讀