Java布局管理 清华大学继续教育学院 IT教育培训中心
Java的布局设计 本章学习内容(掌握基本的布局方法) 流动布局 网格布局 边界布局 卡片布局 网格袋布局 空布局
流动布局 自左向右、自上而下的安排组件,并且尽量将组件居中。 流动布局不会改变组件的尺寸,当当前行无法显示新增组件时,布局管理器会新增一行以安放新增组件 一个典型的例子就是applet中的缺省组件显示。使用教材上的示例列表显示
import javax.swing.*; import java.awt.*; public class exec { public static void main(String [] args) { JFrame f=new JFrame("Hello!"); f.setLocation(10,100); f.setSize(600,400); f.getContentPane().setLayout(new FlowLayout()); JButton jb1=new JButton("Click 1"); JButton jb2=new JButton("Click 2"); JButton jb3=new JButton("Click 3"); f.getContentPane().add(jb1); f.getContentPane().add(jb2); f.getContentPane().add(jb3); f.setVisible(true); } }
当然,流布局管理器类也可以定义很多布局属性,从而进行必要的一些样式调整,如: import javax. swing 当然,流布局管理器类也可以定义很多布局属性,从而进行必要的一些样式调整,如: import javax.swing.*; import java.awt.*; public class exec { public static void main(String [] args) { JFrame f=new JFrame("Hello!"); f.setLocation(10,100); f.setSize(600,400); f.getContentPane().setLayout(new FlowLayout(1,10,100)); JButton jb1=new JButton("Click 1"); JButton jb2=new JButton("Click 2"); JButton jb3=new JButton("Click 3"); f.getContentPane().add(jb1); f.getContentPane().add(jb2); f.getContentPane().add(jb3); f.setVisible(true); } }
说明: 1)流布局管理器类构造函数三个参数的意思分别为:第一参数代表对齐方式,如0表示左对齐,1表示居中,2右对齐,3顶端对齐,4底部对齐;第二参数代表水平间距;第三参数代表垂直间距。 2)可以尝试着改变窗体的大小,观察按钮的布局,特别注意,当一行显示不下而换行显示按钮时,中间的垂直间距和第一行按钮距窗体标题栏的间距都是100象素单位。但是,如果将窗体收缩太小,则可能无法显示全部组件。一个简单的解决方法是设置窗体对象的可调整属性为假,即调用setResizable()方法即可,如:
import javax.swing.*; import java.awt.*; public class exec { public static void main(String [] args) { JFrame f=new JFrame("Hello!"); f.setLocation(10,100); f.setSize(600,400); f.getContentPane().setLayout(new FlowLayout(1,10,100)); JButton jb1=new JButton("Click 1"); JButton jb2=new JButton("Click 2"); JButton jb3=new JButton("Click 3"); f.getContentPane().add(jb1); f.getContentPane().add(jb2); f.getContentPane().add(jb3); f.setResizable(false);//重要 f.setVisible(true); } }
3)只要是容器型的组件都可以添加其他组件,也都可以设置布局管理器,所以面板就是一个常用的容器组件,综合使用面板叠加嵌套布局管理器可以构造出更加灵活的界面,如下面的练习可以显示一个计算器程序: import javax.swing.*; import java.awt.*; public class exec { public static void main(String [] args) { JFrame f=new JFrame("Hello!"); f.setLocation(10,100); f.setSize(150,400); f.getContentPane().setLayout(new FlowLayout(1,10,10)); JLabel l=new JLabel("****计算器****"); JLabel l1=new JLabel("数1:"); JLabel l2=new JLabel("数2:"); JLabel l3=new JLabel("和:"); JTextField t1=new JTextField(5); JTextField t2=new JTextField(5); JTextField t3=new JTextField(10); JButton b=new JButton("Sum"); JPanel p1=new JPanel(); JPanel p2=new JPanel(); JPanel p3=new JPanel(); JPanel p4=new JPanel(); JPanel p5=new JPanel(); p1.setLayout(new FlowLayout(FlowLayout.CENTER,0,10)); p1.add(l); p2.setLayout(new FlowLayout(FlowLayout.CENTER,10,0)); p2.add(l1); p2.add(t1); p3.setLayout(new FlowLayout(FlowLayout.CENTER,10,0)); p3.add(l2); p3.add(t2); p4.setLayout(new FlowLayout(FlowLayout.CENTER,10,0)); p4.add(l3); p4.add(t3); p5.setLayout(new FlowLayout(FlowLayout.CENTER,10,10)); p5.add(b); f.getContentPane().add(p1); f.getContentPane().add(p2); f.getContentPane().add(p3); f.getContentPane().add(p4); f.getContentPane().add(p5); f.setVisible(true); } }
网格布局 需要事先指定布局的行列,形成网格。 组件由左向右、由上至下,并在本布局中会填充网格。缺点在此,因为有可能造成组件显示失真。 当组件超过列数的时候,不是直接添加到下一行,而是增加列数,行数保持不变。 和流布局管理器类不同的地方在于,组件不会因为窗体大小的变化而移位,相反,组件通过自动缩放以保持屏幕组件的网格关系。 创建方法:panel.setLayout(new GridLayout(5,4)); 添加组件:panel.add(new JButton(“1”)); panel.add(new JButton(“2”));
import javax.swing.*; import java.awt.*; public class exec { public static void main(String [] args) { JFrame f=new JFrame("Hello!"); f.setLocation(10,100); f.setSize(600,400); f.setMinimumSize(new Dimension(200,100)); f.getContentPane().setLayout(new GridLayout(3,3,10,10)); JButton[] jb=new JButton[9]; for(int i=0;i<jb.length;i++) { jb[i]=new JButton(String.valueOf(i)); f.getContentPane().add(jb[i]); } f.setVisible(true); } } 说明: 网格布局管理器类构造函数中的四个参数中,前两个代表行数和列数,后两个代表组件的横向间距和纵向间距。
边界布局 边界布局的方式是自然方位的方式 : 北(north)、南(south)、东(east)、西(west)、中(center),其中中是布局余下部分 以上的每个区域可以显示一个组件,并且布局管理器会使北南的组件与容器等宽 组件会依据位置填充或者压缩,很少出现最佳尺寸 组件添加的时候必须指定区域。添加方法为add(Object,String)//Object是被添加组件;String为组件添加位置,如:BorderLayout.NORTH 边界布局的局限性:单个区域不能显示多个组件。
因为在边界布局中单个区域只能显示最后被添加的组件。 解决这个问题的办法是:把组件添加至一个中间容器,之后把中间容器添加到区域中。 如:panel = new Panel(); panel.add(new Button(“确定”)); panel.add(new Label(“选择”)); add(panel,BorderLayout.SOUTH);
import javax.swing.*; import java.awt.*; public class exec { public static void main(String [] args) { JFrame f=new JFrame("Hello!"); f.setLocation(10,100); f.setSize(600,400); f.setMinimumSize(new Dimension(200,100)); f.getContentPane().setLayout(new BorderLayout(5,10)); JButton jb1=new JButton("1"); JButton jb2=new JButton("2"); JButton jb3=new JButton("3"); JButton jb4=new JButton("4"); JButton jb5=new JButton("5"); f.getContentPane().add(jb1,BorderLayout.NORTH); f.getContentPane().add(jb2,BorderLayout.SOUTH); f.getContentPane().add(jb3,BorderLayout.EAST); f.getContentPane().add(jb4,BorderLayout.WEST); f.getContentPane().add(jb5,BorderLayout.CENTER); f.setVisible(true); } } 说明: 边框布局管理器类构造函数的两个参数分别为水平间隔象素数和垂直间隔象素数,上、下、左、右、中分别用北、南、西、东和中来表示。和流布局管理器类不同的地方在于,组件不会因为窗体大小的变化而移位,相反,组件通过自动缩放以保持原有的对应关系。
卡片布局(CardLayout) 卡片布局可以同时容纳多个组件,但只能一次显示一个组件 卡片布局的创建过程: 1、创建卡片布局对象:mycard=new CardLayout(); 2、设置布局:container.setLayout(mycard) 3、添加组件:container.add(组件代号,组件); 4、显示:mycard.show()
卡片布局的实现方法(con为容器) 方法 说明 Void first(con) 显示第一个组件 Void last(con) 显示最后一个组件 Void next(con) 显示当前组件的后一个组件,当前为最后时显示最后的组件 Void previous(con) 显示当前组件的前一个组件,当前为第一个时显示最后的组件 Void show(con,string) 显示名称和和传递的字符串(组件代号)相匹配的组件,如果没有则为空操作
import javax.swing.*; import java.awt.*; public class GUITest { public static void main(String[] args) { // TODO 自动生成方法存根 JFrame frm = new JFrame("Frame with Controls"); frm.getContentPane().setLayout(new CardLayout()); button[] btn = new JButton[10]; for (int i=0; i<10; i++) { btn[i] = new JButton("Button " + (i+1)); frm.add(("Button " + (i+1)), btn[i]); } frm.setBounds(100, 100, 250, 100); frm.setVisible(true); while (true) { ((CardLayout)frm.getContentPane().getLayout()).previous(frm.getContentPane());
网格袋布局(GridBagLayout) 网格袋布局也是在网格中定位组件,但是不显式规定网格中的行列,它是根据组件的约束条件确定行数和列数,而且组件可以跨越几个网格(组件可以重叠)。 这是一个复杂的布局管理器,需要仔细研究和练习。
特色 可在版面上出画大大小小方形的 “袋子” (Bag)。再將元件塞入 “袋子” 中。 是最強悍、应用最广的布局管理器 需利用另一物件:GridBagConstraints,來設定每個袋子的大小。 設定好了以後,再將欲加入此袋的元件与 Constraints 绑定。 最後再丟入 GridBagLayout 即成
GridBag Layout 示意圖 設定 OK 綁 加入 GridBagConstraints Grid Bag G.B. Frame
Grid Bag Layout GridBagLayout 构造函数 GridBagConstraints构造函数 GridBagConstraints( int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets, int ipadx, int ipady)
gridwidth / gridheight gridx / gridy 指出这个 GridBag 由第几列 (gridx)、第几行 (gridy)开始算起。 gridx = a、 gridy = b:指出這个 Grid Bag的位置 gridx = GridBagConstraints.RELATIVE 本元件放在上一个元件的右边 gridy = GridBagConstratins.RELATIVE 本元件在上一个元件的下面 gridwidth / gridheight 此 Grid Bag 的長寬 (單位:行/列) = GridBagConstraints.REMAINDER 將本列 / 行的剩下高度全配給此 Grid Bag
weightx / weighty anchor 用來设定当視窗变大时,此 Grid Bag 要变大的比例 如:“Button 1” 之 weightx = 10, weighty = 1, “Button 2” 之 weigthx = 1, weighty = 1,当視窗变大时,“Button 1”变大的比例要比 “Button 2” 快十倍。 也可以設定在 0.0 (变大时元件不变化) ~ 1.0 (变化最大) 之间 anchor 设定当 Grid Bag 比元件大时,元件如何对齐。 有:CENTER(默认), EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST, NORTH, NORTHEAST可供选择
insets(top, left, bottom, right) ipadx / ipady fill 当視窗拉大时,GridBag 內的元件哪一個方向也須跟著拉大 NONE (默认值):元件不隨視窗拉大而拉大 VERTICAL: 元件的纵方向拉大,橫方向不拉大 HORIZONTAL: 元件的橫方向拉大,纵方向不拉大 BOTH: 元件的橫 /纵方向会隨著視窗拉大而拉大 insets(top, left, bottom, right) 设定元件间彼此的距离 ipadx / ipady 设定元件內部字樣,与元件边界的距离 Button 1
Grid Bag Layout 範例 import javax.swing.*; import java.awt.*; public class GUITest { public static void main(String[] args) { // TODO 自动生成方法存根 int gridx, gridy, gridwidth, gridheight, anchor, fill, ipadx, ipady; double weightx, weighty; Insets insets; JFrame frm = new JFrame("Frame with Controls"); GridBagLayout gb = new GridBagLayout(); GridBagConstraints c; frm.getContentPane().setLayout(gb); JButton[] btn = new JButton[5];
// Button 1 btn[0] = new JButton("Button 1"); gridx = 0; gridy = 0; gridwidth = 1; gridheight = 1; weightx = 10; weighty = 1; anchor = GridBagConstraints.CENTER; fill = GridBagConstraints.HORIZONTAL; insets = new Insets(0, 0, 0, 0); ipadx = 0; ipady = 0; c = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); gb.setConstraints(btn[0], c); frm.add(btn[0]); // Button 2 btn[1] = new JButton("Button 2"); gridx = 1; gridy = 0; gridwidth = 2; gridheight = 1; weightx = 1; weighty = 1; ipadx = 50; ipady = 0; gb.setConstraints(btn[1], c); frm.add(btn[1]);
// Button 3 btn[2] = new JButton("Button 3"); gridx = 0; gridy = 1; gridwidth = 1; gridheight = 1; weightx = 1; weighty = 1; anchor = GridBagConstraints.CENTER; fill = GridBagConstraints.HORIZONTAL; insets = new Insets(10, 0, 0, 0); ipadx = 50; ipady = 0; c = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); gb.setConstraints(btn[2], c); frm.add(btn[2]); // Button 4 btn[3] = new JButton("Button 4"); gridx = 1; gridy = 1; insets = new Insets(0, 0, 0, 0); ipadx = 0; ipady = 50; gb.setConstraints(btn[3], c); frm.add(btn[3]);
// Button 5 btn[4] = new JButton("Button 5"); gridx = 2; gridy = 1; gridwidth = 1; gridheight = 2; weightx = 1; weighty = 1; anchor = GridBagConstraints.SOUTH; fill = GridBagConstraints.HORIZONTAL; insets = new Insets(0, 0, 0, 0); ipadx = 0; ipady = 0; c = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); gb.setConstraints(btn[4], c); frm.add(btn[4]); frm.setBounds(100, 100, 300, 300); frm.setVisible(true); }
Grid Bag Layout 範例 // Button 3 btn[2] = new Button("Button 3"); gridx = 0; gridy = 1; gridwidth = 1; gridheight = 1; weightx = 1; weighty = 1; anchor = GridBagConstraints.CENTER; fill = GridBagConstraints.HORIZONTAL; insets = new Insets(10, 0, 0, 0); ipadx = 50; ipady = 0; c = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); gb.setConstraints(btn[2], c); frm.add(btn[2]);
Grid Bag Layout 範例 // Button 4 btn[3] = new Button("Button 4"); gridx = 1; gridy = 1; gridwidth = 1; gridheight = 1; weightx = 1; weighty = 1; anchor = GridBagConstraints.CENTER; fill = GridBagConstraints.HORIZONTAL; insets = new Insets(0, 0, 0, 0); ipadx = 0; ipady = 50; c = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); gb.setConstraints(btn[3], c); frm.add(btn[3]);
Grid Bag Layout 範例 回到原主題 // Button 5 btn[4] = new Button("Button 5"); gridx = 2; gridy = 1; gridwidth = 1; gridheight = 2; weightx = 1; weighty = 1; anchor = GridBagConstraints.SOUTH; fill = GridBagConstraints.HORIZONTAL; insets = new Insets(0, 0, 0, 0); ipadx = 0; ipady = 0; c = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, anchor, fill, insets, ipadx, ipady); gb.setConstraints(btn[4], c); frm.add(btn[4]); frm.setBounds(100, 100, 300, 300); frm.setVisible(true); } 回到原主題
javax.swing 包提供了一个Box类,它创建的容器称 BoxLayout布局 javax.swing 包提供了一个Box类,它创建的容器称 为盒式容器。其默认的布局管理器是BoxLayout,并且 不能改变盒式容器的布局。 这样的容器将组件排列在一行或一列。 构造方法: BoxLayout(Container con, int axis) 使用BoxLayout的容器 BoxLayout.X_AXIS或BoxLayout.Y_AXIS
类方法: createHorizontalBox():获得一个具有行型盒式布局的盒式容器。 createVerticalBox():获得一个具有列型盒式布局的盒式容器。
Strut:盒式容器中组件间的距离。 Box.createHorizontalStrut(int width): 创建不可见的水平Struct类型的对象(水平支撑)。 高度为0,宽度为width Box.createVerticalStrut(int height): 创建不可见的垂直Struct类型的对象(垂直支撑)。 宽度为0,高度为width
Glue:Glue组件可处理盒式布局容器的剩余空间。 Box.createHorizontalGlue(): 创建不可见的水平Glue类型的对象(水平Glue)。 它会帮助组件靠左/右对齐(两边靠齐)。 Box.createVerticalGlue(): 创建不可见的垂直Struct类型的对象(垂直Glue)。 它会帮助组件靠上/下对齐(上下靠齐)。
组件的setAlignmentX(int i)只有在布局是BoxLayout.Y_AXIS才有效, 而组件的setAlignmentY(int i)在布局为BoxLayout.X_AXIS才有效。 组件对齐一般来说: 所有top-to-bottom BoxLayout object 应该有相同的 X alignment。 所有left-to-right Boxlayout应该有相同的 Y alignment setAlignmentX 和setAlignmentY 可以实现对齐。
import javax.swing.*; import java.awt.*; public class GUITest { public static void main(String[] args) { int gridx, gridy, gridwidth, gridheight, anchor, fill, ipadx, ipady; double weightx, weighty; Insets insets; JFrame frm = new JFrame("Frame with Controls"); Container cp=frm.getContentPane(); Box bBox=Box.createHorizontalBox(); cp.add(bBox); Box vBox1=Box.createVerticalBox(); JLabel lb=new JLabel("这是一个标签!"); vBox1.add(lb); JButton bt1=new JButton("这是一个按钮!"); bt1.setMaximumSize(new Dimension(100,200)); vBox1.add(bt1); bBox.add(vBox1); Box vBox2=Box.createVerticalBox(); bBox.add(vBox2);
JTextField tf1=new JTextField("这是文本框",10); tf1.setAlignmentX(Component.CENTER_ALIGNMENT); tf1.setMaximumSize(new Dimension(150,50)); vBox2.add(tf1); Box vBox2h=Box.createHorizontalBox(); vBox2.add(vBox2h); Box vBox2h1=Box.createVerticalBox(); vBox2h1.add(Box.createVerticalStrut(20)); vBox2h1.add(new JTextArea("这是文本区域")); vBox2h1.add(new JTextArea("测试文本区域")); vBox2h.add(vBox2h1); Box vBox2h2=Box.createVerticalBox(); vBox2h2.add(new JButton("这是按钮2")); vBox2h2.add(Box.createVerticalGlue()); vBox2h2.add(new JButton("这是按钮4")); vBox2h.add(vBox2h2); frm.setBounds(100, 100, 300, 300); frm.setVisible(true); }
空布局和setBounds方法 空布局的布局设置为container.setLayout(null); 步骤: 1、用add方法向容器添加组件 JPanel.add(Button); 2、Button.setBounds(int,int,int,int) 参数依次为:x,y(原点);width,height(宽和高)
import javax.swing.*; import java.awt.*; public class GUITest { /** * @param args */ public static void main(String[] args) { // TODO 自动生成方法存根 int gridx, gridy, gridwidth, gridheight, anchor, fill, ipadx, ipady; double weightx, weighty; Insets insets; JFrame frm = new JFrame("Frame with Controls"); Container cp=frm.getContentPane(); cp.setBackground(Color.RED); cp.setLayout(null); JButton jButton=new JButton("button"); cp.add(jButton); jButton.setBounds(10,10,50,20); JLabel jLabel=new JLabel("label"); cp.add(jLabel); jLabel.setBounds(8,8,50,20); frm.setBounds(100, 100, 300, 300); frm.setVisible(true); }