import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane1 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JScrollPane1();
}
public JScrollPane1() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JFrame Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
//cp.setLayout(null); //不要自行排版, 用預設 BorderLayout
//Build Elements
JLabel picture=new JLabel(new ImageIcon("cat.jpg")); //內容為圖片之 JLabel
cp.add(picture,BorderLayout.CENTER); //JLabel 直接放入內容面板
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
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);}
}
}
小時候天真無邪的樣子
可見只有局部圖片能顯示於 JFrame 視窗中, 當然, 只要調整 JFrame 大小就可以看到整個圖片了, 但如果 JFrame 設定成不可調整呢? 或者圖片很大, 即使 JFrame 放到最大仍然小於圖檔大小, 那就無論如何也無法看到全貌了. 這時只要使用 JScrollPane 的建構子, 將 JLable 先放進 JScrollPane, 再放進內容面板即可 :
JScrollPane(Component view)
如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane2 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JScrollPane2();
}
public JScrollPane2() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
//cp.setLayout(null);
//Build Elements
JLabel picture=new JLabel(new ImageIcon("cat.jpg"));
JScrollPane jsp=new JScrollPane(picture); //JLabel 放入 JScrollPane
cp.add(jsp,BorderLayout.CENTER);
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
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);}
}
}
可見當圖片大小大於視窗容器時, 就會自動出現捲動軸.
JScrollPane 類別主要是由 JViewPort 與 JScrollBar 兩個物件實體組成 (還有標題與轉角等元件), JViewPort 是容器, 用來裝要呈現的元件內容, 後者是用在當內容比 JViewPort 容器還大時, 在右邊或底邊裝上捲軸以便使用者捲動內容. 當移動捲軸時, JScrollPane 會自動處理捲軸事件來移動視圖, 我們不需要特別去處理.
從建構子可知, JScrollPane 面板只能放一個元件, 而且它有自己的版面管理員, 我們無法改變. 如果要放多個元件, 可以先放到 JPanel 中, 可指定所要的版面管理員, 再把 JPanel 放進 JScrollPane 即可.
其 API 參考 :
# http://docs.oracle.com/javase/7/docs/api/
# http://docs.oracle.com/javase/7/docs/api/javax/swing/JScrollPane.html
產生捲軸面板是利用其建構子, 上面範例所使用的建構子是只有一個傳入參數, 即要顯示的元件 JLabel, 我們也可以先用無參數建構子 JScrollPane(), 然後再呼叫 setViewportView() 方法設定 JViewport 的內容, 如下範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane3 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JScrollPane3();
}
public JScrollPane3() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
//cp.setLayout(null);
//Build Elements
JLabel picture=new JLabel(new ImageIcon("cat.jpg"));
JScrollPane jsp=new JScrollPane(); //先呼叫無參數建構子
jsp.setViewportView(picture); //再將 JLabel 放入 viewport
cp.add(jsp,BorderLayout.CENTER);
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
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);}
}
}
除了上述兩個建構子外, JScrollPane 還有兩個建構子 :
JScrollPane(Component view, int vsbPolicy, int hsbPolicy)
JScrollPane(int vsbPolicy, int hsbPolicy)
其中 hsbPolicy 參數水平捲軸的顯示政策, 其值如下 :
- JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS(=32)
- JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED(=31, 預設)
- JScrollPane.HORIZONTAL_SCROLLBAR_NEVER(=30)
- JScrollPane.VERTICAL_SCROLLBAR_ALWAYS(=22)
- JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED(=21, 預設)
- JScrollPane.VERTICAL_SCROLLBAR_NEVER(=20)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane4 implements ActionListener {
JFrame f;
JScrollPane jsp;
public static void main(String argv[]) {
new JScrollPane4();
}
public JScrollPane4() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
//cp.setLayout(null);
//Build Elements
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("需要時顯示垂直捲軸");
btn.addActionListener(this);
panel.add(btn);
btn=new JButton("顯示水平捲軸");
btn.addActionListener(this);
panel.add(btn);
btn=new JButton("不顯示水平捲軸");
btn.addActionListener(this);
panel.add(btn);
btn=new JButton("需要時顯示水平捲軸");
btn.addActionListener(this);
panel.add(btn);
cp.add(panel,BorderLayout.WEST); //JPanel 放在左方
JLabel picture=new JLabel(img);
jsp=new JScrollPane(picture); //JLabel 放入 JScrollPane
cp.add(jsp,BorderLayout.CENTER); //JScrollPane 放在中央
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
String cmd=e.getActionCommand();
if (cmd.equals("顯示垂直捲軸")) {
int policy=JScrollPane.VERTICAL_SCROLLBAR_ALWAYS;
jsp.setVerticalScrollBarPolicy(policy);
}
if (cmd.equals("不顯示垂直捲軸")) {
int policy=JScrollPane.VERTICAL_SCROLLBAR_NEVER;
jsp.setVerticalScrollBarPolicy(policy);
}
if (cmd.equals("需要時顯示垂直捲軸")) {
int policy=JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED;
jsp.setVerticalScrollBarPolicy(policy);
}
if (cmd.equals("顯示水平捲軸")) {
int policy=JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS;
jsp.setHorizontalScrollBarPolicy(policy);
}
if (cmd.equals("不顯示水平捲軸")) {
int policy=JScrollPane.HORIZONTAL_SCROLLBAR_NEVER;
jsp.setHorizontalScrollBarPolicy(policy);
}
if (cmd.equals("需要時顯示水平捲軸")) {
int policy=JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED;
jsp.setHorizontalScrollBarPolicy(policy);
}
jsp.revalidate(); //重整捲軸面板
}
}
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);}
}
}
此例中六個按鈕都註冊了動作事件, 放進 GridLayout 的 JPanel 中, 然後呼叫 JScrollPane 的 setVerticalScrollBarPolicy() 或 setHorizontalScrollBarPolicy() 方法去設定捲軸政策, 由於要在 actionPerform() 方法中存取 JScrollPane 物件, 因此要將其宣告為類別成員. 要注意的是, 更改了捲軸政策後, 必須呼叫 revalidate() 方法才會生效, 此方法繼承自 JComponent 類別.
JScrollPane 除了 JViewport 與 JScrollBar 物件外, 還包括左方的列標頭 (row header), 上方的欄標頭 (column header), 以及四個邊角. 其架構如下 (取自 Java 文件) :
現在就來測試如何加上列標題與欄標題, 最常用的就是加上尺規. 根據下列 API 文件的說明, 需要下載 Rule.java 這個類別來產生尺規 :
# Using Swing Components: Examples
# http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html
但是這個 Rule.java 必須加以修改, 拿掉第一行的 package 宣告, 存檔後編譯即可. 然後就可以建立水平與垂直的 Rule 物件, 並利用 setColumnHeaderView() 與 setRowHeaderView() 方法將其加入 JScrollPane 中, 如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane5 implements ActionListener {
JFrame f;
JScrollPane jsp;
public static void main(String argv[]) {
new JScrollPane5();
}
public JScrollPane5() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
//cp.setLayout(null);
//Build Elements
ImageIcon img=new ImageIcon("cat.jpg");
JLabel picture=new JLabel(img);
jsp=new JScrollPane(picture); //JLabel 放入 JScrollPane
jsp.setPreferredSize(new Dimension(400, 300));
Rule columnView=new Rule(Rule.HORIZONTAL, true); //建立欄尺規
Rule rowView=new Rule(Rule.VERTICAL, true); //建立列尺規
columnView.setPreferredWidth(img.getIconWidth()); //設定欄尺規寬度
rowView.setPreferredHeight(img.getIconHeight()); //設定列尺規高度
jsp.setColumnHeaderView(columnView); //加上欄尺規
jsp.setRowHeaderView(rowView); //加上列尺規
cp.add(jsp,BorderLayout.CENTER); //JScrollPane 放在中央
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
String cmd=e.getActionCommand();
}
}
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);}
}
}
在此例中, 使用 ImageIcon 的 getIconWidth() 與 getIconHeight() 分別取得圖片的寬與高, 以便設定欄尺規的寬度與列尺規的高度, 這是必要的, 否則尺規不會顯現. 這個尺規預設是以公分為單位的, 在 Rule.java 類別中, setIsMetric() 方法會呼叫 setIncrementAndUnits() 方法將公分與英寸進行換算, 因此只要呼叫 setIsMetric 就可以了.
Java 文件的範例是在左上角的 corner 放一個 JToggleButton 來切換, 只要呼叫 JScrollPane 的 setCorner() 方法就可以在 JScrollPane 的四個邊角放置元件, 此方法須傳入兩個參數 :
setCorner(String key, Component corner)
第一個參數為一個表示邊角位置的字串常數, 有如下四個 :
- ScrollPaneConstants.LOWER_LEFT_CORNER
- ScrollPaneConstants.LOWER_RIGHT_CORNER
- ScrollPaneConstants.UPPER_LEFT_CORNER
- ScrollPaneConstants.UPPER_RIGHT_CORNER
第二個參數就是要放到邊角的元件, 此處是一個 JToggleButton 元件.
如下範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane6 implements ItemListener {
JFrame f;
JScrollPane jsp;
Rule columnView;
Rule rowView;
public static void main(String argv[]) {
new JScrollPane6();
}
public JScrollPane6() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
//cp.setLayout(null);
//Build Elements
ImageIcon img=new ImageIcon("cat.jpg");
JLabel picture=new JLabel(img);
jsp=new JScrollPane(picture); //JLabel 放入 JScrollPane
jsp.setPreferredSize(new Dimension(400, 300));
//set Ruler
columnView=new Rule(Rule.HORIZONTAL, true); //建立欄尺規
rowView=new Rule(Rule.VERTICAL, true); //建立列尺規
columnView.setPreferredWidth(img.getIconWidth()); //設定欄尺規寬度
rowView.setPreferredHeight(img.getIconHeight()); //設定列尺規高度
jsp.setColumnHeaderView(columnView); //加上欄尺規
jsp.setRowHeaderView(rowView); //加上列尺規
//set corner
JToggleButton cmin=new JToggleButton("cm", true); //cm/in 切換按鈕
cmin.addItemListener(this); //註冊選項事件
jsp.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, cmin); //設定邊角
cp.add(jsp,BorderLayout.CENTER); //JScrollPane 放在中央
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void itemStateChanged(ItemEvent e) { //實作選項事件
if (e.getStateChange()==ItemEvent.SELECTED) { //切換為公制
rowView.setIsMetric(true);
columnView.setIsMetric(true);
}
else { //切換為英制
rowView.setIsMetric(false);
columnView.setIsMetric(false);
}
}
}
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);}
}
}
上圖為切換成英吋單位, 注意 JToggleButton 按鈕註冊的事件為 ItemAction, 所以必須實作 ItemActionListener. 如果按鈕被按下, 就將尺規物件設為公制 (cm), 否則設為英制 (in). 為了要在 Item 事件處理中存取尺規物件, 所以把 rowView 與 columnView 這兩個尺規物件改為類別成員.
最後, JScrollPane 還有一個最常用的場合, 就是配合 JList 一起使用. 在 AWT 中, List 元件的項目如果超過元件高度時會自動出現捲軸, 不需要使用 ScrollPane 物件; 但很奇怪的是, 到了 Swing 時代, JList 卻沒有這個功能了, 如下範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane7 {
JFrame f;
public static void main(String argv[]) {
new JScrollPane7();
}
public JScrollPane7() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(300,200);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(new GridLayout(1,2));
//Build Elements
String[] nations={
"美國 +1 United States of America",
"英國 +44 United Kindom",
"日本 +81 Japan",
"法國 +33 France",
"俄羅斯 +7 Russia",
"剛果 +243 Democratic Republic of Congo",
"赤道幾內亞 +240 Equatorial Guinea",
"蓋亞那 +592 Guyana",
"薩爾瓦多 +503 Elsalvador",
"委內瑞拉 +58 Venezuela"
};
String[] components={
"JList",
"JComponet",
"JButton",
"JTree",
"JFileChooser",
"JOptionPane",
"JInternalPane",
"JTable",
"JCheckBox",
"JComboBox"
};
JList<String> list1=new JList<String>(nations);
JList<String> list2=new JList<String>(components);
list1.setBorder(BorderFactory.createTitledBorder("國家"));
list2.setBorder(BorderFactory.createTitledBorder("元件"));
cp.add(list1);
cp.add(list2);
f.setVisible(true);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
}
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);}
}
}
可見寬度與高度超出的部分就看不到了, 也不會像 AWT 的 List 元件那樣自動加上捲軸, 當然, 只要視窗為可調整大小, 還是可以看到全部內容的. 注意, 這裡 JList 已經改用泛型重新定義了, 內容為字串要指定為 String.
JList 必須配合 JScrollPane 才會在項目太多或太長超過清單高度或寬度時出現捲軸, 如下面範例 所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JScrollPane8 {
JFrame f;
public static void main(String argv[]) {
new JScrollPane8();
}
public JScrollPane8() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JScrollPane Test");
f.setSize(300,200);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(new GridLayout(1,2));
//Build Elements
String[] nations={
"美國 +1 United States of America",
"英國 +44 United Kindom",
"日本 +81 Japan",
"法國 +33 France",
"俄羅斯 +7 Russia",
"剛果 +243 Democratic Republic of Congo",
"赤道幾內亞 +240 Equatorial Guinea",
"蓋亞那 +592 Guyana",
"薩爾瓦多 +503 Elsalvador",
"委內瑞拉 +58 Venezuela"
};
String[] components={
"JList",
"JComponet",
"JButton",
"JTree",
"JFileChooser",
"JOptionPane",
"JInternalPane",
"JTable",
"JCheckBox",
"JComboBox"
};
JList<String> list1=new JList<String>(nations);
JList<String> list2=new JList<String>(components);
list1.setBorder(BorderFactory.createTitledBorder("國家"));
list2.setBorder(BorderFactory.createTitledBorder("元件"));
cp.add(new JScrollPane(list1));
cp.add(new JScrollPane(list2));
f.setVisible(true);
f.pack(); //不是自行排版要加上 pack()
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
}
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);}
}
}
當資料過長時, JScrollPane 就會適時加上捲軸. 總之, 如果要確保使用者能看到全部資料, 就把元件用 JScrollPane 包起來就行了.
1 則留言 :
您好 我想請問一下 我自己在練習
jLabel 為何會顯示null 一開始輸入可以正確,可是清除資料後 在輸入 label就會顯示null 為什麼呢?
是不是要先把資料初始化?
張貼留言