第12章 轻量容器
本章讨论如下Swing轻量容器: ·JPanel ·JRootPane ·JLayeredPane ·JTabbedPane ·JSplitPane JPanel是AWT的Canvas和Panel类的继承类。文本和图形都可以绘制到JPanel实例中,并且JPanel实例可以用作一个通用容器。 JRootPane是一个包含在窗体、对话框、窗口、内部窗体和Swing小应用程序等Swing顶层容器中的容器。 JLayeredPane允许把它所包含的组件放置在不同的层中。层控制显示组件的深度。 JTabbedPane是一个能够包含多个组件的容器。JTabbedPane包含的多个组件一次只能显示一个。JTabbedPane的实例包含能够用于选取当前显示的组件的选项卡。 JSplitPane包含两个组件,这两个组件由一个分隔体所分隔。可以拖动分隔体以改变每个组件所占据的空间大小。
12.1 JPanel
JPanel是最简单的Swing组件之一;但它也是使用最多的组件之一。Swing在很多其他组件中使用了JPanel实例;例如,缺省时,JRootPane容器为它的内容窗格和玻璃窗格创建了JPanel实例,正如表12-1所反映的那样。 JPanel类具有简单容器显示图形的画布的双重功能。图12-1示出的小应用程序创建了三个JPanel实例:一个包含“Name:”选项卡和文本域的控制面板、一个专门用作显示文本和图形的画布的窗格,以及包含上述控制面板和画面的第三个面板。 例12-1中列出了图12-1中示出的小应用程序的代码。
例12-1 一个使用了三个JPanel实例的小应用程序
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JApplet {
public Test() {
Container contentPane = getContentPane();
JPanel panel = new JPanel(new BorderLayout());
JPanel controlPanel = new JPanel();
JPanel canvas = new Canvas();
canvas.setBorder(
BorderFactory.createLineBorder(Color.black));
controlPanel.add(new JLabel("Name:"));
controlPanel.add(new JTextField(20));
panel.add(controlPanel, BorderLayout.NORTH);
panel.add(canvas, BorderLayout.CENTER);
contentPane.add(panel);
}
}
class Canvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = getSize();
g.setColor(Color.black);
g.drawLine(50,50,size.width,size.height);
g.drawArc(20,40,25,25,0,290);
g.drawString("A JPanel Used as a Canvas", 20, 20);
}
}
12.1.1 JPanel的属性
12.1.2 JPanel的事件
12.1.3 JPanel类总结
12.1.4 AWT兼容
12.2 JRootPane
12.2.1 RootPaneContainer接口
12.2.2玻璃空格
例12-2 玻璃窗格测试小应用程序
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { private Component glassPane = new CustomGlassPane();
public void init() { JRadioButton rb = new JRadioButton(); JButton button = new JButton("show glass pane"); Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout()); contentPane.add(button);
rb.setIcon(new ImageIcon("duke_standing.gif")); rb.setRolloverIcon(new ImageIcon("duke_waving.gif"));
setGlassPane(glassPane); contentPane.add(rb);
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { glassPane.setVisible(true); } }); } } class CustomGlassPane extends JPanel { private JButton button; private String displayString = "glass pane ... ";
public CustomGlassPane() { addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { setVisible(false); } }); } public void paintComponent(Graphics g) { Dimension size = getSize(); FontMetrics fm = g.getFontMetrics(); int sw = fm.stringWidth(displayString); int fh = fm.getHeight();
g.setColor(Color.blue);
for(int row=fh; row < size.height; row += fh) for(int col=0; col < size.width; col += sw) g.drawString(displayString, col, row); } }
12.2.3内容窗格
例12-3 一个定制的内容窗格
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class ContentPaneTest extends JApplet { private JButton button = new JButton("show glass pane");
public void init() { setGlassPane(new CustomGlassPane(button)); setContentPane(new CustomContentPane(button));
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { getGlassPane().setVisible(true); } }); } } class CustomContentPane extends JPanel { private ImageIcon rain = new ImageIcon("rain.gif"); private ImageIcon punch = new ImageIcon("punch.gif"); private int rainw = rain.getIconWidth(); private int rainh = rain.getIconHeight();
public CustomContentPane(JButton button) { add(button); add(new JLabel("I'm a JLabel in the Content Pane", punch, SwingConstants.RIGHT)); } public void paintComponent(Graphics g) { Dimension size = getSize();
for(int row=0; row < size.height; row += rainh) for(int col=0; col < size.width; col += rainw) rain.paintIcon(this,g,col,row); } } class CustomGlassPane extends JPanel { private JButton button; private Point ulhc = new Point(20,20), last; private String displayString = "I'm on the glass pane - drag me around!";
public CustomGlassPane(JButton b) { button = b;
setOpaque(false); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { last = e.getPoint(); } public void mouseReleased(MouseEvent e) { setVisible(false); } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { Point drag = e.getPoint(); ulhc.x += drag.x - last.x; ulhc.y += drag.y - last.y;
repaint();
last.x = drag.x; last.y = drag.y; } }); } public void paintComponent(Graphics g) { FontMetrics fm = g.getFontMetrics(); int sw = fm.stringWidth(displayString); int sh = fm.getHeight(); int ascent = fm.getAscent();
g.drawRect(ulhc.x, ulhc.y, sw + 10, sh + 10); g.drawString(displayString, ulhc.x + 5, ulhc.y + ascent + 5); } }
12.2.4 JRootPane属性
12.2.5 JRootPane事件
例12-4 一个传递事件的玻璃窗格
import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; import javax.swing.text.*;
public class Test extends JApplet { Component glassPane = new AnnotationPane(); JCheckBox annotations = new JCheckBox("annotations");
public void init() { createContainerHierarchy(); setupGlassPane(); } private void createContainerHierarchy() { Container contentPane = getContentPane();
JPanel controlPanel = new JPanel(); JTextArea textArea = new JTextArea(); JScrollPane scrollPane = new JScrollPane(textArea);
readFile(textArea.getDocument());
controlPanel.add(annotations);
contentPane.add(scrollPane, "Center"); // scroll pane contentPane.add(controlPanel, "South"); // panel
textArea.addMouseListener(new MouseAdapter() { public void mouseEntered(MouseEvent e) { System.out.println("enter"); } }); } private void setupGlassPane() { setGlassPane(glassPane); annotations.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if(e.getStateChange() == ItemEvent.SELECTED) glassPane.setVisible(true); else glassPane.setVisible(false); } }); } private void readFile(Document doc) { try { Reader in = new FileReader("Test.java"); char[] buff = new char[4096]; int next;
while ((next = in.read(buff, 0, buff.length)) != -1) doc.insertString( doc.getLength(), new String(buff, 0, next), null); } catch(Exception e) { System.out.println("interruption"); } } } class AnnotationPane extends JPanel { private Icon annotations[] = { new ImageIcon("annotation.gif"), new ImageIcon("annotation_1.gif"), new ImageIcon("annotation_2.gif") }; public void paintComponent(Graphics g) { annotations[0].paintIcon(this, g, 400, 50); annotations[1].paintIcon(this, g, 10, 150); annotations[2].paintIcon(this, g, 10, 265); } }
12.2.6 JRootPane类总结
12.2.7 AWT兼容
12.3 JLayoutPane
12.3.1回顾轻量组件的层序
例12-5 添加到一个内容窗格中的按钮的程序
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { Container cp = getContentPane();
private final Component[] comps = { new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), }; public void init() { cp.setLayout(null);
for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i]; cp.add(button);
String t = "Button #";
t += i + " Index: " + getIndexOf(button);
button.setText(t); button.setBounds(i*50, i*50, 350, 75); System.out.println("Adding: " + button.getText()); } } private int getIndexOf(Component button) { int ncomponents = cp.getComponentCount();
for(int i=0; i < ncomponents; ++i) { Component c = cp.getComponent(i); if(button == c) return i; } return -1; } }
12.3.2为组件分配器
例12-6 所包含在一个分层窗格中的组件分配到层中
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { private JLayeredPane lp = new JLayeredPane();
private Integer[] layers = { JLayeredPane.FRAME_CONTENT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.PALETTE_LAYER, JLayeredPane.MODAL_LAYER, JLayeredPane.POPUP_LAYER, JLayeredPane.DRAG_LAYER, }; private final Component[] comps = { new JButton("Frame Content"), new JButton("Default"), new JButton("Palette"), new JButton("Modal"), new JButton("Popup"), new JButton("Drag"), }; public void init() { setContentPane(lp); lp.setLayout(null);
for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i];
System.out.println("Adding: " + button.getText());
lp.setLayer(button, layers[i].intValue()); lp.add(button); } for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i]; String t = button.getText(); String replacement = new String("Layer: ");
replacement += t + "(" + lp.getLayer(button) + "),"; replacement += " Index: " + lp.getIndexOf(button);
button.setText(replacement); button.setBounds(i*50, i*50, 350, 75); } } }
12.3.3指定同一层中组件的位置
例12-7 同一层中放置组件的缺省方式
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { private JLayeredPane lp = new JLayeredPane();
private Integer[] layers = { JLayeredPane.FRAME_CONTENT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.PALETTE_LAYER, JLayeredPane.MODAL_LAYER, JLayeredPane.POPUP_LAYER, JLayeredPane.DRAG_LAYER, }; private final Component[] comps = { new JButton("Frame Content"), new JButton("Default"), new JButton("default 1"), new JButton("default 2"), new JButton("Palette"), new JButton("Modal"), new JButton("Popup"), new JButton("Drag"), }; public void init() { setContentPane(lp); lp.setLayout(null);
for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i];
lp.setLayer(button, layers[i].intValue()); lp.add(button); } for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i]; String t = button.getText(); String replacement = new String("Layer: ");
replacement += t + "(" + lp.getLayer(button) + "),"; replacement += " Index: " + lp.getIndexOf(button); replacement += " Position: " + lp.getPosition(button);
button.setText(replacement); button.setBounds(i*50, i*50, 350, 75); } } }
例12-8 显式地设置同层中组件的位置
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { private JLayeredPane lp = new JLayeredPane();
private Integer[] layers = { JLayeredPane.FRAME_CONTENT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.DEFAULT_LAYER, JLayeredPane.PALETTE_LAYER, JLayeredPane.MODAL_LAYER, JLayeredPane.POPUP_LAYER, JLayeredPane.DRAG_LAYER, }; private final Component[] comps = { new JButton("Frame Content"), new JButton("Default"), new JButton("default 1"), new JButton("default 2"), new JButton("Palette"), new JButton("Modal"), new JButton("Popup"), new JButton("Drag"), }; public void init() { setContentPane(lp); lp.setLayout(null);
for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i]; String t = button.getText();
lp.setLayer(button, layers[i].intValue()); lp.add(button); } for(int i=0; i < comps.length; ++i) { AbstractButton button = (AbstractButton)comps[i]; String t = button.getText(); String replacement = new String("Layer: ");
if(t.equals("Default")) lp.setPosition(button, 2); else if(t.equals("default 2")) lp.setPosition(button, 0);
replacement += t + "(" + lp.getLayer(button) + "),"; replacement += " Index: " + lp.getIndexOf(button); replacement += " Position: " + lp.getPosition(button);
button.setText(replacement); button.setBounds(i*50, i*50, 350, 75); } } }
12.3.4使用拖动层
例12-9 使用拖动层
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { public void init() { setContentPane(new CustomContentPane()); } } class CustomContentPane extends JLayeredPane { private ImageIcon rain = new ImageIcon("rain.gif"); private ImageIcon punch = new ImageIcon("punch.gif"); private ImageIcon skelly = new ImageIcon("skelly.gif"); private int rainw = rain.getIconWidth(); private int rainh = rain.getIconHeight();
private JLabel[] labels = { new JLabel("I stay put", punch, SwingConstants.RIGHT), new JLabel("Drag me around!", skelly, SwingConstants.RIGHT), };
public CustomContentPane() { Dragger listener = new Dragger(); JCheckBox onDragLayer = new JCheckBox("Drag Layer");
// JLayeredPane has a null layout by default setLayout(new FlowLayout());
onDragLayer.setOpaque(false);
add(onDragLayer); add(labels[0]); add(labels[1]);
labels[1].addMouseMotionListener(listener); labels[1].addMouseListener(listener);
setLabelText();
onDragLayer.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if(e.getStateChange() == ItemEvent.SELECTED) { setLayer(labels[1], JLayeredPane.DRAG_LAYER.intValue()); } else { setLayer(labels[1], JLayeredPane.DEFAULT_LAYER.intValue()); } setLabelText(); validate(); } }); } public void paintComponent(Graphics g) { Dimension size = getSize();
for(int row=0; row < size.height; row += rainh) for(int col=0; col < size.width; col += rainw) rain.paintIcon(this,g,col,row); } private void setLabelText() { for(int i=0; i < labels.length; ++i) { JLabel label = labels[i]; String t = new String("Layer: ");
t += "(" + getLayer(label) + "),"; t += " Index: " + getIndexOf(label);
label.setText(t); } } } class Dragger extends MouseAdapter implements MouseMotionListener { Point press = new Point(); boolean dragging = false;
public void mousePressed(MouseEvent event) { press.x = event.getX(); press.y = event.getY(); dragging = true; } public boolean isDragging() { return dragging; } public void mouseReleased(MouseEvent event) { dragging = false; } public void mouseClicked(MouseEvent event) { dragging = false; } public void mouseMoved(MouseEvent event) { // don't care } public void mouseDragged(MouseEvent event) { Component c = (Component)event.getSource();
if(dragging) { Point loc = c.getLocation(); Point pt = new Point(); pt.x = event.getX() + loc.x - press.x; pt.y = event.getY() + loc.y - press.y; c.setLocation(pt.x, pt.y); c.getParent().repaint(); } } }
12.3.5 JLayeredPane属性
12.3.6 JLayeredPane类总结
12.3.7 AWT兼容
12.4 JTablePane
例12-10 JTabbedPane的一个简单实例
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { public Test() { Container contentPane = getContentPane(); JTabbedPane tp = new JTabbedPane(); JPanel panelOne = new JPanel(); JPanel panelTwo = new JPanel();
panelOne.add(new JButton("button in panel 1")); panelTwo.add(new JButton("button in panel 2"));
tp.add(panelOne, "Panel One"); tp.addTab("Panel Two", new ImageIcon("document.gif"), panelTwo, "tooltip text");
contentPane.setLayout(new BorderLayout()); contentPane.add(tp); } }
12.4.1选项卡的位置
12.4.2 JTabbedPane的属性
例12-11 为JTabbedPane的实例设置选项卡放置位置
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { private JTabbedPane tp = new JTabbedPane(SwingConstants.BOTTOM); private JComboBox combo = new JComboBox();
public Test() { Container contentPane = getContentPane(); JPanel comboPanel = new JPanel(); JPanel panelOne = new JPanel(); JPanel panelTwo = new JPanel();
tp.add(panelOne, "Panel One"); tp.addTab("Panel Two", new ImageIcon("document.gif"), panelTwo, "tooltip text");
combo.addItem("TOP"); combo.addItem("LEFT"); combo.addItem("RIGHT"); combo.addItem("BOTTOM");
setComboValue();
comboPanel.add(new JLabel("Tab Placement:")); comboPanel.add(combo);
contentPane.setLayout(new BorderLayout()); contentPane.add(comboPanel, BorderLayout.NORTH); contentPane.add(tp, BorderLayout.CENTER);
combo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { JComboBox cb = (JComboBox)e.getSource(); int state = e.getStateChange();
if(state == ItemEvent.SELECTED) { String s = (String)cb.getSelectedItem();
if(s.equals("TOP")) tp.setTabPlacement(JTabbedPane.TOP); else if(s.equals("LEFT")) tp.setTabPlacement(JTabbedPane.LEFT); else if(s.equals("RIGHT")) tp.setTabPlacement(JTabbedPane.RIGHT); else if(s.equals("BOTTOM")) tp.setTabPlacement(JTabbedPane.BOTTOM);
tp.validate(); } } }); } private void setComboValue() { int placement = tp.getTabPlacement(); String selectedItem = null;
switch(placement) { case JTabbedPane.TOP: selectedItem = "TOP"; break; case JTabbedPane.LEFT: selectedItem = "LEFT"; break; case JTabbedPane.RIGHT: selectedItem = "RIGHT"; break; case JTabbedPane.BOTTOM: selectedItem = "BOTTOM"; break; } combo.setSelectedItem(selectedItem); } }
12.4.3 JTabbedPane的事件
例12-12 响应JTabbedPane的变化事件
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*;
public class Test extends JApplet {
public Test() { Container contentPane = getContentPane(); JTabbedPane tp = new JTabbedPane(); JPanel panelOne = new JPanel(); JPanel panelTwo = new JPanel();
tp.add(panelOne, "Panel One"); tp.addTab("Panel Two", new ImageIcon("document.gif"), panelTwo, "tooltip text");
contentPane.setLayout(new BorderLayout()); contentPane.add(tp);
tp.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { JTabbedPane tabbedPane = (JTabbedPane)e.getSource();
int index = tabbedPane.getSelectedIndex(); String s = tabbedPane.getTitleAt(index);
showStatus(s + " selected"); } }); } }
12.4.4 JTabbedPane类总结
12.5 JSplitPane类
例12-13 运行中的JSplitPane
import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Test extends JApplet { public Test() { Container contentPane = getContentPane(); JButton left, right; JSplitPane sp = new JSplitPane(); ControlPanel cp = new ControlPanel(sp);
contentPane.setLayout(new BorderLayout()); contentPane.add(sp, BorderLayout.CENTER); contentPane.add(cp, BorderLayout.NORTH);
left = (JButton)sp.getTopComponent(); right = (JButton)sp.getBottomComponent();
System.out.println("left button minimum size: " + left.getMinimumSize()); System.out.println("right button minimum size: " + right.getMinimumSize());
} }
class ControlPanel extends JPanel { private JSplitPane sp;
public ControlPanel(JSplitPane splitPane) { sp = splitPane;
JComboBox dividerSize = new JComboBox(); JComboBox orientation = new JComboBox();
JCheckBox continuous = new JCheckBox( "Continuous Layout"); JCheckBox oneTouch = new JCheckBox( "One Touch Expandable");
Integer initialSize = new Integer(sp.getDividerSize()); dividerSize.addItem(initialSize.toString()); dividerSize.addItem("10"); dividerSize.addItem("20"); dividerSize.addItem("30"); dividerSize.addItem("40");
orientation.addItem("horizontal"); orientation.addItem("vertical");
int initialOrientation = sp.getOrientation(); if(initialOrientation == JSplitPane.HORIZONTAL_SPLIT) orientation.setSelectedItem("horizontal"); else orientation.setSelectedItem("vertical");
boolean initialContinuousLayout = sp.isContinuousLayout(); if(initialContinuousLayout) continuous.setSelected(true);
add(oneTouch); add(continuous); add(new JLabel("Divider Size:")); add(dividerSize); add(new JLabel("Orientation:")); add(orientation);
oneTouch.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if(e.getStateChange() == ItemEvent.SELECTED) sp.setOneTouchExpandable(true); else sp.setOneTouchExpandable(false); } }); continuous.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if(e.getStateChange() == ItemEvent.SELECTED) sp.setContinuousLayout(true); else sp.setContinuousLayout(false); } }); dividerSize.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { JComboBox combo = (JComboBox)e.getSource(); String s = (String)combo.getSelectedItem();
sp.setDividerSize(Integer.parseInt(s)); } }); orientation.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { JComboBox combo = (JComboBox)e.getSource(); String s = (String)combo.getSelectedItem();
if(s.equals("horizontal")) sp.setOrientation( JSplitPane.HORIZONTAL_SPLIT); else sp.setOrientation(JSplitPane.VERTICAL_SPLIT); } }); } }
12.5.1 JSplitPane属性
12.5.2 JSplitPane事件
例12-14 监视一个拆分窗格的分隔体的位置
import java.awt.*; import java.awt.event.*; import java.beans.*; import javax.swing.*;
public class Test extends JApplet { public Test() { Container contentPane = getContentPane(); JSplitPane sp = new JSplitPane();
contentPane.add(sp, BorderLayout.CENTER); sp.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if(e.getPropertyName().equals( JSplitPane.LAST_DIVIDER_LOCATION_PROPERTY)) { JSplitPane jsp = (JSplitPane)e.getSource();
int dl = jsp.getDividerLocation();
JButton lb = (JButton)jsp.getLeftComponent(); JButton rb = (JButton)jsp.getRightComponent();
showStatus("Divider Location: " + dl + " / " + lb.getText() + ": " + lb.getSize() + " / " + rb.getText() + ": " + rb.getSize()); } } }); } }
12.5.3 JSplitPane类总结
略
12.5.4 AWT兼容
略