Swing的容器结构与JLayeredPane的使用

类层次结构图:
java.lang.Object
    --java.awt.Compontent
    --java.awt.Container
      --javax.swing.JComponent
        --javax.swing.JLayeredPane

我们可把Swing容器的结构看似如下图所示:

         |Grass Pane
         |
Root Pane|
         |            |Content Pane
         |Layered Pane|
                      |Menu Bar

其中,Root Pane可以看成是虚拟的容器,包含着Grass Pane、Layered Pane、Content Pane与Menu Bar.Swing的容器包括JApplet ,JFrame,JDialog,JWindow与JInternalFrame都是构造在此结构上,JApplet、JFrame、JDialog、JWindow都是heavyweight容器,只 有JInternalFrame是lightweight容器。当我们要加入某个组件到Swing的容器中时,并不是直接加入到Root Pane,而是加入到 RootPane下面的某一成员(Layered Pane或Content Pane)

Content Pane与Menu Bar只是Layered Pane的其中一层,我们称此层为Frame-Content Layer.若你想知道Frame-Content Layer 在Layered Pane的层次是什么?你可以由JLayeredPane类中的Frame_Content_layer类常数取得。

由此我们可以知道,Layered Pane基本上可拥有非常多的“层”(Layer),那么如何分辨哪一层是在哪一层的上面或下面呢? 答案是Z_order.Z_order本身具有两个整数值,一个是代表层(Layer)的深度,另一个代表同层的相关位置(Position),当Z_order 的Layer数值越小时,表示其位置就在越底层,当Z_order的Layer数值越大时,表示其位置就在越上层。在JLayeredPane类中,共定 义了6个Z_order常数供用户参考,如下所示:

DEFAULT_LAYER:Z_order的Layer数值为0,以整数对象Integer(0)来表示,一般我们加入的组件若没有标记是第几层,默认值就 把组件放在此Default Layer中。

PALETTE_LAYER:Z_order的Layer数值为100,以整数对象Integer(100)来表示,位于Default Layer之上,一般用于放置可移动的 工具栏(Floatable Toolbar).

MODAL_LAYER:Z_order的Layer数值为200,以整数对象Integer(200)来表示,位于PALETTE_LAYER之上,一般用于放置对话框 (Dialog Box).

POPUP_LAYER:Z_order的Layer数值为300,以整数对象Integer(300)来表示,位于MODAL_LAYER之上,一般用于快捷菜单(Poup Menu)与工具栏提示(Tool Tips)中.

DRAG_LAYER:Z_order的Layer数值为400,以整数对象Integer(400)来表示,位于POPUP_LAYER之上,一般用于拖曳组件使其在不同 区域上.

FRAME_CONTENT_LAYER:Z_order的Layer数值为-30000,以整数对象Integer(-30000)来表示,一般来说,Frame Content Layer 最底层的是Layer,用来表示Content Pane与Menu Bar的位置,大部份情况我们不会更改到这个数值。

一般程序会提供良好的Z-order自动管理机制,当然java也不例外,因此大部份情况我们不会使用到Z-order,因为系统会自动 帮我们管理得好好的。用户只需将所需的组件直接加入Content Pane即可,不需要知道它们之间的顺序关系。但如果今天您必须处 理对象之间的层次关系时,例如Word中你可以把某个绘图对象下推至下一层,你就必须亲自处理Z-order的关系了。

下面我们来看如何利用JLayeredPane来控制对象的层次关系:

这个例子分别用7个JLabel对象层层相叠,每个JLabel对象都有不同的Z-order数值,形成7层相叠的效果!

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

public class JLayeredPane1 extends JFrame {
	public JLayeredPane1() {
		super("JLayeredPane");
		/*
		 * 由小到大定义组件深度数值,也就是Z-order layer的大小。
		 */
		Integer[] layerConstants = { JLayeredPane.DEFAULT_LAYER,
				JLayeredPane.PALETTE_LAYER, new Integer(101),
				JLayeredPane.MODAL_LAYER, new Integer(201),
				JLayeredPane.POPUP_LAYER, JLayeredPane.DRAG_LAYER };
		/*
		 * 定义每个JLabel的颜色
		 */
		Color[] colors = { Color.red, Color.blue, Color.magenta, Color.cyan,
				Color.yellow, Color.green, Color.pink };
		Point position = new Point(10, 10);
		JLabel[] label = new JLabel[7];
		JLayeredPane layeredPane = getLayeredPane();// 取得窗口的Layered Pane

		for (int i = 0; i < 7; i++) {
			label[i] = createLabel("第" + (i + 1) + "层", colors[i], position);
			position.x = position.x + 20;
			position.y = position.y + 20;
			// 将组件(JLabel)放入Layered Pane中并给予深度(Z-order layer)的数值。
			layeredPane.add(label[i], layerConstants[i]);
		}
		setSize(new Dimension(280, 280));
		show();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	public JLabel createLabel(String content, Color color, Point position) {
		JLabel label = new JLabel(content, JLabel.CENTER);
		label.setVerticalAlignment(JLabel.TOP);
		label.setBackground(color);
		label.setForeground(Color.black);
		label.setOpaque(true);
		label.setBounds(position.x, position.y, 100, 100);
		return label;
	}

	public static void main(String[] args) {
		new JLayeredPane1();
	}
}

从上面的例子可以看出,Z-order layer数值越小的组件在越底层,也就会被Z-order layer值较大的组件所覆盖。那如果两个 组件都在同一层且相互重叠,怎么知道它们之间的层次关系呢?答案是利用Z-order的另外一个整数值:position。position 数值的关系跟 Z-order的layer数值恰好相反,在同一层中的对象,若position数值越小者则在越上层,position数值越大者则 在越下层。position的数值是从-1~n~1,n是指在同一层中组件的个数,数值-1代表最底层,意思跟n-1一样;数值0代表最上层。 你可以使用JLayeredPane类提供的moveToBack()方法将组件推至position为-1(最底端)的位置,或是使用moveToFront()方法 将组件推至position为0(最顶端)的位置。我们来看下面的范例:

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

public class JLayeredPane3 extends JFrame {
	public JLayeredPane3() {
		super("JLayeredPane");

		JLabel label1 = new JLabel("左Label", JLabel.CENTER);
		label1.setVerticalAlignment(JLabel.TOP);
		label1.setBackground(Color.red);
		label1.setForeground(Color.black);
		label1.setOpaque(true);
		label1.setBounds(20, 20, 150, 150);

		JLabel label2 = new JLabel("右sLabe2", JLabel.CENTER);
		label2.setVerticalAlignment(JLabel.TOP);
		label2.setBackground(Color.red);
		label2.setForeground(Color.black);
		label2.setOpaque(true);
		label2.setBounds(50, 50, 150, 150);

		JLayeredPane layeredPane = getLayeredPane();
		layeredPane.add(label1, new Integer(10), 1);
		layeredPane.add(label2, new Integer(10), 0);

		setSize(new Dimension(280, 280));
		show();
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}

	public static void main(String[] args) {
		new JLayeredPane3();
	}
}

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐