[JAVA學習]JInternalFrame實現MDI

本文轉載自:[選文出處](http://devbean.blog.51cto.com/448512/92426%20%E5%8E%9F%E6%96%87%E5%87%BA%E5%A4%84)

聲明:本文章中介紹的內容可以在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的實現。我們可以看到它的運行截圖如下所示:
這裏寫圖片描述


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(); 
              } 

          }); 
     } 
} 

修改之後的最大化可以是如圖樣子:
修改後最大化示例

本文出自 “豆子空間” 博客,請務必保留此出處 http://devbean.blog.51cto.com/448512/92426

感謝豆子大佬的細心講解~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章