2014年5月23日 星期五

Java Swing 測試 : 頁籤面板 JTabbedPane

頁籤面板 JTabbedPane 的功能類似活頁夾的分類頁籤, 可以將複雜的系統元件依功能分類放在不同頁籤, 使整個版面乾淨清楚, 亦於操作. 我在設計網頁時對這種版面設計情有獨鍾, 不管是 jQuery 還是 ExtJS 都有提供.

JTabbedPane 之 API 參考 :

http://docs.oracle.com/javase/7/docs/api/
# JTabbedPane

JTabbedPane 的建構子只有三個 :
  1. JTabbedPane() :
    預設頁籤在上方
  2. JTabbedPane(int tabPlacement) :
    可指定頁籤位置 :
    JTabbedPane.TOP (預設)
    JTabbedPane.BOTTOM
    JTabbedPane.LEFT
    JTabbedPane.RIGHT
  3. JTabbedPane(int tabPlacement, int layoutPolicy) :
    可指定頁籤布局方式 :
    JTabbedPane.WRAP_TAB_LAYOUT : 頁籤超出容器時跳行顯示 (預設)
    JTabbedPane.SCROLL_TAB_LAYOUT : 頁籤超出容器時用捲軸顯示
位置常數也可以使用 SwingConstants.TOP/BOTTOM/LEFT/RIGHT.
如果使用無參數建構子, 可以用 setTabPlacement() 與 setTabLayoutPolicy() 方法分別設定頁籤位置與布局方式. 欲加入頁籤需用 addTab() 方法 :

addTab(String title, Component component) 
addTab(String title, Icon icon, Component component)
addTab(String title, Icon icon, Component component, String tip)

第一參數為頁籤標題, 第二參數為要加入頁籤之元件. JTabbedPane 每一個頁籤只能加入一個元件, 如果要加入多個元件, 可先放入 JPanel 中包起來, 再將 JPanel 放入頁籤中.

刪除頁籤使用 remove() 方法, 有兩個多載 :

remove(int index) 

傳入參數為 0 起始的頁籤索引. 另一個是傳入參數為頁籤中的元件 :

remove(Component component)

JTabbedPane 切換頁籤為 Change 事件, 若要捕捉此事件需實作 ChangeListener 介面, 並覆寫 stateChanged() 方法. 欲取得目前顯示之頁籤, 可呼叫 getSelectedIndex() 方法.

在下列範例中, 我使用了兩個頁籤來顯示圖片, 並且實作 ChangeListener 來捕捉 Change 事件, 在 JLabel 中顯示目前 active 的頁籤名稱, 程式碼如下 :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class JTabbedPane1 implements ChangeListener {
  JFrame f;
  JLabel currentTab;
  public static void main(String argv[]) {
    new JTabbedPane1();
    }
  public JTabbedPane1() {
    //Setup JFrame
    JFrame.setDefaultLookAndFeelDecorated(true);
    JDialog.setDefaultLookAndFeelDecorated(true);
    f=new JFrame("JTabbedPane Test");
    f.setSize(400,300);
    f.setLocationRelativeTo(null);
    Container cp=f.getContentPane();

    //Build Elements
    JTabbedPane tp=new JTabbedPane();
    JLabel label1=new JLabel(new ImageIcon("cat.jpg"));
    JLabel label2=new JLabel(new ImageIcon("family.jpg"));
    tp.addTab("小時候天真無邪的樣子", new JScrollPane(label1));
    tp.addTab("小狐狸全家福", new JScrollPane(label2));
    tp.addChangeListener(this);
    cp.add(tp,BorderLayout.CENTER);
    currentTab=new JLabel("目前頁籤 : [0]小時候天真無邪的樣子");
    cp.add(currentTab,BorderLayout.SOUTH);
    f.setVisible(true);

    //Close JFrame      
    f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    f.addWindowListener(new WindowHandler(f));
    }
  public void stateChanged(ChangeEvent e) {
    JTabbedPane tb=(JTabbedPane) e.getSource();
    int index=tb.getSelectedIndex();
    String msg="目前頁籤 : [" + index + "]" + tb.getTitleAt(index);
    currentTab.setText(msg);
    }
  }
class WindowHandler extends WindowAdapter {
  JFrame f;
  public WindowHandler(JFrame f) {this.f=f;}
  public void windowClosing(WindowEvent e) {
    int result=JOptionPane.showConfirmDialog(f,
               "確定要結束程式嗎?",
               "確認訊息",
               JOptionPane.YES_NO_OPTION,
               JOptionPane.WARNING_MESSAGE);
    if (result==JOptionPane.YES_OPTION) {System.exit(0);}
    }  
  }

可見只要切換頁籤, 底下的 JLabel 就會顯示目前的頁籤標題, 這是利用呼叫 getSelectedIndex() 所取得的目前頁籤索引當參數, 再呼叫 getTitleAt() 方法得到的.

其次我們來測試頁籤位置切換方法 setTabPlacement(int place), 我們修改上面範例, 添加四個按鈕來切換頁籤位置, 程式碼如下 :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class JTabbedPane2 implements ChangeListener,ActionListener {
  JFrame f;
  JLabel currentTab;
  JTabbedPane tp;
  public static void main(String argv[]) {
    new JTabbedPane2();
    }
  public JTabbedPane2() {
    //Setup JFrame
    JFrame.setDefaultLookAndFeelDecorated(true);
    JDialog.setDefaultLookAndFeelDecorated(true);
    f=new JFrame("JTabbedPane Test");
    f.setSize(400,300);
    f.setLocationRelativeTo(null);
    Container cp=f.getContentPane();

    //Build Elements
    tp=new JTabbedPane();
    JLabel label1=new JLabel(new ImageIcon("cat.jpg"));
    JLabel label2=new JLabel(new ImageIcon("family.jpg"));
    tp.addTab("小時候天真無邪的樣子", new JScrollPane(label1));
    tp.addTab("小狐狸全家福", new JScrollPane(label2));
    tp.addChangeListener(this);
    cp.add(tp,BorderLayout.CENTER);
    //Add JLabel : currentTab
    currentTab=new JLabel("目前頁籤 : [0]小時候天真無邪的樣子");
    cp.add(currentTab,BorderLayout.SOUTH);
    //Add placement button
    JPanel panel=new JPanel(new GridLayout(4,1));
    JButton btn=new JButton("TOP");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("BOTTOM");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("LEFT");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("RIGHT");
    btn.addActionListener(this);
    panel.add(btn);
    cp.add(panel,BorderLayout.WEST);
    f.setVisible(true);

    //Close JFrame      
    f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    f.addWindowListener(new WindowHandler(f));
    }
  public void stateChanged(ChangeEvent e) {
    JTabbedPane tb=(JTabbedPane) e.getSource();
    int index=tb.getSelectedIndex();
    String msg="目前頁籤 : [" + index + "]" + tb.getTitleAt(index);
    currentTab.setText(msg);
    }
  public void actionPerformed(ActionEvent e) {
    String cmd=e.getActionCommand();
    if (cmd.equals("TOP")) {tp.setTabPlacement(JTabbedPane.TOP);}
    if (cmd.equals("BOTTOM")) {tp.setTabPlacement(JTabbedPane.BOTTOM);}
    if (cmd.equals("LEFT")) {tp.setTabPlacement(JTabbedPane.LEFT);}
    if (cmd.equals("RIGHT")) {tp.setTabPlacement(JTabbedPane.RIGHT);}
    }
  }
class WindowHandler extends WindowAdapter {
  JFrame f;
  public WindowHandler(JFrame f) {this.f=f;}
  public void windowClosing(WindowEvent e) {
    int result=JOptionPane.showConfirmDialog(f,
               "確定要結束程式嗎?",
               "確認訊息",
               JOptionPane.YES_NO_OPTION,
               JOptionPane.WARNING_MESSAGE);
    if (result==JOptionPane.YES_OPTION) {System.exit(0);}
    }  
  }

此例中因為要在動作事件處理中存取 JTabbedPane, 所以須將其宣告為類別成員.

頁籤標題除了文字外, 還可以加上圖示與提示文字 (Tool Tip), 這可在 addTab() 方法中設定, 或者用 setIconAt() 與 setToolTipTextAt() 方法. 在下面範例中, 我們在左方版面放置按鈕來新增與刪除頁籤, 以及更改頁籤的布局方式, 程式碼如下 :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class JTabbedPane3 implements ChangeListener,ActionListener {
  JFrame f;
  JLabel currentTab;
  JTabbedPane tp;
  int tabid=0;
  public static void main(String argv[]) {
    new JTabbedPane3();
    }
  public JTabbedPane3() {
    //Setup JFrame
    JFrame.setDefaultLookAndFeelDecorated(true);
    JDialog.setDefaultLookAndFeelDecorated(true);
    f=new JFrame("JTabbedPane Test");
    f.setSize(400,300);
    f.setLocationRelativeTo(null);
    Container cp=f.getContentPane();

    //Build Elements
    tp=new JTabbedPane();
    tp.addChangeListener(this);
    cp.add(tp,BorderLayout.CENTER);
    //Add JLabel : currentTab
    currentTab=new JLabel("");
    cp.add(currentTab,BorderLayout.SOUTH);
    //Add placement button
    JPanel panel=new JPanel(new GridLayout(6,1));
    JButton btn=new JButton("新增頁籤");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("刪除頁籤");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("Enable");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("Disable");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("WRAP");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("SCROLL");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("TOP");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("BOTTOM");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("LEFT");
    btn.addActionListener(this);
    panel.add(btn);
    btn=new JButton("RIGHT");
    btn.addActionListener(this);
    panel.add(btn);
    cp.add(panel,BorderLayout.WEST);
    f.setVisible(true);

    //Close JFrame      
    f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    f.addWindowListener(new WindowHandler(f));
    }
  public void stateChanged(ChangeEvent e) {
    JTabbedPane tb=(JTabbedPane) e.getSource();  //亦可直接用 tp
    int index=tb.getSelectedIndex();
    String msg="合計 " + tp.getTabCount() + " 個頁籤 " +
               "目前頁籤 : " + tb.getTitleAt(index);
    currentTab.setText(msg);
    }
  public void actionPerformed(ActionEvent e) {
    String cmd=e.getActionCommand();
    if (cmd.equals("TOP")) {
      tp.setTabPlacement(JTabbedPane.TOP);
      }
    if (cmd.equals("BOTTOM")) {
      tp.setTabPlacement(JTabbedPane.BOTTOM);
      }
    if (cmd.equals("LEFT")) {
      tp.setTabPlacement(JTabbedPane.LEFT);
      }
    if (cmd.equals("RIGHT")) {
      tp.setTabPlacement(JTabbedPane.RIGHT);
      }
    if (cmd.equals("新增頁籤")) {
      String title="頁籤 " + tabid;
      tp.addTab(title,new JLabel(title, JLabel.CENTER));
      ++tabid;
      }
    if (cmd.equals("刪除頁籤")) {
      tp.remove(tp.getSelectedIndex());
      }
    if (cmd.equals("Enable")) {
      String id=JOptionPane.showInputDialog("請輸入頁籤編號");
      tp.setEnabledAt(tp.indexOfTab("頁籤 " + id),true);
      }
    if (cmd.equals("Disable")) {
      tp.setEnabledAt(tp.getSelectedIndex(),false);
      }
    if (cmd.equals("WRAP")) {
      tp.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
      }
    if (cmd.equals("SCROLL")) {
      tp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
      }
    }
  }
class WindowHandler extends WindowAdapter {
  JFrame f;
  public WindowHandler(JFrame f) {this.f=f;}
  public void windowClosing(WindowEvent e) {
    int result=JOptionPane.showConfirmDialog(f,
               "確定要結束程式嗎?",
               "確認訊息",
               JOptionPane.YES_NO_OPTION,
               JOptionPane.WARNING_MESSAGE);
    if (result==JOptionPane.YES_OPTION) {System.exit(0);}
    }  
  }



當按下 Disable 鈕時, 目前頁籤會變成不可用, 也無法選取, 因此按 Enable 時會彈出輸入盒要求輸入頁籤編號, 組成頁籤標題後呼叫 indexOfTab() 取得其索引, 再呼叫 setEnabledAt() 方法使其變成可用. 頁籤布局預設是 WRAP_TAB_LAYOUT, 按 SCROLL 鈕會使頁籤變成一排, 並出現向前向後的小按鈕, 類似捲軸的功用.

沒有留言 :