文档

Java™ 教程
隐藏目录
如何使用拆分面板
步骤: 使用Swing创建GUI
教程: 使用Swing组件
章节: 如何使用各种组件

如何使用分割窗格

JSplitPane显示两个组件,可以并排或者上下排列。用户可以通过拖动两个组件之间的分隔条来指定每个组件占用的空间比例。您可以通过将一个分割窗格放入另一个分割窗格中来将屏幕空间划分给三个或更多组件,如嵌套分割窗格中所述。

通常情况下,您不直接将感兴趣的组件添加到分割窗格中,而是将每个组件放入一个滚动窗格中,然后将滚动窗格放入分割窗格中。这样,用户可以查看感兴趣组件的任何部分,而无需组件占用大量屏幕空间或适应不同大小的屏幕空间。

下面是一个应用程序的图片,使用分割窗格并排显示一个列表和一张图片:

SplitPaneDemo的快照

请尝试: 
  1. 点击“Launch”按钮以使用Java™ Web Start运行SplitPaneDemo(需要下载JDK 7或更高版本)。或者,您也可以自己编译和运行示例,参考示例索引启动SplitPaneDemo示例
  2. 拖动列表和图片之间的分割线,将其向左或向右拖动。尝试将分割线拖动到窗口边缘。
  3. 点击分割线上的小箭头,隐藏/展开左侧或右侧组件。

下面是创建和设置分割窗格的SplitPaneDemo代码。

//在分割窗格中创建两个滚动窗格
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                           listScrollPane, pictureScrollPane);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation(150);

//为分割窗格中的两个组件设置最小大小
Dimension minimumSize = new Dimension(100, 50);
listScrollPane.setMinimumSize(minimumSize);
pictureScrollPane.setMinimumSize(minimumSize);

该示例使用的构造函数有三个参数。第一个参数表示分割方向,其他两个参数是要放入分割窗格中的两个组件。有关动态设置组件的JSplitPane方法,请参阅设置分割窗格中的组件

这个例子中的分割窗格是水平分割的——两个组件并排显示——由构造函数的JSplitPane.HORIZONTAL_SPLIT参数指定。分割窗格还提供了另一个选项,用JSplitPane.VERTICAL_SPLIT指定,将一个组件放在另一个组件上方。您可以使用setOrientation方法在创建分割窗格后更改分割方向。

在例子的分割窗格的分隔符上方出现了两个小箭头。这些箭头允许用户通过单击折叠(然后展开)任一组件。当前的外观和感觉决定了这些控件是否默认显示。在Java外观和感觉中,默认情况下它们是关闭的。(请注意,并非所有外观和感觉都支持此功能。)该示例使用setOneTouchExpandable方法将它们打开。

分割窗格的分隔符的范围部分取决于分割窗格内组件的最小大小。有关详细信息,请参见定位分隔符并限制其范围

本节的其余部分包括以下主题:

设置分割窗格中的组件

程序可以使用以下四种方法动态设置分割窗格的两个组件:

无论分割窗格当前的分割方向如何,您都可以随时使用这些方法中的任何一个。调用setLeftComponentsetTopComponent是等效的,它们将指定的组件设置在顶部或左侧位置,具体取决于分割窗格当前的分割方向。类似地,调用setRightComponentsetBottomComponent是等效的。这些方法将用新的组件替换该位置上的任何组件。

与其他容器一样,JSplitPane支持add方法。分割窗格将第一个添加的组件放在左侧或顶部位置。使用add的危险在于您可能会不经意地多次调用它,这种情况下分割窗格的布局管理器将抛出一个看起来相当晦涩的异常。如果您正在使用add方法且分割窗格已经有组件,您需要首先使用remove将现有组件移除。

如果在分割窗格中只放置一个组件,则分隔符将固定在分割窗格的右侧或底部,具体取决于分割方向。

设置分隔符的位置和限制范围

要使分割窗格正常工作,通常需要设置分割窗格中组件的最小大小以及分割窗格或其包含组件的首选大小。选择应该设置哪些大小是一门需要理解分割窗格的首选大小和分隔符位置是如何确定的艺术。在详细讨论之前,让我们再次看一下SplitPaneDemo。或者,如果你赶时间,你可以跳到规则列表


试一试: 
  1. 点击启动按钮以使用Java™ Web Start运行SplitPaneDemo(下载JDK 7或更高版本)。或者,如果你想要自己编译和运行示例,请参考示例索引启动SplitPaneDemo示例

    由于演示窗口的大小是使用pack方法设置的,分割窗格处于其首选大小,SplitPaneDemo恰好显式地设置了它。分隔符会自动放置,使左组件达到其首选宽度,剩余的空间全部给右组件。
  2. 使窗口变宽。
    分隔符保持在原地,多余的空间给右侧的组件。
  3. 使窗口明显比首次出现时窄,可能是左组件宽度的两倍。
    同样,左组件的大小和分隔符位置保持不变。只有右组件的大小发生变化。
  4. 使窗口尽可能窄。
    假设窗口使用的是Java外观提供的装饰,你不能将窗口调整到比分割窗格的最小大小更小,分割窗格的最小大小由分割窗格内包含组件的最小大小确定。SplitPaneDemo显式地设置了这些包含组件的最小大小。
  5. 使窗口变宽,然后将分隔符拖动到最右边。
    分隔符只能移动到右组件的最小大小所允许的范围内。如果将分隔符向左拖动,你会看到它也遵守左组件的最小大小。

现在你已经看到了分割窗格的默认行为,我们可以告诉你背后发生的事情以及你可以如何影响它。在这个讨论中,当我们提到一个组件的首选或最小大小时,我们通常是指如果分割窗格是水平的,组件的首选或最小宽度,或者如果分割窗格是垂直的,组件的首选或最小高度。

默认情况下,拆分窗格的首选大小和分隔符位置的初始化是基于两个组件的首选大小。如果拆分窗格没有以首选大小显示,并且程序没有显式设置分隔符位置,那么分隔符的初始位置(以及两个组件的大小)取决于一个称为“调整权重”的拆分窗格属性。如果拆分窗格最初处于其首选大小或更大,则包含的组件在调整大小权重之前以其首选大小开始。如果拆分窗格最初太小而无法显示两个组件的首选大小,则它们在调整大小权重之前以其最小大小开始。

拆分窗格的调整大小权重的值介于0.0和1.0之间,并确定在设置拆分窗格的大小时,空间如何在两个包含的组件之间分配 - 无论是通过编程设置还是通过用户调整拆分窗格(例如,扩大其包含的窗口)。默认情况下,拆分窗格的调整大小权重为0.0,表示左侧或顶部组件的大小固定,而右侧或底部组件调整其大小以适应剩余空间。将调整大小权重设置为0.5可以均匀地分配任何额外或缺少的空间给两个组件。将调整大小权重设置为1.0使得右侧或底部组件的大小保持不变。然而,当用户拖动分隔符时,调整大小权重不起作用。

只要没有包含的组件的大小低于其最小大小,用户可以将分隔符拖动到任意位置。如果分隔符上有一键按钮,则用户可以使用它们将分隔符完全移动到一侧或另一侧 - 无论组件的最小大小是什么。

现在,您已经了解了影响拆分窗格大小和分隔符位置的因素,以下是一些确保它们良好工作的规则:

下面的快照显示了一个名为SplitPaneDividerDemo的示例,该示例演示了分割窗格组件的大小和分隔符的位置。

SplitPaneDividerDemo的快照

与SplitPaneDemo一样,SplitPaneDividerDemo具有一个带有一键按钮的水平分割窗格。SplitPaneDividerDemo具有以下附加功能:


试一试: 
  1. 点击“启动”按钮,使用Java™ Web Start运行SplitPaneDividerDemo(下载JDK 7或更新版本)。或者,如果要自己编译和运行示例,请参考示例索引启动SplitPaneDividerDemo示例

    因为演示窗口的大小是使用pack方法设置的,分割窗格的大小是其首选大小,默认情况下仅足够SizeDisplayer的首选大小。每个SizeDisplayer的首选大小由红色矩形表示。分割器会自动放置,使得两个组件的宽度都为其首选宽度。
  2. 使窗口变宽。
    因为分割窗格的调整权重为0.5,额外空间平均分配给左右两个组件。分隔器相应地移动。
  3. 使窗口尽可能狭窄。
    假设窗口使用的是Java外观和感觉提供的装饰,它不会让您将窗口大小调整为小于分割窗格的最小大小,该大小由其包含的SizeDisplayer的最小大小确定。每个SizeDisplayer的最小大小由明亮蓝色矩形表示。
  4. 使窗口变宽一点,然后将分隔器拖动到最右边。
    分隔器只能移动到右侧组件的最小大小允许的位置。
  5. 确保分割窗格小于其首选大小,然后点击“重置”按钮。
    请注意,尽管在应用程序启动时它们的大小相等,但两个SizeDisplayer显示的大小不同。原因是尽管它们的首选大小相等,但它们的最小大小不相等。由于分割窗格无法以其首选大小或更大的尺寸显示它们,因此使用其最小大小对其进行布局。多余的空间平均分配给组件,因为分割窗格的调整权重为0.5。
  6. 扩大分割窗格,使其足够大,以便两个SizeDisplayer以其首选大小显示,然后点击“重置”按钮。
    分隔器再次放置在中间,以使得两个组件的大小相同。

以下是创建SplitPaneDividerDemo GUI的代码:

public class SplitPaneDividerDemo extends JPanel ... {

    private JSplitPane splitPane;
   
    public SplitPaneDividerDemo() {
        super(new BorderLayout());

        Font font = new Font("Serif", Font.ITALIC, 24);

        ImageIcon icon = createImageIcon("images/Cat.gif");
        SizeDisplayer sd1 = new SizeDisplayer("left", icon);
        sd1.setMinimumSize(new Dimension(30,30));
        sd1.setFont(font);
        
        icon = createImageIcon("images/Dog.gif");
        SizeDisplayer sd2 = new SizeDisplayer("right", icon);
        sd2.setMinimumSize(new Dimension(60,60));
        sd2.setFont(font);
        
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                                   sd1, sd2);
        splitPane.setResizeWeight(0.5);
        splitPane.setOneTouchExpandable(true);
        splitPane.setContinuousLayout(true);

        add(splitPane, BorderLayout.CENTER);
        add(createControlPanel(), BorderLayout.PAGE_END);
    }
    ...
}

代码相当简单易懂,除了可能对setContinuousLayout的调用有些疑惑。将continuousLayout属性设置为true时,拆分窗格的内容在用户移动分隔条时将持续绘制。默认情况下,连续布局是关闭的,因为它可能会对性能产生负面影响。但是,在这个示例中使用它是有意义的,因为尽可能使拆分窗格的组件保持最新,可以提高用户体验。

嵌套拆分窗格

下面是一个通过在另一个拆分窗格中嵌套一个拆分窗格来实现三向拆分的程序的图片:

SplitPaneDemo2的快照

如果拆分窗格的顶部部分看起来很熟悉,那是因为程序将由SplitPaneDemo创建的拆分窗格放在了另一个拆分窗格中。简单的JLabel是第二个拆分窗格中的其他组件。这不是嵌套拆分窗格的最实用的用法,但可以说明问题。

启动SplitPaneDemo2示例

以下是代码中有趣的部分,您可以在SplitPaneDemo2.java中找到:

//创建SplitPaneDemo的一个实例
SplitPaneDemo splitPaneDemo = new SplitPaneDemo();
JSplitPane top = splitPaneDemo.getSplitPane();

...
//创建一个普通的标签
label = new JLabel("在列表中点击图像名称。",
                   JLabel.CENTER);

//创建一个拆分窗格并将"top"(一个拆分窗格)
//和JLabel实例放入其中。
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                                      top, label);

有关解决嵌套拆分窗格时可能出现的边框问题的信息,请参考解决常见组件问题

拆分窗格API

以下表格列出了常用的JSplitPane构造方法和方法。您最有可能在JSplitPane对象上调用的其他方法是其超类提供的setPreferredSize等方法。请参阅JComponent API以获取常用继承方法的表格。

使用列表的API可分为以下几类:

设置分割窗格
方法或构造方法 目的
JSplitPane()
JSplitPane(int)
JSplitPane(int, boolean)
JSplitPane(int, Component, Component)
JSplitPane(int, boolean, Component, Component)
创建一个分割窗格。当存在时,int参数表示分割窗格的方向,可以是HORIZONTAL_SPLIT(默认值)或VERTICAL_SPLIT。当存在时,boolean参数设置用户拖动分割窗格时组件是否持续重绘。如果不指定,此选项(称为continuous layout)将被关闭。Component参数分别设置初始左侧和右侧,或上部和下部组件。
void setOrientation(int)
int getOrientation()
设置或获取分割窗格的方向。使用HORIZONTAL_SPLITVERTICAL_SPLITJSplitPane中定义。如果不指定,分割窗格将水平分割。
void setDividerSize(int)
int getDividerSize()
设置或获取分割线的大小(以像素为单位)。
void setContinuousLayout(boolean)
boolean isContinuousLayout()
设置或获取分割窗格在用户拖动分割线时是否持续布局和绘制组件。默认情况下,持续布局被关闭。
void setOneTouchExpandable(boolean)
boolean isOneTouchExpandable()
设置或获取分割窗格是否显示一个控制按钮在分割线上用于展开/折叠分割窗格。默认情况下,取决于外观和感觉。在Java外观和感觉中,默认情况下关闭。
管理分割窗格的内容
方法 目的
void setTopComponent(Component)
void setBottomComponent(Component)
void setLeftComponent(Component)
void setRightComponent(Component)
Component getTopComponent()
Component getBottomComponent()
Component getLeftComponent()
Component getRightComponent()
设置或获取指定的组件。每个方法都可以在分割窗格的方向无关的情况下工作。顶部和左侧等效,底部和右侧等效。
void remove(Component)
void removeAll()
从分割窗格中移除指定的组件。
void add(Component) 将组件添加到分割窗格中。您只能向分割窗格添加两个组件。第一个添加的组件是顶部/左侧组件。第二个添加的组件是底部/右侧组件。任何尝试添加更多组件都会导致异常。
定位分割器
方法 目的
void setDividerLocation(double)
void setDividerLocation(int)
int getDividerLocation()
设置或获取当前的分割器位置。在设置分割器位置时,可以指定新位置为百分比(double)或像素位置(int)。
void resetToPreferredSizes() 将分割器移动到两个组件的首选大小。这是拆分窗格在启动时分割自身的方式,除非另有指定。
void setLastDividerLocation(int)
int getLastDividerLocation()
设置或获取分割器的先前位置。
int getMaximumDividerLocation()
int getMinimumDividerLocation()
获取分割器的最小和最大位置。这些是通过设置拆分窗格的两个组件的最小大小来隐式设置的。
void setResizeWeight(float)
float getResizeWeight()
设置或获取拆分窗格的调整权重,取值范围为0.0(默认值)到1.0。有关调整权重的说明和使用调整权重的示例,请参见定位分割器和限制其范围

使用分割面板的示例

这个表格展示了一些使用JSplitPane的示例以及这些示例的描述。

示例 描述位置 备注
SplitPaneDemo 本页和如何使用列表 展示了一个水平分割的分割面板。
SplitPaneDividerDemo 本页 演示了如何使用组件大小信息和调整权重来定位分隔条。
SplitPaneDemo2 本页 将一个分割面板放在另一个分割面板中,创建一个三向分割。
TreeDemo 如何使用树 使用垂直分割的分割面板将一个树(在滚动面板中)和一个编辑器面板(在滚动面板中)分开。不使用一键展开功能。
TextComponentDemo 文本组件特性 使用垂直分割的分割面板将一个文本面板和一个文本区域分开,两者都在滚动面板中。
TextSamplerDemo 文本组件特性 使用垂直分割和调整权重为0.5的分割面板将一个文本面板和一个编辑器面板分开,两者都在滚动面板中。分割面板位于具有相当复杂布局的容器的右半部分。使用了诸如GridLayoutBorderLayout的布局管理器,以及分割面板的调整权重,确保滚动面板中的组件共享所有额外空间。
ListSelectionDemo 如何编写列表选择监听器 使用垂直分割的分割面板将一个上面板(包含一个列表和一个表格,都在滚动面板中)和一个下面板(包含一个组合框和一个滚动面板)分开。下面板使用边界布局使得组合框小而滚动面板占据大部分空间。

上一页: 如何使用Spinner
下一页: 如何使用选项卡窗格