声明:本文章中介绍的内容可以在GPF项目中找到相应的实现。
 
GPF计划使用MDI的处理模式,Java的JDesktopPane和JInternalFrame已经为我们实现了这样的功能。但是,在将JInternalFrame最大化的时候,JDesktopPane和我们熟知的其他软件,如Word等,具有不同的处理方式。此时可以通过这里介绍的内容弥补这一缺点,使Swing的程序更类似于本地实现。
 
首先先看一下怎么使用JDesktopPane和JInternalFrame实现MDI。其实实现的方式很简单,就是在一个窗口中添加JDesktopPane,然后使用JDesktopPane的add方法,添加JInternalFrame的实例即可。具体的代码片段如下所示:
 
//... 
final JDesktopPane desktopPane =  new JDesktopPane(); 
//... 
Container content = getContentPane(); 
content.add(desktopPane, BorderLayout.CENTER); 
//... 
InnerFrame iFrame =  new InnerFrame(); 
iFrame.setVisible( true); 
desktopPane.add(iFrame); 
//...
 
由此即可按照Java提供的方式添加MDI的实现。我们可以看到它的运行截图如下所示:
 
 
可以看到,当JInternalFrame最大化的时候,仅仅是充满了整个JDesktopPane,并不会像一般的MDI程序一样,将最大化最小化的按钮显示在菜单栏。这是因为JInternalFrame是一个轻量级组件,必须依附在容器之中,因此它的大小不可能超出JDesktopPane。为了获得我们想要的效果,我们对JInternalFrame的UI进行改写:
 
class InnerFrame  extends JInternalFrame { 
   
   /** The is hidden. */ 
   boolean isHidden =  false
   
   /** The old ui. */ 
  BasicInternalFrameUI oldUi =  null
   
   /** 
   * Instantiates a new inner frame. 
   */
 
   public InnerFrame() { 
      oldUi = (BasicInternalFrameUI)getUI(); 
      setSize(200, 200); 
      maximizable =  true
      closable =  true
      addComponentListener( new ComponentAdapter() { 
          public  void componentResized(ComponentEvent e) { 
            InnerFrame selectedFrame = (InnerFrame)e.getSource(); 
             if(selectedFrame.isMaximum()){ 
              selectedFrame.hideNorthPanel(); 
              opPane.setVisible( true); 
               try { 
                 selectedFrame.setMaximum( true); 
              }  catch (PropertyVetoException ex) { 
                 ex.printStackTrace(); 
              } 
          } 
      } 
    }); 
  } 
   
   /** 
   * Hide north panel. 
   */
 
   public  void hideNorthPanel(){ 
      ((BasicInternalFrameUI)  this.getUI()).setNorthPane( null); 
       this.putClientProperty( "JInternalFrame.isPalette", Boolean.TRUE); 
      isHidden =  true
  } 
   
   /** 
   * Show north panel. 
   */
 
   public  void showNorthPanel() { 
       this.setUI(oldUi); 
       this.putClientProperty( "JInternalFrame.isPalette", Boolean.FALSE); 
      isHidden =  false
  } 
   
   /* (non-Javadoc) 
   * @see javax.swing.JInternalFrame#updateUI() 
   */
 
   public  void updateUI() { 
       super.updateUI(); 
       if (isHidden) { 
        hideNorthPanel(); 
      } 
  } 
}
 
InnerFrame类继承自JInternalFrame,由于JInternalFrame没有对于窗口最大化事件的监听。所以,我们把它添加了一个ComponentListener。当组件大小改变时,调用componentResized方法,然后在这里判断如果组件大小是isMaximum()的,则将NorthPane隐藏掉。这里的JInternalFrame的NorthPane就是绘有关闭按钮的那一条面板。由于定义了hideNorthPane()和showNorthPane()这两个方法,是得我们对于InnerFrame的控制加强了。
 
修改后的完整代码如下所示:
 
import java.awt.BorderLayout; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import java.beans.PropertyVetoException; 

import javax.swing.JButton; 
import javax.swing.JDesktopPane; 
import javax.swing.JFrame; 
import javax.swing.JInternalFrame; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.plaf.basic.BasicInternalFrameUI; 

/** 
* MDIFrame is a frame using JInternalFrame to implements MDI as Word on Windows. 
*  
* @author Cheng 
* @version 1.0.0 for GPF MDI test 
*/
 
@SuppressWarnings( "serial"
public  class MDIFrame  extends JFrame { 
  
     /** The desktop pane. */ 
     final JDesktopPane desktopPane =  new JDesktopPane(); 
  
     /** The operation pane with restore and close buttons. */ 
     final JPanel opPane =  new JPanel(); 
  
     /** 
     * Instantiates a new mDI frame. 
     */
 
     public MDIFrame(){ 
      setTitle( "MDI Frame"); 
      setSize(600, 550); 
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
   
       final JMenuBar bar =  new JMenuBar(); 
      JMenuItem exit =  new JMenuItem( "Exit"); 
          exit.addActionListener( new ActionListener(){ 

              @Override 
               public  void actionPerformed(ActionEvent e) { 
                   System.exit(0); 
              } 
    
      }); 
      bar.add(exit); 
       // operation pane with two button, set invisible at first 
      opPane.setLayout( new FlowLayout(FlowLayout.TRAILING)); 
      JButton restore =  new JButton( "#"); 
      restore.setMargin( new Insets(0, 0, 0, 0)); 
      restore.setPreferredSize( new Dimension(15, 15)); 
      restore.addActionListener( new ActionListener(){ 

      @Override 
       public  void actionPerformed(ActionEvent e) { 
            InnerFrame i = (InnerFrame)desktopPane.getSelectedFrame(); 
             try { 
                 // notice this method, when JInternalFrame set maximun false
                 // this internal frame will be set as old size 
                i.setMaximum( false); 
            }  catch (PropertyVetoException ex) { 
                ex.printStackTrace(); 
            } 
            i.showNorthPanel(); 
            opPane.setVisible( false); 
          } 
    
      }); 
      opPane.add(restore); 
      JButton close =  new JButton( "X"); 
      close.setMargin( new Insets(0, 0, 0, 0)); 
      close.setPreferredSize( new Dimension(15, 15)); 
      close.addActionListener( new ActionListener(){ 

          @Override 
           public  void actionPerformed(ActionEvent e) { 
            JInternalFrame i = desktopPane.getSelectedFrame(); 
            i.dispose(); 
            opPane.setVisible( false); 
          } 
    
      }); 
      opPane.add(close); 
      bar.add(opPane); 
      opPane.setVisible( false); 
      setJMenuBar(bar); 
   
      Container content = getContentPane(); 
      content.add(desktopPane, BorderLayout.CENTER); 
       final JPanel ctrlPane =  new JPanel(); 
      JButton add =  new JButton( "add"); 
      add.addActionListener( new ActionListener(){ 

          @Override 
           public  void actionPerformed(ActionEvent e) { 
              InnerFrame iFrame =  new InnerFrame(); 
              iFrame.setVisible( true); 
              desktopPane.add(iFrame); 
          } 
    
      }); 
      ctrlPane.add(add); 
      content.add(ctrlPane, BorderLayout.SOUTH); 
      setVisible( true); 
    } 
  
     /** 
     * The Class InnerFrame. 
     */
 
     class InnerFrame  extends JInternalFrame { 
   
       /** The is hidden. */ 
       boolean isHidden =  false
   
       /** The old ui. */ 
      BasicInternalFrameUI oldUi =  null
   
       /** 
       * Instantiates a new inner frame. 
       */
 
       public InnerFrame() { 
          oldUi = (BasicInternalFrameUI)getUI(); 
          setSize(200, 200); 
          maximizable =  true
          closable =  true
          addComponentListener( new ComponentAdapter() { 
               public  void componentResized(ComponentEvent e) { 
                  InnerFrame selectedFrame = (InnerFrame)e.getSource(); 
                   if(selectedFrame.isMaximum()){ 
                      selectedFrame.hideNorthPanel(); 
                      opPane.setVisible( true); 
                       try { 
                           selectedFrame.setMaximum( true); 
                      }  catch (PropertyVetoException ex) { 
                           ex.printStackTrace(); 
                       } 
                   } 
               } 
          }); 
      } 
   
       /** 
       * Hide north panel. 
       */
 
       public  void hideNorthPanel(){ 
          ((BasicInternalFrameUI)  this.getUI()).setNorthPane( null); 
           this.putClientProperty( "JInternalFrame.isPalette", Boolean.TRUE); 
          isHidden =  true
      } 
   
       /** 
       * Show north panel. 
       */
 
       public  void showNorthPanel() { 
           this.setUI(oldUi); 
           this.putClientProperty( "JInternalFrame.isPalette", Boolean.FALSE); 
          isHidden =  false
      } 
   
       /* (non-Javadoc) 
       * @see javax.swing.JInternalFrame#updateUI() 
       */
 
       public  void updateUI() { 
           super.updateUI(); 
           if (isHidden) { 
              hideNorthPanel(); 
          } 
       } 
    } 
  
     /** 
     * The main method. 
     *  
     * @param args the arguments 
     */
 
     public  static  void main(String[] args) { 
          SwingUtilities.invokeLater( new Runnable(){ 

              @Override 
               public  void run() { 
                    new MDIFrame(); 
              } 
    
          }); 
     } 

 
修改之后的最大化可以是如图样子:
 
 
当然,按钮之类的很难看,不过修改那个的话就是很容易的了,在这里不再赘述。
 
本程序代码在Java 6 下编译通过。由于Java文件不允许上传,所以将后缀名改为txt,编译时请将文件名改为MDIFrame.java即可。