本教程针对JDK 8编写。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
有关Java SE 9和后续版本中更新的语言功能的摘要,请参阅Java语言变化。
有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息,请参阅JDK发行说明。
JSplitPane
显示两个组件,可以并排或者上下排列。用户可以通过拖动两个组件之间的分隔条来指定每个组件占用的空间比例。您可以通过将一个分割窗格放入另一个分割窗格中来将屏幕空间划分给三个或更多组件,如嵌套分割窗格中所述。
通常情况下,您不直接将感兴趣的组件添加到分割窗格中,而是将每个组件放入一个滚动窗格中,然后将滚动窗格放入分割窗格中。这样,用户可以查看感兴趣组件的任何部分,而无需组件占用大量屏幕空间或适应不同大小的屏幕空间。
下面是一个应用程序的图片,使用分割窗格并排显示一个列表和一张图片:
下面是创建和设置分割窗格的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
方法将它们打开。
分割窗格的分隔符的范围部分取决于分割窗格内组件的最小大小。有关详细信息,请参见定位分隔符并限制其范围。
本节的其余部分包括以下主题:
程序可以使用以下四种方法动态设置分割窗格的两个组件:
setLeftComponent
setRightComponent
setTopComponent
setBottomComponent
无论分割窗格当前的分割方向如何,您都可以随时使用这些方法中的任何一个。调用setLeftComponent
和setTopComponent
是等效的,它们将指定的组件设置在顶部或左侧位置,具体取决于分割窗格当前的分割方向。类似地,调用setRightComponent
和setBottomComponent
是等效的。这些方法将用新的组件替换该位置上的任何组件。
与其他容器一样,JSplitPane
支持add
方法。分割窗格将第一个添加的组件放在左侧或顶部位置。使用add
的危险在于您可能会不经意地多次调用它,这种情况下分割窗格的布局管理器将抛出一个看起来相当晦涩的异常。如果您正在使用add
方法且分割窗格已经有组件,您需要首先使用remove
将现有组件移除。
如果在分割窗格中只放置一个组件,则分隔符将固定在分割窗格的右侧或底部,具体取决于分割方向。
要使分割窗格正常工作,通常需要设置分割窗格中组件的最小大小以及分割窗格或其包含组件的首选大小。选择应该设置哪些大小是一门需要理解分割窗格的首选大小和分隔符位置是如何确定的艺术。在详细讨论之前,让我们再次看一下SplitPaneDemo。或者,如果你赶时间,你可以跳到规则列表。
pack
方法设置的,分割窗格处于其首选大小,SplitPaneDemo恰好显式地设置了它。分隔符会自动放置,使左组件达到其首选宽度,剩余的空间全部给右组件。现在你已经看到了分割窗格的默认行为,我们可以告诉你背后发生的事情以及你可以如何影响它。在这个讨论中,当我们提到一个组件的首选或最小大小时,我们通常是指如果分割窗格是水平的,组件的首选或最小宽度,或者如果分割窗格是垂直的,组件的首选或最小高度。
默认情况下,拆分窗格的首选大小和分隔符位置的初始化是基于两个组件的首选大小。如果拆分窗格没有以首选大小显示,并且程序没有显式设置分隔符位置,那么分隔符的初始位置(以及两个组件的大小)取决于一个称为“调整权重”的拆分窗格属性。如果拆分窗格最初处于其首选大小或更大,则包含的组件在调整大小权重之前以其首选大小开始。如果拆分窗格最初太小而无法显示两个组件的首选大小,则它们在调整大小权重之前以其最小大小开始。
拆分窗格的调整大小权重的值介于0.0和1.0之间,并确定在设置拆分窗格的大小时,空间如何在两个包含的组件之间分配 - 无论是通过编程设置还是通过用户调整拆分窗格(例如,扩大其包含的窗口)。默认情况下,拆分窗格的调整大小权重为0.0,表示左侧或顶部组件的大小固定,而右侧或底部组件调整其大小以适应剩余空间。将调整大小权重设置为0.5可以均匀地分配任何额外或缺少的空间给两个组件。将调整大小权重设置为1.0使得右侧或底部组件的大小保持不变。然而,当用户拖动分隔符时,调整大小权重不起作用。
只要没有包含的组件的大小低于其最小大小,用户可以将分隔符拖动到任意位置。如果分隔符上有一键按钮,则用户可以使用它们将分隔符完全移动到一侧或另一侧 - 无论组件的最小大小是什么。
现在,您已经了解了影响拆分窗格大小和分隔符位置的因素,以下是一些确保它们良好工作的规则:
setMinimumSize
方法或重写getMinimumSize
方法来设置组件的最小大小。例如,如果您希望用户能够将分隔符拖动到两侧的最大范围:Dimension minimumSize = new Dimension(0, 0); leftComponent.setMinimumSize(minimumSize); rightComponent.setMinimumSize(minimumSize);
如果拆分窗格被赋予了其首选大小,这通常会发生,首选大小取决于包含拆分窗格的布局管理器。另一种选择是在拆分窗格上明确设置大于所包含组件大小的首选大小。
setResizeWeight
来实现:splitPane.setResizeWeight(1.0);
splitPane.setResizeWeight(0.5);
setPreferredSize
方法,调用滚动窗格中的组件的适当方法(例如,对于JList
或JTree
,可以调用setVisibleRowCount
方法)。setDividerLocation
方法。例如,要使左侧组件宽度为150像素:splitPane.setDividerLocation(150 + splitPane.getInsets().left);
要使右侧组件宽度为150像素:
splitPane.setDividerLocation(splitPane.getSize().width - splitPane.getInsets().right - splitPane.getDividerSize() - 150);
splitPane.setDividerLocation(0.25);
请注意,这是根据当前大小实现的,因此只有在拆分窗格可见时才真正有用。
如果想要将分割窗格布局恢复到初始状态,并可能重新定位分割条,可以在分割窗格上调用resetToPreferredSizes()
方法。
revalidate
— 并不足以引起分割窗格重新布局。您还必须调用resetToPreferredSizes
方法。
下面的快照显示了一个名为SplitPaneDividerDemo的示例,该示例演示了分割窗格组件的大小和分隔符的位置。
与SplitPaneDemo一样,SplitPaneDividerDemo具有一个带有一键按钮的水平分割窗格。SplitPaneDividerDemo具有以下附加功能:
resetToPreferredSizes
方法。SizeDisplayer
的自定义JComponent
子类的实例。SizeDisplayer在淡入的背景下显示可选文本(还有可选图像)。更重要的是,它具有显示其首选和最小大小的矩形。pack
方法设置的,分割窗格的大小是其首选大小,默认情况下仅足够SizeDisplayer
的首选大小。每个SizeDisplayer
的首选大小由红色矩形表示。分割器会自动放置,使得两个组件的宽度都为其首选宽度。SizeDisplayer
的最小大小确定。每个SizeDisplayer
的最小大小由明亮蓝色矩形表示。SizeDisplayer
显示的大小不同。原因是尽管它们的首选大小相等,但它们的最小大小不相等。由于分割窗格无法以其首选大小或更大的尺寸显示它们,因此使用其最小大小对其进行布局。多余的空间平均分配给组件,因为分割窗格的调整权重为0.5。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时,拆分窗格的内容在用户移动分隔条时将持续绘制。默认情况下,连续布局是关闭的,因为它可能会对性能产生负面影响。但是,在这个示例中使用它是有意义的,因为尽可能使拆分窗格的组件保持最新,可以提高用户体验。
下面是一个通过在另一个拆分窗格中嵌套一个拆分窗格来实现三向拆分的程序的图片:
如果拆分窗格的顶部部分看起来很熟悉,那是因为程序将由SplitPaneDemo
创建的拆分窗格放在了另一个拆分窗格中。简单的JLabel
是第二个拆分窗格中的其他组件。这不是嵌套拆分窗格的最实用的用法,但可以说明问题。
以下是代码中有趣的部分,您可以在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);
有关解决嵌套拆分窗格时可能出现的边框问题的信息,请参考解决常见组件问题。
以下表格列出了常用的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_SPLIT 或VERTICAL_SPLIT 在JSplitPane 中定义。如果不指定,分割窗格将水平分割。 |
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的分割面板将一个文本面板和一个编辑器面板分开,两者都在滚动面板中。分割面板位于具有相当复杂布局的容器的右半部分。使用了诸如GridLayout 和BorderLayout 的布局管理器,以及分割面板的调整权重,确保滚动面板中的组件共享所有额外空间。 |
ListSelectionDemo |
如何编写列表选择监听器 | 使用垂直分割的分割面板将一个上面板(包含一个列表和一个表格,都在滚动面板中)和一个下面板(包含一个组合框和一个滚动面板)分开。下面板使用边界布局使得组合框小而滚动面板占据大部分空间。 |