五.
窗格、滚动窗格和布局管理
窗格 (JPanel) 和滚动窗格 (JScrollPane)
在图形用户界面设计中大量用于各种组件在窗口上的布置和安排。这里所谓的布置和安排,就是布局
(Layout),因此不得不先说说布局。
将加入到容器(通常为窗口等)
的组件按照一定的顺序和规则放置,使之看起来更美观,这就是布局。布局由布局管理器
(Layout Manager)
来管理。那么,我们在什么时候应该使用布局管理器?应用选择哪种布局管理器?又该怎样使用布局管理器呢?
往往,我们设计一个窗口,其中是要添加若干组件的。为了管理好这些管理的布局,我们就要使用布局管理器。比如说,设计一个简单的编辑器,这个编辑器中只
需要放置两个按钮和一个多行文本框。这些组件是让 Java
自己任意安排呢?还是按照一定的位置关系较规范的安排呢?当然应该选择后者。那么,为了按照一定的位置关系安排这些组件,我们就需要用到布局管理器了。
然后我们遇到了一个选择题——使用哪种布局管理器。为此,我们首先要知道有些什么布局管理器,它们的布局特点是什么。常用的布局管理器有:
FlowLayout、BorderLayout、GridLayout、BoxLayout 等,其中 FlowLayout
和 BorderLayout
最常用,本文主要也就只谈谈这两种布局管理器。下面列表说明它们的布局特点:
布局管理器
布局特点
FlowLayout
将组件按从左到右从上到下的顺序依次排列,一行不能放完则折到下一行继续放置
BorderLayout
将组件按东、南、西、北、中五个区域放置,每个方向最多只能放置一个组件
GridLayout
形似一个无框线的表格,每个单元格中放一个组件
BoxLayout
就像整齐放置的一行或者一列盒子,每个盒子中一个组件
就上述的编辑器为例,如果选用
FlowLayout,那么两个按钮和一个多行文本框就会排列在一行——当然这是窗口足够宽的情况;如果窗口稍窄一些,则可能分两行排列,第一行有两个按
钮,而第二行是多行文本框——这是最理想的情况;如果窗口再窄一些,就可能分三行排列,第一行和第二行分别放置一个按钮,第三行放置多行文本框。因此,如
果窗口大小可以改变,那么三个组件的位置关系也可能随着窗口大小的变化而变化。所以,FlowLayout
不适用。其实上面所举的例程中,大部分都是用的
FlowLayout,那是因为我们没有要求组件的布局。
如果选用 BorderLayout 的情况又如何呢?我们可以试着加入一个窗格
(JPanel,稍后讲解),并将两个按钮放置在其中,然后将这个窗格加入到
BorderLayout 的北部 (即上部);再将多行文本框加入到 BorderLayout
中部。结果类似使用 FlowLayout
的第二种可能,是最理想的情况。而且,如果改变窗口大小,它们的位置关系仍然是北-中的关系,不会随之改变。
剩下的两种布局管理器,加以窗格 (JPanel)
的配合,也能够很好的安排上述编辑器所需的三个组件。但是由于它们的使用稍为复杂一些,所以就不讲了。下面就讲讲如何使用
FlowLayout 和 BorderLayout。
任何布局管理器,都需要用在容器上,比如 JFrame 的 Content Pane
和下面要说的 JPanel 都是容器。容器组件提供了一个 setLayout
方法,就是用来改变其布局管理器的。默认情况下,JFrame 的 Content
Pane 使用的是 BorderLayout,而 JPanel 使用的是
FlowLayout。但不管怎样,我们都可以调用它们的 setLayout
方法来改变其布局管理器。比如上述的编辑器中,我们要让窗口 (JFrame
对象,假设为 frame) 使用 BorderLayout,就可以使用
frame.getContentPane().setLayout(new BorderLayout());
来改变其布局管理器为一个新的 BorderLayout 对象。
然后,我们对布局管理器的直接
操作就结束了,剩下的只需要往容器里添加组件。如果使用
FlowLayout,我们只需要使用容器的 add(Component c)
方法添加组件就行了。但是,如果使用 BorderLayout
就不一样了,因为要指定是把组件添加到哪个区域啊。那我们就使用容器的
add(Component c, Object o)
方法添加组件,该方法的第二个参数就是指明添加到的区域用的。例如,上述编辑器中要添加一个多行文本框到
BorderLayout 的中部,就可以用 frame.getContentPane().add(new
JTextArea(5, 15), BorderLayout.CENTER) 来实现。
BorderLayout 的五个区域分别是用下列五个常量来描述的:
BorderLayout.EAST 东
BorderLayout.SOUTH 南
BorderLayout.WEST 西
BorderLayout.NORTH 北
BorderLayout.CENTER 中
刚才已经提到了使用 JPanel。JPanel
作为一个容器,可以包容一些组件,然后将这个 JPanel
对象作为一个组件添加到另一个容器 (称作父容器)
中。这个功能有什么好处呢?
上面不是提到 BorderLayout
的一个区域中只能添加一个组件吗?但是我们的编辑器需要添加两个按钮到它的北部,怎么办?上面的例子中,我们就是用的一个
JPanel 包容了这两个按钮,然后再将这个 JPanel
对象作为一个组件添加到设置布局管理器为 BorderLayout 的 Content Pane
中。
上面说到各布局管理器的布局特点的时候,几乎每一种都是一个区域只能添加一个组件,那我们想添加多个组件到一个区域的时候,就要用到
JPanel 了。如果还没有明白,稍后看一段程序可能更易于理解。
而滚动窗格 (JScrollPane)
呢?它是一个能够自己产生滚动条的容器,通常只包容一个组件,并且根据这个组件的大小自动产生滚动条。比如上面讲
JTextArea 的时候提到:JTextAera
会随用户输入的内容自动扩展大小,很容易打破各组件的布局。但是,如果我们将它包容在一个滚动窗格中,它的扩展就不会直接反映在大小的变化上,而会反映在
滚动窗格的滚动条上,也就不会打破各组件的布局了。稍后的例子会让你清清楚楚。
是不是等着看例子了?好,例子来了:
/**
* TestPanels.java
* @author Fancy */
import javax.swing.*;
import java.awt.*;
public class TestPanels extends JFrame {
public TestPanels() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel panel = new JPanel();
for (int i = 0; i < 2; i++) {
panel.add(new JButton("Button 00" + i));
}
JTextArea textArea = new JTextArea(5, 15);
textArea.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane(textArea);
getContentPane().add(panel, BorderLayout.NORTH);
getContentPane().add(scrollPane, BorderLayout.CENTER);
pack();
}
public static void main(String[] args) {
TestPanels tp = new TestPanels();
tp.show();
}
}
这个例子的运行结果如下图,正是我们想要的结果——上面两个按钮,下面是一个可以滚动的多行文本框:
上例中首先产生了一个 JPanel 对象 (JPanel panel = new
JPanel();),然后将两个按钮置于其中 (panel.add
...);然后产生了一个多行文本框 (JTextArea textArea = new
JTextArea(5, 15);),并使用一个滚动窗格将它包裹起来 (JScrollPane
scrollPane = new
JScrollPane(textArea);),使之成为可以滚动的多行文本框。最后将两个容器
(JPanel 对象和 JScrollPane 对象) 分别添加到了窗口的北部
(getContentPane().add(panel, BorderLayout.NORTH);) 和中部
(也就是剩余部分,getContentPane().add(scrollPane,
BorderLayout.CENTER);)。
好像有点不对劲,是什么呢?对了,我们没有设置 Content Pane
的布局管理器为 BorderLayout 啊,为什么……刚才不是说了吗,JFrame 的
Content Pane 的默认布局管理器就是
BorderLayout,所以不用再设置了。
好了,《Java
的图形用户界面设计》就告一段落了。由于篇幅有限,这里说的都是初级知识,有此基础,设计复杂一点的图形用户界面也就不是难事了!