如何使用菜单
原文:
docs.oracle.com/javase/tutorial/uiswing/components/menu.html
菜单提供了一种节省空间的方式,让用户从几个选项中选择一个。用户可以使用其他组件进行一对多选择,包括组合框、列表、单选按钮、微调器和工具栏。如果你的任何菜单项执行的操作被另一个菜单项或工具栏按钮复制,那么除了本节,你还应该阅读如何使用操作。
菜单在独特之处在于,按照惯例,它们不会与 UI 中的其他组件放在一起。相反,菜单通常出现在菜单栏中或作为弹出菜单。菜单栏包含一个或多个菜单,并具有习惯的、平台相关的位置 通常位于窗口顶部。弹出菜单是一个在用户进行平台特定鼠标操作(例如按下右键)后才可见的菜单,弹出菜单会出现在光标下方。
以下图显示了许多与菜单相关的组件:菜单栏、菜单、菜单项、单选按钮菜单项、复选框菜单项和分隔线。正如你所见,菜单项可以具有图像、文本或两者。你还可以指定其他属性,如字体和颜色。
本节的其余部分将教你有关菜单组件并告诉你如何使用各种菜单功能:
-
菜单组件层次结构
-
创建菜单
-
处理菜单项的事件
-
启用键盘操作
-
弹出菜单
-
自定义菜单布局
-
菜单 API
-
使用菜单的示例
菜单组件层次结构
这是与菜单相关类的继承层次结构的图片:
正如图所示,菜单项(包括菜单)只是按钮。你可能想知道,如果菜单只是一个按钮,它如何显示其菜单项。答案是,当菜单被激活时,它会自动弹出一个显示菜单项的弹出菜单。
创建菜单
以下代码创建了显示在菜单部分开头附近的菜单。粗体代码行创建并连接菜单对象;其他代码设置或自定义菜单对象。你可以在MenuLookDemo.java
中找到整个程序。其他所需文件在示例索引中列出。
试试这个:
- 点击“启动”按钮以使用Java™ Web Start运行 MenuLook 演示(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
因为这段代码没有事件处理,菜单除了外观上看起来正常外并没有实际作用。如果运行示例,您会注意到尽管缺少自定义事件处理,菜单和子菜单在应该出现时会出现,并且当用户选择时复选框和单选按钮会做出适当响应。
*//Where the GUI is created:*
JMenuBar menuBar;
JMenu menu, submenu;
JMenuItem menuItem;
JRadioButtonMenuItem rbMenuItem;
JCheckBoxMenuItem cbMenuItem;
//Create the menu bar.
menuBar = new JMenuBar();
//Build the first menu.
menu = new JMenu("A Menu");
menu.setMnemonic(KeyEvent.VK_A);
menu.getAccessibleContext().setAccessibleDescription(
"The only menu in this program that has menu items");
menuBar.add(menu);
//a group of JMenuItems
menuItem = new JMenuItem("A text-only menu item",
KeyEvent.VK_T);
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_1, ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription(
"This doesn't really do anything");
menu.add(menuItem);
menuItem = new JMenuItem("Both text and icon",
new ImageIcon("images/middle.gif"));
menuItem.setMnemonic(KeyEvent.VK_B);
menu.add(menuItem);
menuItem = new JMenuItem(new ImageIcon("images/middle.gif"));
menuItem.setMnemonic(KeyEvent.VK_D);
menu.add(menuItem);
//a group of radio button menu items
menu.addSeparator();
ButtonGroup group = new ButtonGroup();
rbMenuItem = new JRadioButtonMenuItem("A radio button menu item");
rbMenuItem.setSelected(true);
rbMenuItem.setMnemonic(KeyEvent.VK_R);
group.add(rbMenuItem);
menu.add(rbMenuItem);
rbMenuItem = new JRadioButtonMenuItem("Another one");
rbMenuItem.setMnemonic(KeyEvent.VK_O);
group.add(rbMenuItem);
menu.add(rbMenuItem);
//a group of check box menu items
menu.addSeparator();
cbMenuItem = new JCheckBoxMenuItem("A check box menu item");
cbMenuItem.setMnemonic(KeyEvent.VK_C);
menu.add(cbMenuItem);
cbMenuItem = new JCheckBoxMenuItem("Another one");
cbMenuItem.setMnemonic(KeyEvent.VK_H);
menu.add(cbMenuItem);
//a submenu
menu.addSeparator();
submenu = new JMenu("A submenu");
submenu.setMnemonic(KeyEvent.VK_S);
menuItem = new JMenuItem("An item in the submenu");
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_2, ActionEvent.ALT_MASK));
submenu.add(menuItem);
menuItem = new JMenuItem("Another item");
submenu.add(menuItem);
menu.add(submenu);
//Build second menu in the menu bar.
menu = new JMenu("Another Menu");
menu.setMnemonic(KeyEvent.VK_N);
menu.getAccessibleContext().setAccessibleDescription(
"This menu does nothing");
menuBar.add(menu);
...
frame.setJMenuBar(*theJMenuBar*);
正如代码所示,要为JFrame
设置菜单栏,您可以使用setJMenuBar
方法。要将JMenu
添加到JMenuBar
,您可以使用add(JMenu)
方法。要向JMenu
添加菜单项和子菜单,您可以使用add(JMenuItem)
方法。
注意:
菜单项,就像其他组件一样,最多可以在一个容器中。如果尝试将菜单项添加到第二个菜单中,菜单项将在添加到第二个菜单之前从第一个菜单中移除。要实现多个执行相同操作的组件,请参阅如何使用操作。
前述代码中的其他方法包括setAccelerator
和setMnemonic
,稍后在启用键盘操作中进行讨论。setAccessibleDescription
方法在如何支持辅助技术中进行讨论。
处理菜单项的事件
要检测用户选择JMenuItem
时,您可以监听动作事件(就像您为JButton
所做的那样)。要检测用户选择JRadioButtonMenuItem
时,您可以监听动作事件或项目事件,如如何使用单选按钮中所述。对于JCheckBoxMenuItem
,通常监听项目事件,如如何使用复选框中所述。
试试这个:
- 点击“启动”按钮以使用Java™ Web Start运行菜单演示(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
这是实现事件处理的代码:
public class MenuDemo ... implements ActionListener,
ItemListener {
...
public MenuDemo() {
*//...for each JMenuItem instance:*
menuItem.addActionListener(this);
...
*//for each JRadioButtonMenuItem:*
rbMenuItem.addActionListener(this);
...
*//for each JCheckBoxMenuItem:*
cbMenuItem.addItemListener(this);
...
}
public void actionPerformed(ActionEvent e) {
*//...Get information from the action event...
//...Display it in the text area...*
}
public void itemStateChanged(ItemEvent e) {
*//...Get information from the item event...
//...Display it in the text area...*
}
有关处理动作和项目事件的示例,请参见按钮、单选按钮和复选框部分,以及本节末尾的示例列表。
启用键盘操作
菜单支持两种键盘替代方式:助记符和加速键。助记符提供了一种使用键盘导航菜单层次结构的方法,增加了程序的可访问性。另一方面,加速键提供了绕过导航菜单层次结构的键盘快捷方式。助记符适用于所有用户;加速键适用于高级用户。
助记符是使已经可见的菜单项被选择的键。例如,在MenuDemo
中,第一个菜单的助记符是 A,其第二个菜单项的助记符是 B。这意味着,当您在 Java 外观下运行MenuDemo
时,按下 Alt 和 A 键会使第一个菜单出现。当第一个菜单可见时,按下 B 键(带有或不带有 Alt)会选择第二个菜单项。菜单项通常通过在菜单项文本中的助记字符的第一次出现下划线来显示其助记符,如下面的快照所示。
加速键是一种键组合,导致选择菜单项,无论它是否可见。例如,在MenuDemo
中按下 Alt 和 2 键会选择第一个菜单的子菜单中的第一个项目,而不会弹出任何菜单。只有叶子菜单项 不弹出其他菜单的菜单 可以有加速键。以下快照显示了 Java 外观如何显示具有加速键的菜单项。
您可以在构造菜单项时或使用setMnemonic
方法时指定助记符。要指定加速键,请使用setAccelerator
方法。以下是设置助记符和加速键的示例:
//Setting the mnemonic when constructing a menu item:
menuItem = new JMenuItem("A text-only menu item",
KeyEvent.VK_T);
//Setting the mnemonic after creation time:
menuItem.setMnemonic(KeyEvent.VK_T);
//Setting the accelerator:
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_T, ActionEvent.ALT_MASK));
如您所见,您可以通过指定用户应按下的KeyEvent
常量来设置助记符。要指定加速键,必须使用KeyStroke
对象,该对象结合了一个键(由KeyEvent
常量指定)和一个修饰键掩码(由ActionEvent
常量指定)。
注意:
由于弹出菜单与常规菜单不同,不总是由组件包含,因此弹出菜单项中的加速键在弹出菜单不可见时不起作用。
弹出菜单
要显示弹出菜单(JPopupMenu
),必须在每个应与弹出菜单关联的组件上注册鼠标侦听器。鼠标侦听器必须检测用户请求显示弹出菜单。
弹出菜单应该如何显示的确切手势因外观和感觉而异。在 Microsoft Windows 中,用户按照惯例在鼠标光标位于启用弹出菜单的组件上时释放右鼠标按钮来显示弹出菜单。在 Java 外观中,通常的触发方式是按下右鼠标按钮(对于在释放按钮时弹出并消失的弹出菜单)或单击它(对于保持弹出状态的弹出菜单)。
试试这个:
- 点击“启动”按钮以使用Java™ Web Start运行 PopupMenu 演示(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
*//...where instance variables are declared:*
JPopupMenu popup;
*//...where the GUI is constructed:*
//Create the popup menu.
popup = new JPopupMenu();
menuItem = new JMenuItem("A popup menu item");
menuItem.addActionListener(this);
popup.add(menuItem);
menuItem = new JMenuItem("Another popup menu item");
menuItem.addActionListener(this);
popup.add(menuItem);
//Add listener to components that can bring up popup menus.
MouseListener popupListener = new PopupListener();
output.addMouseListener(popupListener);
menuBar.addMouseListener(popupListener);
...
class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
}
弹出菜单有一些有趣的实现细节。其中之一是每个菜单都有一个关联的弹出菜单。当菜单被激活时,它使用其关联的弹出菜单来显示其菜单项。
另一个细节是,弹出菜单本身使用另一个组件来实现包含菜单项的窗口。根据弹出菜单显示的情况,弹出菜单可能使用轻量级组件(如JPanel
)、“中等重量”组件(如Panel
)或重量级窗口(继承自Window
)来实现其“窗口”。
轻量级弹出窗口比重量级窗口更高效,但在 Java SE 平台 6 Update 12 发布之前,如果 GUI 中有任何重量级组件,它们的效果不佳。具体来说,当轻量级弹出显示区域与重量级组件的显示区域相交时,重量级组件会显示在顶部。这是在 6u12 发布之前我们建议不要混合使用重量级和轻量级组件的原因之一。如果您正在使用较旧的版本并且绝对需要在 GUI 中使用重量级组件,则可以调用JPopupMenu.setLightWeightPopupEnabled(false)
来禁用轻量级弹出窗口。有关在 6u12 版本及更高版本中混合组件的信息,请参阅混合重量级和轻量级组件。
自定义菜单布局
因为菜单由普通的 Swing 组件组成,所以你可以轻松地自定义它们。例如,你可以向JMenu
或JMenuBar
添加任何轻量级组件。而且因为JMenuBar
使用了BoxLayout
,你可以通过向其添加不可见组件来自定义菜单栏的布局。以下是向菜单栏添加填充物组件的示例,以便最后一个菜单位于菜单栏的右边缘:
*//...create and add some menus...*
menuBar.add(Box.createHorizontalGlue());
*//...create the rightmost menu...*
menuBar.add(rightMenu);
试试这个:
- 点击启动按钮以使用Java™ Web Start运行 MenuGlue Demo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
这是 MenuGlueDemo 显示的修改后的菜单布局:
改变菜单外观的另一种方法是改变用于控制它们的布局管理器。例如,你可以将菜单栏的布局管理器从默认的左到右的BoxLayout
更改为诸如GridLayout
之类的东西。
试试这个:
- 点击启动按钮以使用Java™ Web Start运行 MenuLayout Demo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
这是MenuLayoutDemo
创建的菜单布局的图片:
菜单 API
以下表格列出了常用的菜单构造函数和方法。使用菜单的 API 属于以下类别:
-
创建和设置菜单栏
-
创建和填充菜单
-
创建、填充和控制弹出菜单
-
实现菜单项
创建和设置菜单栏
构造函数或方法 | 目的 |
---|---|
JMenuBar() | 创建一个菜单栏。 |
JMenu add(JMenu) | 将菜单添加到菜单栏的末尾。 |
| void setJMenuBar(JMenuBar) JMenuBar getJMenuBar()
(在JApplet
、JDialog
、JFrame
、JInternalFrame
、JRootPane
中) | 设置或获取 applet、dialog、frame、internal frame 或 root pane 的菜单栏。 |
创建和填充菜单
构造函数或方法 | 目的 |
---|
JMenu(Action) | 创建一个菜单。字符串指定菜单显示的文本。Action
指定菜单的文本和其他属性(参见如何使用操作)。 |
JMenuItem add(JMenuItem) JMenuItem add(String) | 将菜单项添加到菜单的末尾。如果参数是一个字符串,则菜单会自动创建一个显示指定文本的JMenuItem 对象。 |
---|---|
void addSeparator() | 在菜单的末尾添加一个分隔符。 |
| JMenuItem insert(JMenuItem, int) void insert(String, int)
void insertSeparator(int) | 在指定位置向菜单中插入菜单项或分隔符。第一个菜单项在位置 0,第二个在位置 1,依此类推。JMenuItem
和String
参数在对应的add
方法中的处理方式相同。 |
| void remove(JMenuItem) void remove(int)
void removeAll() | 从菜单中移除指定的项。如果参数是一个整数,则指定要移除的菜单项的位置。 |
创建、填充和控制弹出菜单
构造函数或方法 | 目的 |
---|---|
JPopupMenu() JPopupMenu(String) | 创建一个弹出菜单。可选的字符串参数指定外观和感觉可能作为弹出窗口的一部分显示的标题。 |
JMenuItem add(JMenuItem) JMenuItem add(String) | 将菜单项添加到弹出菜单的末尾。如果参数是一个字符串,则菜单会自动创建一个显示指定文本的JMenuItem 对象。 |
void addSeparator() | 在弹出菜单的末尾添加一个分隔符。 |
void insert(Component, int) | 在指定位置将菜单项插入菜单中。第一个菜单项在位置 0,第二个在位置 1,依此类推。Component 参数指定要添加的菜单项。 |
void remove(int) void removeAll() | 从菜单中移除指定的项目。如果参数是一个整数,则指定要移除的菜单项的位置。 |
static void setLightWeightPopupEnabled(boolean) | 默认情况下,Swing 使用轻量级组件来实现菜单的窗口。如果在 Swing 程序中使用任何重量级组件,可能会出现问题,如弹出菜单中所述。(这是避免使用重量级组件的几个原因之一。)作为解决方法,调用JPopupMenu.setLightWeightPopupEnabled(false) 。 |
void show(Component, int, int) | 在指定的x,y位置(由整数参数按顺序指定)在指定组件的坐标系中显示弹出菜单。 |
菜单项的实现
构造函数或方法 | 目的 |
---|
| JMenuItem() JMenuItem(String)
JMenuItem(String, int)的创建方法受到Java中的启发。
JMenuItem(Action) | 创建一个普通的菜单项。如果存在图标参数,则指定菜单项应显示的图标。类似地,字符串参数指定菜单项应显示的文本。整数参数指定要使用的键盘助记符。您可以指定KeyEvent类中定义的任何相关 VK 常量。例如,要指定 A 键,请使用KeyEvent.VK_A
。具有Action
参数的构造函数设置菜单项的Action
,导致菜单项的属性从Action
初始化。有关详细信息,请参阅如何使用操作。 |
| JCheckBoxMenuItem() JCheckBoxMenuItem(String)的创建方法受到Java中的启发。
JCheckBoxMenuItem(Icon)的创建方法受到Java中的启发。
JCheckBoxMenuItem(String, Icon)的创建方法受到Java中的启发。
JCheckBoxMenuItem(String, boolean)的创建方法受到Java中的启发。
JCheckBoxMenuItem(String, Icon, boolean) | 创建一个外观和行为类似复选框的菜单项。如果有字符串参数,则指定菜单项应显示的文本。如果为布尔参数指定true
,则菜单项最初为选中状态(已选中)。否则,菜单项最初未选中。 |
| JRadioButtonMenuItem() JRadioButtonMenuItem(String)的创建方法受到Java中的启发。
JRadioButtonMenuItem(Icon)的创建方法受到Java中的启发。
JRadioButtonMenuItem(String, Icon)的创建方法受到Java中的启发。
JRadioButtonMenuItem(String, boolean)的创建方法受到Java中的启发。
JRadioButtonMenuItem(Icon, boolean)
JRadioButtonMenuItem(String, Icon, boolean) | 创建一个外观和行为类似单选按钮的菜单项。如果有字符串参数,则指定菜单项应显示的文本。如果为布尔参数指定true
,则菜单项最初被选中。否则,菜单项最初未选中。 |
| void setState(boolean) boolean getState()
(在JCheckBoxMenuItem
中) | 设置或获取复选框菜单项的选择状态。 |
void setEnabled(boolean) | 如果参数为 true,则启用菜单项。否则,禁用菜单项。 |
---|---|
void setMnemonic(int) | 设置启用键盘导航到菜单或菜单项的助记符。使用KeyEvent 类中定义的 VK 常量之一。 |
void setAccelerator(KeyStroke) | 设置激活菜单项的加速键。 |
void setActionCommand(String) | 设置菜单项执行的操作的名称。 |
void addActionListener(ActionListener) void addItemListener(ItemListener) | 向菜单项添加事件侦听器。有关详细信息,请参考处理菜单项事件。 |
void setAction(Action) | 设置与菜单项关联的Action 。有关详细信息,请参阅如何使用操作。 |
许多前述方法都是从AbstractButton 继承而来的。查看按钮 API 以获取AbstractButton 提供的其他有用方法的信息。 |
使用菜单的示例
菜单在我们的一些示例中使用。
示例 | 描述位置 | 注释 |
---|---|---|
MenuLookDemo |
此部分(创建菜单) | 一个简单的示例,创建除弹出菜单之外的所有类型的菜单,但不处理来自菜单项的事件。 |
MenuDemo |
此部分(处理菜单项事件) | 为MenuLookDemo 添加事件处理。 |
PopupMenuDemo |
此部分(弹出菜单) | 为MenuDemo 添加弹出菜单。 |
MenuGlueDemo |
此部分(自定义菜单布局) | 通过向菜单栏添加不可见组件演示影响菜单布局。 |
MenuLayoutDemo |
此部分(自定义菜单布局) | 实现侧向打开的菜单,排列在垂直菜单栏中。 |
MenuSelectionManagerDemo |
| 为 MenuDemo 添加高亮检测。要查看此功能,请单击菜单,然后将鼠标移动到任何菜单项或子菜单上。每秒钟,文本区域将更新有关当前高亮菜单项的信息,不要与用户最终选择的菜单项混淆。此演示使用默认的MenuSelectionManager ,用于跟踪菜单层次结构的状态。 |
ActionDemo |
如何使用操作 | 使用Action 对象实现通过工具栏按钮提供的功能的菜单项。 |
Framework |
| 弹出多个具有菜单栏的相同框架。 |
InternalFrameDemo |
如何使用内部框架 | 使用菜单项创建窗口。 |
查看使用 JavaFX UI 控件:菜单教程,了解如何在 JavaFX 中创建菜单。
如何使用面板
原文:
docs.oracle.com/javase/tutorial/uiswing/components/panel.html
JPanel
类提供了用于轻量级组件的通用容器。默认情况下,面板除了自己的背景之外不会添加颜色;但是,您可以轻松地向其添加边框并自定义其绘制。详细信息请参见执行自定义绘制。
在许多外观类型中,面板默认是不透明的。不透明的面板作为内容窗格效果很好,并且可以帮助高效绘制,如使用顶级容器中所述。您可以通过调用setOpaque
方法来改变面板的透明度。透明面板不绘制背景,因此底部的任何组件都会透过显示出来。
一个例子
下图展示了一个有颜色的Converter
应用程序版本,更详细地讨论在使用模型中。
Converter
示例以多种方式使用面板:
-
在前面的快照中,一个被涂成红色的
JPanel
实例作为应用程序框架的内容窗格。这个内容窗格使用自上而下的BoxLayout
来布局其内容,并使用一个空边框在它们周围留出 5 像素的空间。有关内容窗格的信息,请参见使用顶级容器。 -
两个自定义
JPanel
子类的实例,命名为ConversionPanel
,被用来包含组件并协调组件之间的通信,这些ConversionPanel
面板也有标题边框,描述其内容并用一条线围住内容。每个ConversionPanel
面板使用从左到右的BoxLayout
对象来布局其内容。 -
在每个
ConversionPanel
中,一个被涂成品红色的JPanel
实例用于确保组合框的正确大小和位置。每个这样的JPanel
实例使用自上而下的BoxLayout
对象(通过一个不可见的填充组件的帮助)来布局组合框。 -
在每个
ConversionPanel
中,一个未命名的JPanel
子类的实例,被涂成蓝色,将两个组件(文本字段和滑块)分组并限制它们的大小。每个这样的JPanel
实例使用自上而下的BoxLayout
对象来布局其内容。
这就是Converter
应用程序的正常外观。
正如Converter
示例所展示的,面板对于组合组件、简化组件布局以及在组件组周围放置边框非常有用。本节的其余部分提供了有关组合和布局组件的提示。有关使用边框的信息,请参见如何使用边框。
设置布局管理器
与其他容器一样,面板使用布局管理器来定位和调整其组件的大小。默认情况下,面板的布局管理器是FlowLayout
的一个实例,它将面板的内容放在一行中。您可以通过调用setLayout
方法或在创建面板时指定布局管理器来轻松使面板使用任何其他布局管理器。由于避免了不必要创建FlowLayout
对象,因此后一种方法在性能方面更可取。
这是在创建面板时设置布局管理器的示例。
JPanel p = new JPanel(new BorderLayout()); //PREFERRED!
这种方法不适用于BoxLayout
,因为BoxLayout
构造函数需要一个现有的容器。这是一个使用BoxLayout
的示例。
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
添加组件
当您向面板添加组件时,您使用add
方法。您指定给add
方法的参数取决于面板使用的布局管理器。当布局管理器为FlowLayout
、BoxLayout
、GridLayout
或SpringLayout
时,您通常会使用单参数的add
方法,如下所示:
aFlowPanel.add(aComponent);
aFlowPanel.add(anotherComponent);
当布局管理器为BorderLayout
时,您需要提供一个参数,指定添加的组件在面板内的位置。例如:
aBorderPanel.add(aComponent, BorderLayout.CENTER);
aBorderPanel.add(anotherComponent, BorderLayout.PAGE_END);
使用GridBagLayout
,您可以使用add
方法,但必须以某种方式为每个组件指定网格包约束。
有关选择和使用标准布局管理器的信息,请参阅使用布局管理器。
面板 API
JPanel
类本身的 API 很少。您最有可能在JPanel
对象上调用的方法是它从其超类继承的方法 JComponent
、Container
和Component
。以下表列出了您最有可能使用的 API,除了与边框和布局提示相关的方法。有关所有JComponent
对象都可以使用的 API 的更多信息,请参阅 JComponent 类。
-
创建一个
JPanel
-
管理容器的组件
-
设置或获取布局管理器
创建一个JPanel
构造函数 | 目的 |
---|---|
JPanel() JPanel(LayoutManager) | 创建一个面板。LayoutManager 参数为新面板提供布局管理器。默认情况下,面板使用FlowLayout 来布置其组件。 |
管理容器的组件
方法 | 目的 |
---|
| void add(Component) void add(Component, int)
void add(Component, Object, int)
void add(String, Component) | 将指定的组件添加到面板中。当存在时,int
参数是容器中组件的索引。默认情况下,第一个添加的组件位于索引 0,第二个位于索引 1,依此类推。Object
参数取决于布局管理器,通常为布局管理器提供有关添加组件的定位和其他布局约束的信息。String
参数类似于Object
参数。 |
int getComponentCount() | 获取此面板中的组件数。 |
---|
| Component getComponent(int) Component getComponentAt(int, int)
Component getComponentAt(Point)
Component[] getComponents() | 获取指定的组件或组件。您可以根据索引或x, y位置获取组件。 |
| void remove(Component) void remove(int)
void removeAll() | 移除指定的组件。 |
设置或获取布局管理器
方法 | 目的 |
---|---|
void setLayout(LayoutManager) LayoutManager getLayout() | 设置或获取此面板的布局管理器。布局管理器负责根据某种理念在面板的边界内定位面板的组件。 |
使用面板的示例
此课程中的许多示例使用JPanel
对象。以下表格列出了一些。
示例 | 描述位置 | 注意事项 |
---|---|---|
Converter |
这一部分 | 使用五个面板,其中四个使用BoxLayout ,一个使用GridLayout 。这些面板使用边框,并根据需要使用大小和对齐提示来影响布局。 |
ListDemo |
如何使用列表 | 使用一个面板,默认使用FlowLayout 管理器,将三个组件居中排列在一行。 |
ToolBarDemo |
如何使用工具栏 | 使用一个面板作为内容窗格。该面板包含三个组件,由BorderLayout 布局。 |
BorderDemo |
如何使用边框 | 包含许多具有各种边框的面板。几个面板使用BoxLayout 。 |
BoxLayoutDemo |
如何使用 BoxLayout | 演示了一个使用 Swing 的BoxLayout 管理器的面板。 |
如何使用密码字段
原文:
docs.oracle.com/javase/tutorial/uiswing/components/passwordfield.html
JPasswordField
类是JTextField
的子类,为密码输入提供了专门的文本字段。出于安全原因,密码字段不显示用户输入的字符。相反,该字段显示与键入字符不同的字符,例如星号'*'。作为另一个安全预防措施,密码字段将其值存储为字符数组,而不是字符串。与普通的文本字段一样,当用户指示文本输入完成时,例如按下回车按钮时,密码字段会触发操作事件。
这是一个演示的图片,打开一个小窗口并提示用户输入密码。
点击“启动”按钮以使用Java™ Web Start运行 PasswordDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
密码是"bugaboo"。密码"bugaboo"仅为示例。在生产系统中使用安全的身份验证方法。您可以在PasswordDemo.java
中找到此程序的完整代码。以下是创建和设置密码字段的代码:
passwordField = new JPasswordField(10);
passwordField.setActionCommand(OK);
passwordField.addActionListener(this);
传递给JPasswordField
构造函数的参数指示字段的首选大小,在这种情况下至少为 10 列宽。默认情况下,密码字段显示每个键入字符的点。如果要更改回显字符,请调用setEchoChar
方法。然后,代码向密码字段添加了一个操作监听器,该监听器检查用户键入的值。以下是操作监听器的actionPerformed
方法的实现:
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (OK.equals(cmd)) { //Process the password.
char[] input = passwordField.getPassword();
if (isPasswordCorrect(input)) {
JOptionPane.showMessageDialog(controllingFrame,
"Success! You typed the right password.");
} else {
JOptionPane.showMessageDialog(controllingFrame,
"Invalid password. Try again.",
"Error Message",
JOptionPane.ERROR_MESSAGE);
}
//Zero out the possible password, for security.
Arrays.fill(input, '0');
passwordField.selectAll();
resetFocus();
} else *...//handle the Help button...*
}
安全提示: 为了进一步增强安全性,一旦您完成了getPassword
方法返回的字符数组,您应该将其每个元素都设置为零。前面的代码片段展示了如何做到这一点。
通常使用密码字段的程序在执行需要密码的任何操作之前会验证密码。该程序调用一个私有方法 isPasswordCorrect
,该方法将 getPassword
方法返回的值与存储在字符数组中的值进行比较。以下是其代码:
private static boolean isPasswordCorrect(char[] input) {
boolean isCorrect = true;
char[] correctPassword = { 'b', 'u', 'g', 'a', 'b', 'o', 'o' };
if (input.length != correctPassword.length) {
isCorrect = false;
} else {
isCorrect = Arrays.equals (input, correctPassword);
}
//Zero out the password.
Arrays.fill(correctPassword,'0');
return isCorrect;
}
密码字段 API
以下表格列出了常用的 JPasswordField
构造函数和方法。有关密码字段继承的 API 信息,请参阅如何使用文本字段。
常用的 JPasswordField 构造函数和方法
构造函数或方法 | 目的 |
---|
| JPasswordField() JPasswordField(String)
JPasswordField(Document, String, int) | 创建一个密码字段。当存在时,int
参数指定所需的列宽。String
参数包含字段的初始文本。Document
参数为字段提供自定义模型。 |
char[] getPassword() | 将密码作为字符数组返回。 |
---|---|
void setEchoChar(char) char getEchoChar() | 设置或获取代替用户键入的实际字符显示的回显字符。 |
| void addActionListener(ActionListener) void removeActionListener(ActionListener)
(在 JTextField
中定义) | 添加或移除动作监听器。 |
void selectAll() (在 JTextComponent 中定义) |
选择密码字段中的所有字符。 |
---|
使用密码字段的示例
PasswordDemo 是教程中唯一使用 JPasswordField
对象的示例。然而,教程中有许多示例使用 JTextField
对象,其 API 被 JPasswordField
继承。有关更多信息,请参阅使用文本字段的示例。
如果你正在使用 JavaFX 进行编程,请查看密码字段。
如何使用进度条
译文:
docs.oracle.com/javase/tutorial/uiswing/components/progress.html
有时候程序中运行的任务可能需要一段时间才能完成。用户友好的程序会向用户提供一些指示,表明任务正在进行,任务可能需要多长时间,以及已经完成了多少工作。指示工作和可能的进度量的一种方式是使用动画图像。
另一种指示工作的方法是设置等待光标,使用Cursor
类和Component
定义的setCursor
方法。例如,以下代码在光标悬停在container
上时显示等待光标(包括未指定光标的任何组件):
container.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
为了传达任务完成的程度,你可以使用类似这样的进度条:
有时候你无法立即确定长时间运行任务的长度,或者任务可能在完成的同一状态停滞很长时间。你可以通过将进度条设置为不确定模式来展示没有可测量进度的工作。不确定模式下的进度条显示动画以指示工作正在进行。一旦进度条可以显示更有意义的信息,你应该将其切换回默认的确定模式。在 Java 外观中,不确定模式的进度条看起来像这样:
Swing 提供了三个类来帮助你使用进度条:
一个可见的组件,用于图形显示已完成总任务的百分比。查看使用确定性进度条以获取有关使用典型进度条的信息和示例。章节使用不确定模式告诉你如何为显示活动而对进度条进行动画处理,直到任务的范围被确定。
不是一个可见的组件。相反,这个类的一个实例监视任务的进度,并在必要时弹出一个对话框。查看如何使用进度监视器获取详细信息和使用进度监视器的示例。
一个带有附加进度监视器的输入流,用于监视从流中读取的内容。您可以像使用基本 I/O 中描述的其他输入流一样使用此流的实例。您可以通过调用getProgressMonitor
获取流的进度监视器,并按照如何使用进度监视器中的描述进行配置。
在看到进度条和进度监视器实际运行后,决定使用进度条还是进度监视器可以帮助您确定哪种适合您的应用程序。
使用确定性进度条
这是一个小型演示应用程序的图片,该应用程序使用进度条来测量在其自己的线程中运行的任务的进度:
试试这个:
- 点击启动按钮以使用Java™ Web Start运行 ProgressBar Demo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
以下代码来自ProgressBarDemo.java
,创建并设置了进度条:
*//Where member variables are declared:*
JProgressBar progressBar;
...
*//Where the GUI is constructed:*
progressBar = new JProgressBar(0, task.getLengthOfTask());
progressBar.setValue(0);
progressBar.setStringPainted(true);
创建进度条的构造函数设置了进度条的最小值和最大值。您也可以使用setMinimum
和setMaximum
设置这些值。此程序中使用的最小值和最大值为 0 和任务的长度,这是许多程序和任务的典型值。但是,进度条的最小值和最大值可以是任何值,甚至是负值。代码片段还将进度条的当前值设置为 0。
调用setStringPainted
会导致进度条在其边界内显示任务完成的百分比的文本指示。默认情况下,进度条显示其getPercentComplete
方法返回的值格式化为百分比,例如33%。或者,您可以通过调用setString
替换默认值为其他字符串。例如,
if (*/*...half way done...*/*)
progressBar.setString("Half way there!");
当用户点击开始时,会创建并执行内部类Task
的一个实例。
public void actionPerformed(ActionEvent evt) {
startButton.setEnabled(false);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
done = false;
task = new Task();
task.addPropertyChangeListener(this);
task.execute();
}
Task
是javax.swing.SwingWorker
的子类。Task
实例为ProgressBarDemo
执行了三个重要的操作:
-
实例在单独的线程中调用
doInBackground
。这是实际执行长时间任务的地方。在后台线程中使用而不是事件分派线程可以防止用户界面在任务运行时冻结。 -
当后台任务完成时,实例在事件分派线程中调用
done
方法。 -
实例维护一个绑定属性
progress
,该属性更新以指示任务的进度。每次progress
更改时,都会调用propertyChange
方法。
有关SwingWorker
的更多信息,请参阅 Worker Threads and SwingWorker 在 Swing 中的并发性。
ProgressBarDemo
中的后台任务通过在随机时间间隔报告随机进度量来模拟真实任务。propertyChange
方法响应任务的progress
属性的更改,从而更新进度条:
public void propertyChange(PropertyChangeEvent evt) {
if (!done) {
int progress = task.getProgress();
progressBar.setValue(progress);
taskOutput.append(String.format(
"Completed %d%% of task.\n", progress));
}
当后台任务完成时,任务的done
方法会重置进度条:
public void done() {
//Tell progress listener to stop updating progress bar.
done = true;
Toolkit.getDefaultToolkit().beep();
startButton.setEnabled(true);
setCursor(null); //turn off the wait cursor
progressBar.setValue(progressBar.getMinimum());
taskOutput.append("Done!\n");
}
请注意,done
方法将done
字段设置为true
,防止propertyChange
进一步更新进度条。这是必要的,因为对progress
属性的最终更新可能发生在调用done
之后。
使用不确定模式
在ProgressBarDemo2
中,直到实际进度开始,不确定模式被设置:
public void propertyChange(PropertyChangeEvent evt) {
if (!done) {
int progress = task.getProgress();
if (progress == 0) {
progressBar.setIndeterminate(true);
taskOutput.append("No progress yet\n");
} else {
progressBar.setIndeterminate(false);
progressBar.setString(null);
progressBar.setValue(progress);
taskOutput.append(String.format(
"Completed %d%% of task.\n", progress));
}
}
}
代码中的其他更改与字符串显示有关。显示字符串的进度条可能比不显示的进度条更高,作为演示设计者,我们随意决定该进度条仅在默认的确定模式下显示字符串。然而,我们希望避免布局丑陋,这可能会导致进度条在更改模式时改变高度。因此,代码保留了对setStringPainted(true)
的调用,但添加了对setString("")
的调用,以便不显示任何文本。稍后,当进度条从不确定模式切换到确定模式时,调用setString(null)
会使进度条显示其默认字符串。
我们没有做的一个改变是从progress
事件处理程序中删除对progressBar.setValue
的调用。这个调用不会造成任何伤害,因为不确定的进度条不使用其值属性,除非可能在状态字符串中显示它。事实上,尽可能保持进度条的数据最新是一个好习惯,因为一些外观和感觉可能不支持不确定模式。
试试这个:
-
点击启动按钮以使用Java™ Web Start运行 ProgressBar2 演示(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
-
按下Start按钮。请注意,进度条在按下按钮后立即开始动画,然后切换回确定模式(类似于 ProgressBarDemo)。
如何使用进度监视器
现在让我们重写 ProgressBarDemo,使用进度监视器而不是进度条。这是新演示程序 ProgressMonitorDemo 的图片:
试试这个:
-
点击启动按钮以使用Java™ Web Start运行 ProgressMonitor 演示(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
-
按下Start按钮。一段时间后,程序会显示一个进度对话框。
-
点击OK按钮。请注意,即使对话框消失,任务仍在继续。
-
启动另一个任务。对话框弹出后,点击Cancel按钮。对话框消失,任务停止。
进度监视器不能再次使用,因此每次启动新任务时都必须创建一个新的。该程序每次用户通过Start按钮启动新任务时都会创建一个进度监视器。
创建进度监视器的语句如下:
progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this,
"Running a Long Task",
"", 0, task.getLengthOfTask());
此代码使用ProgressMonitor
的唯一构造函数来创建监视器并初始化几个参数:
-
第一个参数提供了由进度监视器弹出的对话框的父组件。
-
第二个参数是描述正在监视的任务性质的字符串。此字符串显示在对话框上。有关此参数的详细信息,请参阅进度监视 API。
-
第三个参数是另一个字符串,用于提供可变的状态说明。示例使用空字符串表示对话框应为可变状态说明腾出空间,但初始时为空。如果为此参数提供
null
,则对话框中将省略说明。示例在每次progress
属性更改时更新说明。同时更新监视器的当前值:int progress = task.getProgress(); String message = String.format("Completed %d%%.\n", progress); progressMonitor.setNote(message); progressMonitor.setProgress(progress); taskOutput.append(message);
-
最后两个参数分别提供对话框中显示的进度条的最小值和最大值。
默认情况下,进度监视器在决定是否弹出对话框之前等待至少 500 毫秒。它还等待进度超过最小值。如果计算出任务将需要超过 2000 毫秒才能完成,进度对话框将出现。要调整最小等待时间,调用setMillisToDecidedToPopup
。要调整对话框出现所需的最小进度时间,调用setMillisToPopup
。
通过这个例子使用进度监视器,添加了一个在使用进度条版本中不存在的功能:用户可以通过在对话框上点击取消按钮来取消任务。以下是示例中检查用户是否取消任务或任务是否正常退出的代码:
if (progressMonitor.isCanceled() || task.isDone()) {
progressMonitor.close();
Toolkit.getDefaultToolkit().beep();
if (progressMonitor.isCanceled()) {
task.cancel(true);
taskOutput.append("Task canceled.\n");
} else {
taskOutput.append("Task completed.\n");
}
startButton.setEnabled(true);
}
请注意,进度监视器本身不会取消任务。它提供了 GUI 和 API,使程序可以轻松地这样做。
决定使用进度条还是进度监视器
如果需要,可以使用进度条:
-
您希望更多地控制进度条的配置。如果直接使用进度条,可以将其设置为不确定状态,使其垂直显示,提供要显示的字符串,在其上注册更改侦听器,并为其提供有界范围模型以控制进度条的最小、最大和当前值。
-
程序需要在进度条旁边显示其他组件。
-
需要多个进度条。对于某些任务,您需要监视多个参数。例如,安装程序可能会监视磁盘空间使用情况以及成功安装的文件数量。
-
需要重复使用进度条。进度条可以重复使用;进度监视器则不行。一旦进度监视器决定显示对话框(或不显示),进度监视器就无法再次执行此操作。
如果需要,可以使用进度监视器:
-
您希望以一种简单的方式在对话框中显示进度。
-
运行的任务是次要的,用户可能对任务的进度不感兴趣。进度监视器提供了一种让用户在任务仍在运行时关闭对话框的方法。
-
您希望以一种简单的方式取消任务。进度监视器为用户提供了一个 GUI 来取消任务。您只需调用进度监视器的
isCanceled
方法,就可以找出用户是否按下了取消按钮。 -
您的任务在运行时定期显示一条简短的消息。进度监视器对话框提供了
setNote
方法,以便任务可以提供关于正在执行的操作的更多信息。例如,安装任务可能会报告每个文件的名称在安装时的情况。 -
任务可能不需要很长时间才能完成。您可以决定在何时运行的任务花费的时间足够长,以至于需要让用户知道。如果任务在您设置的时间范围内完成,进度监视器不会弹出对话框。
如果您决定使用进度监视器并且您正在监视的任务正在从输入流中读取,请使用ProgressMonitorInputStream
类。
进度监视 API
以下表格列出了常用的用于使用进度条和进度监视器的 API。因为JProgressBar
是JComponent
的子类,您可能会在JProgressBar
上调用的其他方法列在 The JComponent Class 中。请注意,ProgressMonitor
是Object
的子类,不是一个可视组件。
用于监视进度的 API 分为以下几类:
-
创建进度条
-
设置或获取进度条的约束/值
-
控制进度条的外观
-
创建进度监视器
-
配置进度监视器
-
终止进度监视器
创建进度条
构造函数 | 目的 |
---|---|
JProgressBar() JProgressBar(int, int) | 创建水平进度条。无参数构造函数将进度条初始化为最小值和初始值为 0,最大值为 100。具有两个整数参数的构造函数指定最小值和最大值。 |
JProgressBar(int) JProgressBar(int, int, int) | 创建具有指定方向的进度条,可以是JProgressBar.HORIZONTAL 或JProgressBar.VERTICAL 。可选的第二个和第三个参数指定最小值和最大值。 |
JProgressBar(BoundedRangeModel) | 使用指定的范围模型创建水平进度条。 |
设置或获取进度条的约束/值
方法 | 目的 |
---|---|
void setValue(int) int getValue() | 设置或获取进度条的当前值。该值受最小值和最大值的约束。 |
double getPercentComplete() | 获取进度条的完成百分比。 |
void setMinimum(int) int getMinimum() | 设置或获取进度条的最小值。 |
void setMaximum(int) int getMaximum() | 设置或获取进度条的最大值。 |
void setModel(BoundedRangeModel) BoundedRangeModel getModel() | 设置或获取进度条使用的模型。该模型确定了进度条的约束和值,因此您可以直接使用它作为使用上述单独设置/获取方法的替代方法。 |
控制进度条的外观
方法 | 目的 |
---|---|
void setIndeterminate(boolean) | 通过指定true ,将进度条置于不确定模式。指定false 将进度条恢复到默认的确定模式。 |
void setOrientation(int) int getOrientation() | 设置或获取进度条是垂直还是水平。可接受的值为JProgressBar.VERTICAL 或JProgressBar.HORIZONTAL 。 |
void setBorderPainted(boolean) boolean isBorderPainted() | 设置或获取进度条是否有边框。 |
void setStringPainted(boolean) boolean isStringPainted() | 设置或获取进度条是否显示百分比字符串。默认情况下,百分比字符串的值是由getPercentComplete 返回的值格式化为百分比。您可以使用setString 设置要显示的字符串。 |
void setString(String) String getString() | 设置或获取百分比字符串。 |
创建进度监视器
方法或构造函数 | 目的 |
---|---|
ProgressMonitor(Component, Object, String, int, int) | 创建一个进度监视器。Component 参数是监视器对话框的父级。Object 参数是要放在对话框内的选项窗格上的消息。该对象的值通常是一个String 。String 参数是一个可变的状态注释。最后两个int 参数分别设置对话框中使用的进度条的最小值和最大值。 |
ProgressMonitor getProgressMonitor() (在ProgressMonitorInputStream 中) |
获取一个监视从输入流读取的进度监视器。 |
配置进度监视器
方法 | 目的 |
---|---|
void setMinimum(int) int getMinimum() | 设置或获取进度监视器的最小值。该值由监视器用于在对话框中设置进度条。 |
void setMaximum(int) int getMaximum() | 设置或获取进度监视器的最大值。该值由监视器用于在对话框中设置进度条。 |
void setProgress(int) | 更新监视器的进度。 |
void setNote(String) String getNote() |
设置或获取状态注释。此注释显示在对话框中。要从对话框中省略状态注释,请在监视器的构造函数的第三个参数中提供null 。 |
void setMillisToDecideToPopup(int) int getMillisToDecideToPopup() |
设置或获取监视器在多长时间后决定弹出对话框。 |
终止进度监视器
方法 | 目的 |
---|---|
void close() |
关闭进度监视器。这将销毁对话框。 |
boolean isCanceled() |
确定用户是否按下了取消按钮。 |
监控进度的示例
以下示例使用JProgressBar
或ProgressMonitor
。
示例 | 描述位置 | 备注 |
---|---|---|
ProgressBarDemo |
本节 | 使用基本进度条显示在单独线程中运行的任务的进度。 |
ProgressBarDemo2 |
本节 | 使用基本进度条显示在单独线程中运行的任务的进度。 |
ProgressMonitorDemo |
本节 | 修改前一个示例,使用进度监视器而不是进度条。 |
如果您在 JavaFX 中编程,请参阅进度条和进度指示器。
如何使用根窗格
原文:
docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html
通常情况下,你不会直接创建一个JRootPane
对象。相反,当你实例化JInternalFrame
或其中一个顶级 Swing 容器时,例如JApplet
、JDialog
和JFrame
,你会得到一个JRootPane
(不管你是否想要!)。
使用顶级容器告诉你如何使用根窗格的基础知识 获取内容窗格,设置其布局管理器,并向其添加 Swing 组件。本节将告诉你更多关于根窗格的内容,包括组成根窗格的组件以及如何使用它们。
如前图所示,根窗格有四个部分:
玻璃窗格
默认情况下隐藏。如果使玻璃窗格可见,那么它就像是覆盖在根窗格的所有其他部分上的一块玻璃板。除非你实现了玻璃窗格的paintComponent
方法以执行某些操作,并且它可以拦截根窗格的输入事件,否则它是完全透明的。在下一节中,你将看到使用玻璃窗格的示例。
分层窗格
用于定位其内容的位置,包括内容窗格和可选菜单栏。还可以按指定的 Z 顺序容纳其他组件。有关详细信息,请参见分层窗格。
内容窗格
根窗格可见组件的容器,不包括菜单栏。有关使用内容窗格的信息,请参见使用顶级容器。
可选菜单栏
根窗格容器菜单的所在地。如果容器有一个菜单栏,通常使用容器的setJMenuBar
方法将菜单栏放在适当的位置。有关使用菜单和菜单栏的更多信息,请参见如何启用菜单。
玻璃窗格
当你想要捕获事件或在已包含一个或多个组件的区域上绘制时,玻璃窗格非常有用。例如,你可以通过让玻璃窗格拦截事件来禁用多组件区域的鼠标事件。或者你可以使用玻璃窗格在多个组件上显示图像。
这是一个演示玻璃窗格功能的应用程序的图片。它包含一个复选框,让你设置玻璃窗格是否“可见” 是否可以接收事件并在屏幕上绘制自己。当玻璃窗格可见时,它会阻止所有输入事件到达内容窗格中的组件。它还会在上次检测到鼠标按下事件的位置绘制一个红点。
试试这个:
-
点击“启动”按钮以使用Java™ Web Start运行 GlassPaneDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
-
点击按钮 1。
按钮的外观会发生变化,显示已被点击。
-
点击复选框,使玻璃窗格“可见”,然后再次点击按钮 1。
按钮不会被点击,因为玻璃窗格拦截了所有鼠标事件。玻璃窗格在释放鼠标的位置绘制一个红色圆圈。
-
再次点击复选框,使玻璃窗格隐藏。
当玻璃窗格检测到在复选框上方发生事件时,它会将其转发给复选框。否则,复选框将不会响应点击。
以下来自GlassPaneDemo.java
的代码显示和隐藏了玻璃窗格。该程序恰好创建了自己的玻璃窗格。但是,如果玻璃窗格不进行任何绘制,程序可能会简单地将侦听器附加到由getGlassPane
返回的默认玻璃窗格。
myGlassPane = new MyGlassPane(...);
changeButton.addItemListener(myGlassPane);
frame.setGlassPane(myGlassPane);
...
class MyGlassPane extends JComponent
implements ItemListener {
...
//React to change button clicks.
public void itemStateChanged(ItemEvent e) {
setVisible(e.getStateChange() == ItemEvent.SELECTED);
}
...
}
下一个代码片段实现了玻璃窗格的鼠标事件处理。如果鼠标事件发生在复选框上方,则玻璃窗格会重新分发事件,以便复选框接收到事件。
*...//In the implementation of the glass pane's mouse listener:*
public void mouseMoved(MouseEvent e) {
redispatchMouseEvent(e, false);
}
*.../* The mouseDragged, mouseClicked, mouseEntered,
* mouseExited, and mousePressed methods have the same
* implementation as mouseMoved. */...*
public void mouseReleased(MouseEvent e) {
redispatchMouseEvent(e, true);
}
private void redispatchMouseEvent(MouseEvent e,
boolean repaint) {
Point glassPanePoint = e.getPoint();
Container container = contentPane;
Point containerPoint = SwingUtilities.convertPoint(
glassPane,
glassPanePoint,
contentPane);
if (containerPoint.y < 0) { //we're not in the content pane
*//Could have special code to handle mouse events over
//the menu bar or non-system window decorations, such as
//the ones provided by the Java look and feel.*
} else {
//The mouse event is probably over the content pane.
//Find out exactly which component it's over.
Component component =
SwingUtilities.getDeepestComponentAt(
container,
containerPoint.x,
containerPoint.y);
if ((component != null)
&& (component.equals(liveButton))) {
//Forward events over the check box.
Point componentPoint = SwingUtilities.convertPoint(
glassPane,
glassPanePoint,
component);
component.dispatchEvent(new MouseEvent(component,
e.getID(),
e.getWhen(),
e.getModifiers(),
componentPoint.x,
componentPoint.y,
e.getClickCount(),
e.isPopupTrigger()));
}
}
//Update the glass pane if requested.
if (repaint) {
glassPane.setPoint(glassPanePoint);
glassPane.repaint();
}
}
这是在MyGlassPane
中实现绘制的代码。
protected void paintComponent(Graphics g) {
if (point != null) {
g.setColor(Color.red);
g.fillOval(point.x - 10, point.y - 10, 20, 20);
}
}
分层窗格
分层窗格是一个具有深度的容器,使得重叠的组件可以相互覆盖。有关分层窗格的一般信息,请参阅如何使用分层窗格。本节讨论了根窗格如何使用分层窗格。
每个根窗格都将其菜单栏和内容窗格放在JLayeredPane
的一个实例中。分层窗格提供的 Z 排序使得可以在其他组件上方显示弹出菜单等行为。
您可以选择将组件放在根窗格的分层窗格中。如果这样做,那么您应该意识到某些深度被定义为用于特定功能,并且应该按照预期使用这些深度。否则,您的组件可能无法与其他组件很好地配合。以下是显示功能图层及其关系的图表:
下表描述了每个图层的预期用途,并列出了与每个图层对应的JLayeredPane
常量:
图层名称 | 值 | 描述 |
---|---|---|
FRAME_CONTENT_LAYER |
new Integer(-30000) |
根窗格将菜单栏和内容窗格添加到此深度的分层窗格中。 |
DEFAULT_LAYER |
new Integer(0) |
如果在将组件添加到分层窗格时未指定组件的深度,则分层窗格会将其放在此深度处。 |
PALETTE_LAYER |
new Integer(100) |
此层对于浮动工具栏和调色板非常有用。 |
MODAL_LAYER |
new Integer(200) |
模态内部框对话框应属于此层。 |
POPUP_LAYER |
new Integer(300) |
弹出窗口应放在此层,因为它们需要出现在几乎所有内容的上方。 |
DRAG_LAYER |
new Integer(400) |
当组件被拖动时应使用。组件应在放下时返回到其常规层。 |
这是 RootLayeredPaneDemo 的图片,这是一个使用根窗格的分层窗格而不是创建新的分层窗格的版本的 LayeredPaneDemo。
试一试:
-
单击“启动”按钮以使用Java™ Web Start运行 RootLayeredPaneDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
-
在窗口中移动光标,使得杜克出现在其他组件的顶部。
请注意,当光标停留在非标签组件上时 无论是在内容窗格中还是在 Java 外观提供的标题栏中 杜克的移动会暂时停止。这是因为鼠标移动事件传递给包含层次结构中最深且对鼠标事件感兴趣的组件。移动杜克的鼠标移动监听器已在分层窗格上注册,并且该窗格中的大多数组件(除了标签)恰好具有鼠标移动监听器。当鼠标移动到分层窗格中的一个感兴趣的组件上时,分层窗格不会收到事件,而感兴趣的组件会收到。
-
确保选择了“在层中的顶部位置”复选框,将杜克的层更改为黄色(-30000)。
与以前一样,他会出现在其他组件的顶部,除了品红色(0)和青色(301)的矩形。
-
保持杜克在黄色层中,单击复选框将杜克发送到层的后面 -30000。
杜克消失了,因为内容窗格及其中的所有组件现在都在他的上方。
-
将杜克的层更改为青色(301),将杜克向下移动一点,使其站在黄色矩形的顶边上,然后按空格键打开组合框的下拉列表。
如果外观实现下拉列表作为轻量级弹出窗口,杜克会出现在下拉列表的顶部。
根窗格 API
接下来的表格列出了使用根窗格、玻璃窗格和内容窗格的 API。有关使用内容窗格的更多信息,请转到使用顶层容器。本节中的表格如下:
-
使用根窗格
-
设置或获取根窗格的内容
使用根窗格的 API 描述在其他地方:
-
分层窗格 API
-
菜单 API
使用根窗格
方法 | 目的 |
---|---|
JRootPane getRootPane() (在JApplet 、JDialog 、JFrame 、JInternalFrame 和JWindow 中) |
获取 applet、dialog、frame、internal frame 或 window 的根窗格。 |
static JRootPane getRootPane(Component) (在SwingUtilities 中) |
如果组件包含根窗格,则返回该根窗格。否则,返回包含该组件的根窗格(如果有)。 |
JRootPane getRootPane() (在JComponent 中) |
为JComponent 调用SwingUtilities 的getRootPane 方法。 |
void setDefaultButton(JButton) JButton getDefaultButton() | 设置或获取根窗格中的默认按钮(如果有)。特定外观和感觉的操作,如按下 Enter 键,会执行按钮的操作。 |
设置或获取根窗格的内容
以下方法在JApplet
、JDialog
、JFrame
、JInternalFrame
、JRootPane
和JWindow
中定义,除非另有说明。
方法 | 目的 |
---|---|
void setGlassPane(Component) Component getGlassPane() | 设置或获取玻璃窗格。 |
void setLayeredPane(JLayeredPane) Container getLayeredPane() | 设置或获取分层窗格。 |
void setContentPane(Container) Container getContentPane() | 设置或获取内容面板。 |
| void setJMenuBar(JMenuBar) JMenuBar getJMenuBar()
(未在JWindow
中定义) | 设置或获取菜单栏。
使用根窗格的示例
每个 Swing 程序都有一个根窗格,但很少直接引用它。以下列表中的示例演示了如何使用JRootPane
或玻璃窗格的功能。还请参阅以下列表:
-
使用分层窗格的示例
-
使用菜单的示例
-
使用框架的示例(用于使用内容窗格的示例)
示例 | 描述位置 | 注释 |
---|---|---|
GlassPaneDemo |
本节 | 使用绘制位和重新分发事件的玻璃窗格。 |
RootLayeredPaneDemo |
本节 | 调整 LayeredPaneDemo 以使用根窗格的分层窗格。 |
ListDialog |
如何使用列表 | 设置JDialog 的默认按钮。 |
FrameDemo2 |
如何制作框架 | 为JFrame 设置默认按钮。 |
如何使用滚动窗格
原文:
docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html
JScrollPane
提供了一个组件的可滚动视图。当屏幕空间有限时,使用滚动窗格来显示一个大的组件或一个大小可以动态改变的组件。用于节省屏幕空间的其他容器包括分割窗格和选项卡窗格。
创建滚动窗格的代码可以很简洁。例如,这里有一个演示程序的图片,将一个文本区域放入滚动窗格中,因为随着文本的追加,文本区域的大小会动态增长:
这是创建文本区域、将其设置为滚动窗格的客户端并将滚动窗格添加到容器的代码:
*//In a container that uses a BorderLayout:*
textArea = new JTextArea(5, 30);
...
JScrollPane scrollPane = new JScrollPane(textArea);
...
setPreferredSize(new Dimension(450, 110));
...
add(scrollPane, BorderLayout.CENTER);
粗体代码行创建了JScrollPane
,指定文本区域为滚动窗格的客户端。程序不会在JScrollPane
对象上调用任何方法,因为滚动窗格会自动处理一切:在必要时创建滚动条,当用户移动滚动条时重新绘制客户端等。
您可能已经注意到前面的代码设置了滚动窗格容器的首选大小。在 Java 外观中,这个首选大小恰好比我们在创建时请求的 5 行文本区域显示所需的高度要低一点,因此滚动条最初会显示一个垂直滚动条。如果我们不限制滚动窗格容器的大小,滚动窗格将足够大,以便文本区域显示使用JTextArea
构造函数指定的完整 5 行和 30 列。有关使滚动窗格达到所需大小的技术信息,请参考 Sizing a Scroll Pane。
本节的其余部分讨论以下主题:
-
滚动窗格的工作原理
-
设置滚动条策略
-
提供自定义装饰
-
实现具有滚动功能的客户端
-
调整滚动窗格大小
-
动态更改客户端大小
-
滚动窗格 API
-
使用滚动窗格的示例
滚动窗格的工作原理
这是一个应用程序的快照,使用定制的滚动窗格查看照片:
此应用程序中的滚动窗格与先前的演示程序中的滚动窗格非常不同。这个滚动窗格不是显示文本,而是包含一个图像。滚动窗格还有两个滚动条,一个行标题,一个列标题和四个角,其中三个已经定制。
试试这个:
-
点击“启动”按钮以使用Java™ Web Start运行 ScrollDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
-
移动滚动条上的旋钮。观察图像滚动以及水平和垂直标尺的滚动。
-
如果您的鼠标带有滚轮(通常位于鼠标按钮之间),请使用鼠标滚轮垂直滚动图像。
-
点击滚动窗格左上角的cm切换按钮。行和列标题上的单位将更改为英寸(或切换回厘米)。
-
点击滚动条上的箭头按钮。还可以尝试点击垂直滚动条旋钮上方或下方的轨道,或水平滚动条左侧或右侧。
-
将光标移动到图像上并按下光标。继续按住光标,拖动到图像外部的某个点并暂停。图像的可见区域朝光标移动。这种通过拖动进行滚动的功能由滚动窗格和
JComponent
API 启用,但由显示图像的自定义组件实现。 -
调整窗口大小。注意当滚动窗格足够大以显示整个图像时,滚动条会消失,并在滚动窗格太小以显示整个图像时重新出现。
在创建滚动窗格时,ScrollDemo 程序会建立滚动窗格的客户端:
//*Where the member variables are declared:*
private ScrollablePicture picture;
...
//*Where the GUI is created:*
picture = new ScrollablePicture( *...* );
JScrollPane pictureScrollPane = new JScrollPane(picture);
滚动窗格的客户端也被称为视图或视口视图。您可以通过调用setViewportView
方法动态更改客户端。请注意,JScrollPane
没有对应的getViewportView
方法。如果您需要再次引用客户端对象,可以将其缓存在变量中,或在滚动窗格上调用getViewport().getViewportView()
。
当用户操作滚动窗格中的滚动条时,客户端可见区域相应地发生变化。这张图片展示了滚动窗格与其客户端之间的关系,并指示了滚动窗格委托的类来帮助:
滚动窗格使用JViewport
实例来管理客户端的可见区域。视口负责根据滚动条的位置来定位和调整客户端的大小,并显示它。
滚动窗格可能使用两个单独的JScrollBar
实例作为滚动条。滚动条为用户提供操作可见区域的接口。下图显示了滚动条的三个区域:滑块(有时称为拇指)、(箭头)按钮和轨道。
当用户上下移动垂直滚动条上的滑块时,客户端的可见区域上下移动。类似地,当用户左右移动水平滚动条上的滑块时,客户端的可见区域相应地左右移动。滑块相对于其轨道的位置与可见区域相对于客户端的位置成比例。在 Java 外观和其他一些外观中,滑块的大小给出了客户端可见部分的视觉线索。
通过单击箭头按钮,用户可以按单位增量滚动。通过在轨道内部单击,用户可以按块增量滚动。如果用户使用带有滚轮的鼠标,则用户可以使用鼠标滚轮垂直滚动。鼠标滚轮滚动的量取决于平台。例如,在 Windows XP 上,默认情况下,鼠标滚轮每次滚动三个单位增量;鼠标控制面板允许您指定不同数量的单位增量或使用块增量。有关单位和块增量的更多信息,请参阅实现滚动智能客户端。
典型的程序不会直接实例化或调用视口或滚动条的方法。相反,程序使用JScrollPane
API 和实现滚动智能客户端中讨论的 API 来实现滚动行为。一些具有滚动智能的组件,如JList
、JTable
和JTree
,还提供其他 API 来帮助您影响它们的滚动行为。
设置滚动条策略
在ScrollDemo
应用程序启动时,滚动窗格有两个滚动条。如果将窗口放大,两个滚动条都会消失,因为它们不再需要。然后,如果只缩小窗口的高度而不改变宽度,则垂直滚动条会重新出现。进一步的实验将显示,在此应用程序中,根据需要,两个滚动条都会消失和重新出现。此行为由滚动窗格的滚动条策略控制,实际上,有两种策略:每个滚动条都有自己的策略。
ScrollDemo
没有明确设置滚动窗格的滚动条策略 它使用默认值。您可以在创建滚动窗格时设置策略,或在运行时动态更改它们。
在JScrollPane
提供的构造函数中,这两个构造函数允许您在创建滚动窗格时设置滚动条策略:
JScrollPane(Component, int, int)
JScrollPane(int, int)
第一个int
指定垂直滚动条的策略;第二个指定水平滚动条的策略。您还可以使用setHorizontalScrollBarPolicy
和setVerticalScrollBarPolicy
方法动态设置策略。在构造函数和方法中,使用ScrollPaneConstants
接口中定义的以下常量之一(该接口由JScrollPane
实现):
策略 | 描述 |
---|---|
VERTICAL_SCROLLBAR_AS_NEEDED HORIZONTAL_SCROLLBAR_AS_NEEDED |
默认选项。当视口小于客户端时,滚动条出现;当视口大于客户端时,滚动条消失。 |
VERTICAL_SCROLLBAR_ALWAYS HORIZONTAL_SCROLLBAR_ALWAYS |
总是显示滚动条。如果视口足够大以显示整个客户端,则滑块会消失。 |
VERTICAL_SCROLLBAR_NEVER HORIZONTAL_SCROLLBAR_NEVER |
从不显示滚动条。如果您不希望用户直接控制客户端显示的部分,或者希望他们仅使用非滚动条技术(如拖动),请使用此选项。 |
提供自定义装饰
滚动窗格绘制的区域由最多九个部分组成:中心、四边和四个角。中心是所有滚动窗格中始终存在的唯一组件。除了滚动条,边可以包含列和行标题。只有当相交于该角的两边包含可见组件时,角组件才可见。
如图所示,在ScrollDemo
中的滚动窗格具有自定义的行和列标题。此外,因为所有四边都被填充,所有四个角都存在。程序自定义了三个角——两个只是用与Rule
相同颜色填充其区域,另一个包含一个切换按钮。第四个角,右下角,是滚动窗格提供的默认角。请注意,因为在此示例中行和列标题始终存在,切换按钮也始终存在。
如果一个角落包含用户始终需要访问的控件,请确保相交于该角落的边始终存在。例如,如果该应用程序将切换放置在下右角,与滚动条相交的地方,那么如果用户调整窗口大小,甚至一个滚动条消失,切换也会消失。
滚动窗格的行和列标题由自定义的JComponent
子类Rule
提供,该子类以厘米或英寸绘制标尺。以下是创建并设置滚动窗格的行和列标题的代码:
*//Where the member variables are defined:*
private Rule columnView;
private Rule rowView;
...
*//Where the GUI is initialized:*
ImageIcon bee = createImageIcon("images/flyingBee.jpg");
...
//Create the row and column headers.
columnView = new Rule(Rule.HORIZONTAL, true);
rowView = new Rule(Rule.VERTICAL, true);
...
pictureScrollPane.setColumnHeaderView(columnView);
pictureScrollPane.setRowHeaderView(rowView);
您可以为滚动窗格的行和列标题使用任何组件。滚动窗格将行和列标题放在它们自己的JViewPort
中。因此,水平滚动时,列标题会跟随移动,垂直滚动时,行标题会跟随移动。确保行和列与视图具有相同的宽度和高度,因为JScrollPane
不强制执行这些值具有相同的大小。如果一个与另一个不同,您可能无法获得所需的行为。
作为JComponent
子类,我们的自定义Rule
类将其渲染代码放在其paintComponent
方法中。Rule
渲染代码确保仅在当前裁剪边界内绘制,以确保快速滚动。您的自定义行和列标题应该做同样的事情。
您还可以为滚动窗格的角使用任何组件。ScrollDemo
通过在左上角放置一个切换按钮,并在右上角和左下角放置自定义Corner
对象来说明这一点。以下是创建Corner
对象并调用setCorner
将它们放置的代码:
//Create the corners.
JPanel buttonCorner = new JPanel(); //use FlowLayout
isMetric = new JToggleButton("cm", true);
isMetric.setFont(new Font("SansSerif", Font.PLAIN, 11));
isMetric.setMargin(new Insets(2,2,2,2));
isMetric.addItemListener(this);
buttonCorner.add(isMetric);
...
//Set the corners.
pictureScrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
buttonCorner);
pictureScrollPane.setCorner(JScrollPane.LOWER_LEFT_CORNER,
new Corner());
pictureScrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER,
new Corner());
记住,每个角的大小由相交的边的大小确定。对于某些组件,您必须确保组件的特定实例适合其角落。例如,程序设置了切换按钮的字体和边距,以使其适应标题所确定的空间。这不是Corner
类的问题,因为该类用单一颜色填充其整个边界,无论它们是什么颜色。
从代码中可以看出,常量指示角的位置。此图显示了每个位置的常量:
这些常量在ScrollPaneConstants
接口中定义,JScrollPane
实现了该接口。
实现滚动智能客户端
要自定义客户端组件与其滚动窗格的交互方式,您可以使组件实现Scrollable
接口。通过实现Scrollable
,客户端可以指定用于查看它的视口的大小以及单击滚动条上不同控件时滚动的量。您还可以指定视图是否应跟踪视口的大小。当视口大于视图时,但视图应填充可用空间时,通常会使用此选项。
注意:如果您无法或不想实现可滚动的客户端,可以使用setUnitIncrement
和setBlockIncrement
方法来指定单位和块增量JScrollBar
。例如,以下代码将垂直滚动的单位增量设置为 10 像素:
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
这里再次介绍滚动条的三个控制区域:旋钮、按钮和轨道。
您可能已经注意到,在ScrollDemo
中操作滚动条时,单击按钮会将图像滚动到刻度边界。您可能还注意到,在轨道上单击会将图片滚动一个“屏幕”。更一般地,按钮按单位增量滚动可见区域,轨道按块增量滚动可见区域。您在示例中看到的行为不是滚动窗格的默认行为,而是由客户端在其实现Scrollable
接口时指定的。
ScrollDemo
程序的客户端是ScrollablePicture
。ScrollablePicture
是JLabel
的子类,提供了所有五个Scrollable
方法的实现:
-
getScrollableBlockIncrement
-
getScrollableUnitIncrement
-
getPreferredScrollableViewportSize
-
getScrollableTracksViewportHeight
-
getScrollableTracksViewportWidth
ScrollablePicture
主要实现Scrollable
接口以影响单位和块增量。但是,它必须为所有五个方法提供实现。因此,它为其他三个方法提供了合理的默认值,您可能希望为您的滚动类复制这些默认值。
每当用户单击滚动条上的按钮时,滚动窗格都会调用客户端的getScrollableUnitIncrement
方法。只要客户端实现了 Scrollable 接口,这就是真的。此方法返回要滚动的像素数。该方法的一个明显实现是返回标头标尺上刻度标记之间的像素数。然而,ScrollablePicture
做了不同的事情:它返回将图像定位在刻度标记边界上所需的值。以下是实现:
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation,
int direction) {
//Get the current position.
int currentPosition = 0;
if (orientation == SwingConstants.HORIZONTAL) {
currentPosition = visibleRect.x;
} else {
currentPosition = visibleRect.y;
}
//Return the number of pixels between currentPosition
//and the nearest tick mark in the indicated direction.
if (direction < 0) {
int newPosition = currentPosition -
(currentPosition / maxUnitIncrement)
* maxUnitIncrement;
return (newPosition == 0) ? maxUnitIncrement : newPosition;
} else {
return ((currentPosition / maxUnitIncrement) + 1)
* maxUnitIncrement
- currentPosition;
}
}
如果图像已经在刻度标记边界上,此方法返回刻度之间的像素数。否则,它返回从当前位置到最近刻度的像素数。
同样,滚动窗格在用户点击轨道时调用客户端的getScrollableBlockIncrement
方法,但仅当客户端实现了 Scrollable 接口时才调用。这是ScrollablePicture
对该方法的实现:
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation,
int direction) {
if (orientation == SwingConstants.HORIZONTAL)
return visibleRect.width - maxUnitIncrement;
else
return visibleRect.height - maxUnitIncrement;
}
此方法返回可见矩形的高度减去一个刻度标记。这种行为在垂直滚动时很典型,否则,它是宽度。块增量应略小于视口,以留下一点之前可见区域的上下文。例如,文本区域可能留下一两行文本作为上下文,表格可能留下一行或一列(取决于滚动方向)。
ScrollablePicture.java
还有一段代码,这段代码不是Scrollable
接口所必需的,但在可滚动组件中很常见:一个鼠标移动监听器,让用户通过从图片上拖动来滚动图片。以下代码中的粗体代码实现了通过拖动来滚动:
public class ScrollablePicture extends JLabel
implements Scrollable,
MouseMotionListener {
...
public ScrollablePicture(...) {
...
setAutoscrolls(true); //enable synthetic drag events
addMouseMotionListener(this); //handle mouse drags
}
...
public void mouseDragged(MouseEvent e) {
//The user is dragging us, so scroll!
Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
scrollRectToVisible(r);
}
...
}
当用户从图片拖动到图片外部位置并暂停时,此代码片段会滚动图片。setAutoscrolls
方法由JComponent
定义,用于辅助滚动而不是实现拖动滚动。将 autoscrolls 属性设置为true
会使组件即使鼠标没有移动(因为它在组件外部停止拖动),也会触发合成鼠标拖动事件。组件的鼠标移动监听器应该监听这些事件并做出相应反应。
调整滚动窗格大小
除非你明确设置了滚动窗格的首选大小,否则滚动窗格会根据其九个组件的首选大小来计算它的首选大小(视口以及如果存在的话,两个滚动条,行和列标题以及四个角)。最大的因素,也是大多数程序员关心的因素,是用于显示客户端的视口的大小。
如果客户端不懂滚动,那么滚动窗格会自动调整大小,以便客户端以其首选大小显示。对于典型的不懂滚动的客户端,这使得滚动窗格变得多余。也就是说,滚动窗格没有滚动条,因为客户端的首选大小足够显示整个客户端。在这种情况下,如果客户端不会动态改变大小,你应该通过设置其首选大小或其容器的首选大小来限制滚动窗格的大小。
如果客户端懂滚动,那么滚动窗格会使用客户端的getPreferredScrollableViewportSize
方法返回的值来计算其视口的大小。该方法的实现通常报告一个比组件的标准首选大小小的滚动的首选大小。例如,默认情况下,JList
的getPreferredScrollableViewportSize
实现返回的值刚好足够显示八行。
像列表、表格、文本组件和树形结构这样的懂滚动的类通常提供一个或多个方法,让程序员影响getPreferredScrollableViewportSize
返回的大小。例如,你可以通过调用setVisibleRowCount
方法来设置列表或树中可见行的数量。列表或树会负责计算显示该行数所需的大小。
参考与滚动相关的其他类中的方法以获取除JScrollPane
之外的类提供的与滚动相关的方法的信息。记住,如果你不喜欢getPreferredScrollableViewportSize
返回的值,你总是可以设置滚动窗格或其容器的首选大小。
动态更改客户端的大小
更改滚动窗格客户端的大小是一个两步过程。首先,设置客户端的首选大小。然后,在客户端上调用revalidate
,让滚动窗格知道它应该更新自身和其滚动条。让我们看一个例子。
这是一个应用程序的图片,当用户放置一个边界超出当前边界的圆圈时,客户端的大小会发生变化。当用户清除绘图区域时,程序也会更改客户端的大小:
你可以在ScrollDemo2.java
中找到此示例的完整源代码,该示例基于教程读者约翰·维拉提供的示例。你可以运行 ScrollDemo2(下载 JDK 7 或更高版本)。
这是在必要时更改绘图区域大小的代码:
if (changed) {
//Update client's preferred size because
//the area taken up by the graphics has
//gotten larger or smaller (if cleared).
drawingArea.setPreferredSize(*/* the new size */*);
//Let the scroll pane know to update itself
//and its scroll bars.
drawingArea.revalidate();
}
请注意,当客户端更改大小时,滚动条会调整。滚动窗格不会调整大小,视口也不会调整大小。
参考SplitPaneDemo
以查看另一个客户端对象大小变化的示例。
滚动窗格 API
以下表格列出了常用的与滚动相关的构造函数和方法。您最有可能在JScrollPane
对象上调用的其他方法是其超类提供的setPreferredSize
等方法。请参阅 The JComponent API 以查看常用继承方法的表格。
使用滚动窗格的 API 分为以下几类:
-
设置滚动窗格
-
装饰滚动窗格
-
实现滚动智能客户端
-
与滚动相关的其他类中的方法
设置滚动窗格
(JScrollPane
构造函数和方法)
方法或构造函数 | 目的 |
---|
| JScrollPane() JScrollPane(Component)
JScrollPane(Component, int, int) | 创建一个滚动窗格。Component
参数在存在时设置滚动窗格的客户端。两个int
参数在存在时分别设置垂直和水平滚动条策略。|
void setViewportView(Component) |
设置滚动窗格的客户端。 |
---|---|
void setVerticalScrollBarPolicy(int) int getVerticalScrollBarPolicy() |
设置或获取垂直滚动策略。ScrollPaneConstants 定义了三个值来指定此策略:VERTICAL_SCROLLBAR_AS_NEEDED (默认值)、VERTICAL_SCROLLBAR_ALWAYS 和VERTICAL_SCROLLBAR_NEVER 。 |
void setHorizontalScrollBarPolicy(int) int getHorizontalScrollBarPolicy() | 设置或获取水平滚动策略。ScrollPaneConstants 定义了三个值来指定此策略:HORIZONTAL_SCROLLBAR_AS_NEEDED (默认值)、HORIZONTAL_SCROLLBAR_ALWAYS 和HORIZONTAL_SCROLLBAR_NEVER 。 |
void setViewportBorder(Border) Border getViewportBorder() | 设置或获取视口周围的边框。这比在组件上设置边框更可取。 |
boolean isWheelScrollingEnabled() | 设置或获取是否响应鼠标滚轮进行滚动。默认情况下启用鼠标滚轮滚动。 |
装饰滚动窗格
(JScrollPane
方法)
方法 | 目的 |
---|---|
void setColumnHeaderView(Component) void setRowHeaderView(Component) | 设置滚动窗格的列或行标题。 |
void setCorner(String, Component) Component getCorner(String) | 设置或获取指定的角落。int 参数指定哪个角落,并且必须是ScrollPaneConstants 中定义的以下常量之一:UPPER_LEFT_CORNER 、UPPER_RIGHT_CORNER 、LOWER_LEFT_CORNER 、LOWER_RIGHT_CORNER 、LOWER_LEADING_CORNER 、LOWER_TRAILING_CORNER 、UPPER_LEADING_CORNER 和UPPER_TRAILING_CORNER 。 |
实现滚动智能客户端
方法 | 目的 |
---|
| int getScrollableUnitIncrement(Rectangle, int, int) int getScrollableBlockIncrement(Rectangle, int, int)
(Scrollable
接口所需) | 获取以像素为单位的单位或块增量。Rectangle
参数是当前可见矩形的边界。第一个 int
参数是根据用户单击的滚动条是 SwingConstants.HORIZONTAL
还是 SwingConstants.VERTICAL
。第二个 int
参数指示要滚动的方向。小于 0 的值表示向上或向左。大于 0 的值表示向下或向右。
Dimension getPreferredScrollableViewportSize() (Scrollable 接口所需) |
获取视口的首选大小。这允许客户端影响其显示的视口的大小。如果视口大小不重要,实现此方法以返回 getPreferredSize 。 |
---|
| boolean getScrollableTracksViewportWidth() boolean getScrollableTracksViewportHeight()
(Scrollable
接口所需) | 获取滚动窗格是否应强制客户端与视口的宽度或高度相同。这两种方法中的任何一个返回 true
效果上都禁止水平或垂直滚动。
void setAutoscrolls(boolean) (在 JComponent 中) |
设置当用户将鼠标拖动到组件外部并停止时是否生成合成的鼠标拖动事件;这些事件对于通过拖动进行滚动是必要的。默认情况下,该值为 false ,但许多可滚动的组件如 JTable 和自定义组件会将该值设置为 true 。 |
---|
与滚动相关的其他类中的方法
方法 | 目的 |
---|---|
void scrollRectToVisible(Rectangle) (在 JComponent 中) |
如果组件位于支持滚动的容器中,如滚动窗格,则调用此方法会滚动滚动窗格,使指定的矩形可见。 |
| void setVisibleRowCount(int) int getVisibleRowCount()
(在JList
中) | 设置或获取列表中有多少行是可见的。getPreferredScrollableViewportSize
方法使用可见行数来计算其返回值。
void ensureIndexIsVisible(int) (在JList 中) |
滚动以使指定索引处的行可见。此方法调用scrollRectToVisible ,仅在列表位于支持滚动的容器中(如滚动窗格)时有效。 |
---|
| void setVisibleRowCount(int) int getVisibleRowCount()
(在JTree
中) | 设置或获取树中有多少行是可见的。getPreferredScrollableViewportSize
方法使用可见行数来计算其返回值。
| void scrollPathToVisible(TreePath) void scrollRowToVisible(int)
(在JTree
中) | 滚动以使指定的树路径或指定索引处的行可见。这些方法调用scrollRectToVisible
,仅在树位于支持滚动的容器中(如滚动窗格)时有效。
| void setScrollsOnExpand(boolean) boolean getScrollsOnExpand()
(在JTree
中) | 设置或获取用户展开节点时是否自动滚动。默认为 True。此功能仅在树位于支持滚动的容器中(如滚动窗格)时有效。
void setPreferredScrollableViewportSize(Dimension) (在JTable 中) |
设置getPreferredScrollableViewportSize 返回的值。 |
---|
使用滚动窗格的示例
此表显示了使用JScrollPane
的示例以及这些示例的描述位置。
示例 | 描述位置 | 备注 |
---|---|---|
ToolBarDemo |
这一部分,如何使用工具栏 | 展示了滚动窗格的简单而典型的用法。 |
ScrollDemo |
这一部分 | 使用了滚动窗格的许多功能。 |
ScrollDemo2 |
这一部分 | 展示了如何更改客户端的大小。 |
SplitPaneDemo |
如何使用分割窗格, 如何使用列表 | 将列表和标签放入滚动窗格中。同时,展示了处理滚动窗格客户端大小变化的情况。 |
TableDemo |
如何使用表格 | 将表格放入滚动窗格中。 |
TextSamplerDemo |
使用文本组件 | 将文本区域、编辑器窗格和文本窗格放入滚动窗格中。 |
TreeDemo |
如何使用树 | 将树放入滚动窗格中。 |
如果您正在使用 JavaFX 进行编程,请参阅滚动窗格。
如何使用分隔符
原文:
docs.oracle.com/javase/tutorial/uiswing/components/separator.html
JSeparator
类提供水平或垂直的分隔线或空白空间。它最常用于菜单和工具栏。实际上,您甚至可以在不知道JSeparator
类存在的情况下使用分隔符,因为菜单和工具栏提供了方便的方法来创建并添加针对其容器定制的分隔符。分隔符与边框有些相似,只是它们是真正的组件,因此会在容器内绘制,而不是在特定组件的边缘周围。
这是一个菜单的图片,其中有三个分隔符,用于将菜单分成四组项目:
将菜单项和分隔符添加到菜单的代码非常简单,大致如下:
menu.add(menuItem1);
menu.add(menuItem2);
menu.add(menuItem3);
menu.addSeparator();
menu.add(rbMenuItem1);
menu.add(rbMenuItem2);
menu.addSeparator();
menu.add(cbMenuItem1);
menu.add(cbMenuItem2);
menu.addSeparator();
menu.add(submenu);
将分隔符添加到工具栏类似。您可以在菜单和工具栏的操作部分找到完整的代码解释。如果您想对菜单和工具栏中的分隔符有更多控制,可以直接使用实现它们的JSeparator
子类:JPopupMenu.Separator和JToolBar.Separator。特别是,JToolBar.Separator
具有用于指定分隔符大小的 API。
使用 JSeparator
您可以直接使用JSeparator
类在任何容器中提供分隔线。以下图片显示了一个 GUI,其中在标有 Fire 的按钮右侧有一个分隔符。
分隔符几乎没有 API,并且非常容易使用,只要记住一件事:在大多数实现中,垂直分隔符的首选高度为 0,水平分隔符的首选宽度为 0。这意味着分隔符不可见,除非您设置其首选大小或将其放在像BorderLayout
或BoxLayout
这样的布局管理器的控制下,以拉伸以填充其可用的显示区域。
垂直分隔符确实有一定的宽度(水平分隔符有一定的高度),因此您应该看到分隔符所在的空间。但是,除非宽度和高度都不为零,否则不会绘制实际的分隔线。
以下代码片段显示了 ListDemo 如何组合包含垂直分隔符的面板。您可以在ListDemo.java
中找到 ListDemo 的完整源代码。
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane,
BoxLayout.LINE_AXIS));
buttonPane.add(fireButton);
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(new JSeparator(SwingConstants.VERTICAL));
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(employeeName);
buttonPane.add(hireButton);
buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
正如代码所示,按钮、分隔符和文本字段都共享一个容器 一个使用从左到右的盒式布局的 JPanel
实例。由于布局管理器(以及分隔符具有无限的最大尺寸),分隔符会自动调整为其可用的显示区域一样高。
在上述代码中,水平支撑是不可见的组件,用于在分隔符周围提供空间。5 像素的空边框在面板周围提供缓冲,并防止分隔符延伸到其上方的组件和下方窗口的边缘。
这是另一个使用分隔符的 GUI 的图片,这次是为了在一组控件和显示区域之间放置一个分隔线。
您可以在示例索引中找到代码。以下是设置分隔符容器的代码:
JPanel panel = new JPanel(new BorderLayout());
...
panel.setBorder(BorderFactory.createEmptyBorder(
GAP/2, //top
0, //left
GAP/2, //bottom
0)); //right
panel.add(new JSeparator(JSeparator.VERTICAL),
BorderLayout.LINE_START);
panel.add(addressDisplay,
BorderLayout.CENTER);
与上一个示例一样,面板使用空边框,以便分隔符不会延伸到其容器的边缘。将分隔符放在由 BorderLayout
控制的容器的最左侧区域使分隔符与容器中心的地址显示组件一样高。有关边框布局工作原理的详细信息,请参阅如何使用 BorderLayout。
分隔符 API
使用分隔符的 API 很少,因为它们没有内容,也不响应用户输入。
创建和初始化分隔符
构造函数或方法 | 目的 |
---|
| void addSeparator() void addSeparator(Dimension)
(在 JToolBar
中) | 在工具栏的当前末尾附加一个工具栏分隔符(在大多数情况下是不可见的),可选参数指定分隔符的大小。此方法的无参数版本使用默认大小的分隔符,由当前外观和感觉确定。 |
| void addSeparator() void insertSeparator(int)
(在 JMenu
中) | 在菜单中放置一个分隔符。addSeparator
方法将分隔符放在菜单的当前末尾。insertSeparator
方法在指定位置将分隔符插入菜单中。 |
void addSeparator() (在 JPopupMenu 中) |
在弹出菜单的当前末尾放置一个分隔符。 |
---|---|
JSeparator() JSeparator(int) | 创建一个分隔符。如果不指定参数,分隔符是水平的。参数可以是SwingConstants.HORIZONTAL 或SwingConstants.VERTICAL 。 |
| void setOrientation(int) int getOrientation()
(在JSeparator
中) | 获取或设置分隔符的方向,可以是SwingConstants.HORIZONTAL
或SwingConstants.VERTICAL
。 |
JToolBar.Separator() JToolBar.Separator(Dimension) | 创建用于工具栏的分隔符。可选参数指定分隔符的大小。 |
---|---|
setSeparatorSize(Dimension) (在JToolBar.Separator 中) |
指定分隔符的大小。更具体地说,指定的Dimension 用作分隔符的最小、首选和最大大小。 |
JPopupMenu.Separator() | 创建用于菜单的分隔符。 |
使用分隔符的示例
本课程的几个示例使用分隔符,通常在菜单中。以下是一些更有趣的示例列表。
示例 | 描述位置 | 备注 |
---|---|---|
ListDemo |
本节和如何使用列表 | 在由水平盒式布局控制的面板中使用垂直分隔符。 |
TextInputDemo |
本节和如何使用格式化文本字段 | 在由边界布局控制的面板左侧使用垂直分隔符。 |
MenuDemo |
本节和如何使用菜单 | 使用JMenu 方法addSeparator 在菜单中放置分隔符。 |
ToolBarDemo2 |
如何使用工具栏 | 使用JToolBar 方法addSeparator 在两种按钮之间放置空间。 |
如果您正在使用 JavaFX 编程,请参阅使用 JavaFX UI 控件。
如何使用滑块
原文:
docs.oracle.com/javase/tutorial/uiswing/components/slider.html
JSlider
组件旨在让用户轻松输入由最小值和最大值限定的数值。如果空间有限,spinner 是滑块的一个可能替代品。
以下图片显示了一个应用程序,该应用程序使用滑块来控制动画速度:
试试这个:
-
单击“启动”按钮以使用Java™ Web Start运行 SliderDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
-
使用滑块调整动画速度。
-
将滑块推到 0 以停止动画。
以下是创建上一个示例中滑块的SliderDemo.java
文件中的代码。
static final int FPS_MIN = 0;
static final int FPS_MAX = 30;
static final int FPS_INIT = 15; //initial frames per second
. . .
JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
FPS_MIN, FPS_MAX, FPS_INIT);
framesPerSecond.addChangeListener(this);
//Turn on labels at major tick marks.
framesPerSecond.setMajorTickSpacing(10);
framesPerSecond.setMinorTickSpacing(1);
framesPerSecond.setPaintTicks(true);
framesPerSecond.setPaintLabels(true);
默认情况下,主要和次要刻度线的间距为零。要查看刻度线,必须显式设置主要或次要刻度线(或两者)的间距为非零值,并调用setPaintTicks(true)
方法。但是,您还需要标签来标记刻度线。要在主要刻度线位置显示标准数字标签,请设置主要刻度线间距,然后调用setPaintLabels(true)
方法。示例程序以这种方式为其滑块提供标签。但您不仅限于使用这些标签。自定义滑块上的标签向您展示如何自定义滑块标签。此外,滑块功能允许您为JSlider
组件设置字体。
Font font = new Font("Serif", Font.ITALIC, 15);
framesPerSecond.setFont(font);
当您移动滑块的旋钮时,将调用滑块的ChangeListener
的stateChanged
方法。有关更改侦听器的信息,请参阅如何编写更改侦听器。以下是对滑块值更改做出反应的更改侦听器代码:
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
int fps = (int)source.getValue();
if (fps == 0) {
if (!frozen) stopAnimation();
} else {
delay = 1000 / fps;
timer.setDelay(delay);
timer.setInitialDelay(delay * 10);
if (frozen) startAnimation();
}
}
}
请注意,只有当getValueIsAdjusting
方法返回false
时,stateChanged
方法才会更改动画速度。当用户移动滑块旋钮时,会触发许多更改事件。该程序只对用户操作的最终结果感兴趣。
自定义滑块上的标签
下面的演示是使用具有自定义标签的滑块的 SliderDemo 的修改版本:
此程序的源代码可以在SliderDemo2.java
中找到。点击“启动”按钮以使用Java™ Web Start运行 SliderDemo2(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
以下代码创建滑块并自定义其标签:
//Create the slider
JSlider framesPerSecond = new JSlider(JSlider.VERTICAL,
FPS_MIN, FPS_MAX, FPS_INIT);
framesPerSecond.addChangeListener(this);
framesPerSecond.setMajorTickSpacing(10);
framesPerSecond.setPaintTicks(true);
//Create the label table
Hashtable labelTable = new Hashtable();
labelTable.put( new Integer( 0 ), new JLabel("Stop") );
labelTable.put( new Integer( FPS_MAX/10 ), new JLabel("Slow") );
labelTable.put( new Integer( FPS_MAX ), new JLabel("Fast") );
framesPerSecond.setLabelTable( labelTable );
framesPerSecond.setPaintLabels(true);
setLabelTable
方法指定的哈希表中的每个键值对给出一个标签的位置和值。哈希表键必须是Integer
类型,并且必须具有滑块范围内的一个值,以便放置标签。与每个键关联的哈希表值必须是一个Component
对象。此演示使用仅包含文本的JLabel
实例。一个有趣的修改是使用包含图标或按钮的JLabel
实例,这些按钮可以将旋钮移动到标签的位置。
使用JSlider
类的createStandardLabels
方法创建一组在特定间隔位置的数字标签。您还可以修改createStandardLabels
方法返回的表格,以进行自定义。
滑块 API
以下表格列出了常用的JSlider
构造函数和方法。请参阅 The JComponent Class 以查看常用继承方法的表格。
使用滑块的 API 分为以下几个类别:
-
创建滑块
-
微调滑块的外观
-
观察滑块操作
-
直接使用数据模型
创建滑块
构造函数 | 目的 |
---|---|
JSlider() | 创建具有范围从 0 到 100 和初始值为 50 的水平滑块。 |
JSlider(int min, int max) JSlider(int min, int max, int value) | 创建具有指定最小值和最大值的水平滑块。第三个int 参数(如果存在)指定滑块的初始值。 |
JSlider(int orientation) JSlider(int orientation, int min, int max, int value) | 创建具有指定方向的滑块,该方向必须是JSlider.HORIZONTAL 或JSlider.VERTICAL 。最后三个int 参数(如果存在)分别指定滑块的最小值、最大值和初始值。 |
JSlider(BoundedRangeModel) | 使用指定的模型创建水平滑块,该模型管理滑块的最小值、最大值和当前值及它们之间的关系。 |
调整滑块外观
方法 | 目的 |
---|---|
void setValue(int) int getValue() | 设置或获取滑块的当前值。设置方法还会定位滑块的旋钮。 |
void setOrientation(int) int getOrientation() | 设置或获取滑块的方向。可能的值为JSlider.HORIZONTAL 或JSlider.VERTICAL 。 |
void setInverted(boolean) boolean getInverted() | 设置或获取是否在水平滑块的左侧或垂直滑块的底部显示最大值,从而反转滑块的范围。 |
| void setMinimum(int) int getMinimum()
int getMaximum() | 设置或获取滑块的最小值或最大值。这些方法一起设置或获取滑块的范围。 |
| void setMajorTickSpacing(int) int getMajorTickSpacing()
int getMinorTickSpacing() | 设置或获取主刻度和次刻度之间的范围。必须调用setPaintTicks(true)
才能显示刻度标记。 |
void setPaintTicks(boolean) boolean getPaintTicks() | 设置或获取是否在滑块上绘制刻度标记。 |
---|---|
void setPaintLabels(boolean) boolean getPaintLabels() | 设置或获取是否在滑块上绘制标签。您可以通过setLabelTable 提供自定义标签,或者通过将主刻度间距设置为非零值来获取自动标签。 |
void setLabelTable(Dictionary) Dictionary getLabelTable() | 设置或获取滑块的标签。您必须调用setPaintLabels(true) 才能显示标签。 |
Hashtable createStandardLabels(int) Hashtable createStandardLabels(int, int) | 创建一组标准的数字标签。第一个int 参数指定增量,第二个int 参数指定起始点。当未指定时,起始点设置为滑块的最小数字。 |
setFont(java.awt.Font) | 设置滑块标签的字体。 |
观察滑块操作
方法 | 目的 |
---|---|
void addChangeListener(ChangeListener) | 向滑块注册一个变更监听器。 |
boolean getValueIsAdjusting() | 确定用户移动滑块按钮的手势是否完成。 |
直接使用数据模型
类、接口或方法 | 目的 |
---|---|
BoundedRangeModel | 滑块数据模型所需的接口。 |
DefaultBoundedRangeModel | BoundedRangeModel 接口的实现。 |
(在JSlider
中) | 设置或获取滑块使用的数据模型。您也可以通过使用接受BoundedRangeModel
类型单一参数的构造函数来设置模型。 |
使用滑块的示例
该表格展示了使用JSlider
的示例以及这些示例的描述位置。
示例 | 描述位置 | 备注 |
---|---|---|
SliderDemo |
本节 | 展示了带有主要刻度标签的滑块。 |
SliderDemo2 |
本节 | 展示了带有自定义标签的垂直滑块。 |
Converter |
使用模型, 如何使用面板 | 一个特色是两个共享数据并具有自定义BoundedRangeModel 的滑块的测量转换应用程序。 |
如果您正在使用 JavaFX 进行编程,请参阅滑块。
标签:教程,菜单,Java,int,void,2022,组件,滚动,窗格 From: https://www.cnblogs.com/apachecn/p/18131176