ZetCode

Java Swing 中的菜单和工具栏

最后修改于 2023 年 1 月 10 日

在本 Java Swing 教程中,我们将学习菜单和工具栏。在示例中,我们将创建普通菜单、子菜单、复选框菜单项、单选按钮菜单项、弹出菜单和工具栏。

菜单是位于菜单栏中的一组命令。工具栏具有应用程序中一些常用命令的按钮。

我们将使用以下组件

Swing JMenuBar

我们从一个简单的菜单栏示例开始。

com/zetcode/SimpleMenuEx.java
package com.zetcode;

import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

public class SimpleMenuEx extends JFrame {

    public SimpleMenuEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();

        setTitle("Simple menu");
        setSize(350, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();
        var exitIcon = new ImageIcon("src/resources/exit.png");

        var fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);

        var eMenuItem = new JMenuItem("Exit", exitIcon);
        eMenuItem.setMnemonic(KeyEvent.VK_E);
        eMenuItem.setToolTipText("Exit application");
        eMenuItem.addActionListener((event) -> System.exit(0));

        fileMenu.add(eMenuItem);
        menuBar.add(fileMenu);

        setJMenuBar(menuBar);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new SimpleMenuEx();
            ex.setVisible(true);
        });
    }
}

我们的示例将显示一个包含一个项目的菜单。选择退出菜单项将关闭应用程序。

var menuBar = new JMenuBar();

菜单栏用 JMenuBar 创建。

var exitIcon = new ImageIcon("src/resources/exit.png");

退出图标显示在菜单中。

var fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);

菜单对象用 JMenu 类创建。菜单也可以通过键盘访问。要将菜单绑定到特定键,我们使用 setMnemonic() 方法。在我们的例子中,菜单可以使用 Alt+F 快捷键打开。

var eMenuItem = new JMenuItem("Exit", exitIcon);
eMenuItem.setMnemonic(KeyEvent.VK_E);

菜单对象由菜单项组成。菜单项使用 JMenuItem 类创建。菜单项有自己的助记符。它可以使用 Alt+F+E 组合键激活。

eMenuItem.setToolTipText("Exit application");

这行代码为菜单项创建一个工具提示。

eMenuItem.addActionListener((event) -> System.exit(0));

JMenuItem 是一种特殊的按钮组件。我们向它添加一个动作监听器,该监听器会终止应用程序。

fileMenu.add(eMenuItem);
menuBar.add(fileMenu);

菜单项被添加到菜单对象中,菜单对象被插入到菜单栏中。

setJMenuBar(menuBar);

setJMenuBar() 方法为 JFrame 容器设置菜单栏。

Simple menu
图:简单菜单

Swing 子菜单

每个菜单也可以有一个子菜单。通过这种方式,我们可以将类似的命令放入组中。例如,我们可以将隐藏和显示各种工具栏的命令(如个人栏、地址栏、状态栏或导航栏)放入一个名为工具栏的子菜单中。在菜单中,我们可以使用分隔符分隔命令。分隔符是一条简单的线。通常的做法是使用单个分隔符分隔“新建”、“打开”、“保存”等命令,以及“打印”、“打印预览”等命令。除了助记符之外,菜单命令还可以通过加速器启动。

com/zetcode/SubmenuEx.java
package com.zetcode;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import java.awt.EventQueue;

public class SubmenuEx extends JFrame {

    public SubmenuEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();

        setTitle("Submenu");
        setSize(360, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();

        var iconNew = new ImageIcon("src/resources/new.png");
        var iconOpen = new ImageIcon("src/resources/open.png");
        var iconSave = new ImageIcon("src/resources/save.png");
        var iconExit = new ImageIcon("src/resources/exit.png");

        var fileMenu = new JMenu("File");
        var impMenu = new JMenu("Import");

        var newsMenuItem = new JMenuItem("Import newsfeed list...");
        var bookmarksMenuItem = new JMenuItem("Import bookmarks...");
        var importMailMenuItem = new JMenuItem("Import mail...");

        impMenu.add(newsMenuItem);
        impMenu.add(bookmarksMenuItem);
        impMenu.add(importMailMenuItem);

        var newMenuItem = new JMenuItem("New", iconNew);
        var openMenuItem = new JMenuItem("Open", iconOpen);
        var saveMenuItem = new JMenuItem("Save", iconSave);

        var exitMenuItem = new JMenuItem("Exit", iconExit);
        exitMenuItem.setToolTipText("Exit application");

        exitMenuItem.addActionListener((event) -> System.exit(0));

        fileMenu.add(newMenuItem);
        fileMenu.add(openMenuItem);
        fileMenu.add(saveMenuItem);
        fileMenu.addSeparator();
        fileMenu.add(impMenu);
        fileMenu.addSeparator();
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        setJMenuBar(menuBar);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new SubmenuEx();
            ex.setVisible(true);
        });
    }
}

此示例创建一个子菜单,并使用菜单分隔符分隔菜单项组。

var impMenu = new JMenu("Import");
...
fileMenu.add(impMenu);

子菜单就像任何其他普通菜单一样。它以相同的方式创建。我们只需将一个菜单添加到现有菜单即可。

exitMenuItem.setToolTipText("Exit application");

工具提示通过 setToolTipText() 方法设置为退出菜单项。

var newMenuItem = new JMenuItem("New", iconNew);

JMenuItem 构造函数创建一个带有标签和图标的菜单项。

fileMenu.addSeparator();

分隔符是一条水平线,用于在视觉上分隔菜单项。通过这种方式,我们可以将项目分组到一些逻辑位置。分隔符用 addSeparator() 方法创建。

Submenu
图:子菜单

Swing 助记符和加速器

助记符和加速器是快捷键,允许通过键盘执行命令。助记符导航菜单层次结构以选择特定的菜单项,而加速器绕过菜单层次结构并直接激活菜单项。

以下示例利用了动作,动作是可以由需要相同功能的不同组件共享的对象。

com/zetcode/ShortcutsEx.java
package com.zetcode;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

public class ShortcutsEx extends JFrame {

    public ShortcutsEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();

        setTitle("Mnemonics and accelerators");
        setSize(360, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();

        var iconNew = new ImageIcon("src/resources/new.png");
        var iconOpen = new ImageIcon("src/resources/open.png");
        var iconSave = new ImageIcon("src/resources/save.png");
        var iconExit = new ImageIcon("src/resources/exit.png");

        var fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);

        var newMenuItem = new JMenuItem(new MenuItemAction("New", iconNew,
                KeyEvent.VK_N));

        var openMenuItem = new JMenuItem(new MenuItemAction("Open", iconOpen,
                KeyEvent.VK_O));

        var saveMenuItem = new JMenuItem(new MenuItemAction("Save", iconSave,
                KeyEvent.VK_S));

        var exitMenuItem = new JMenuItem("Exit", iconExit);
        exitMenuItem.setMnemonic(KeyEvent.VK_E);
        exitMenuItem.setToolTipText("Exit application");
        exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W,
                InputEvent.CTRL_DOWN_MASK));

        exitMenuItem.addActionListener((event) -> System.exit(0));

        fileMenu.add(newMenuItem);
        fileMenu.add(openMenuItem);
        fileMenu.add(saveMenuItem);
        fileMenu.addSeparator();
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        setJMenuBar(menuBar);
    }

    private class MenuItemAction extends AbstractAction {

        public MenuItemAction(String text, ImageIcon icon,
                              Integer mnemonic) {
            super(text);

            putValue(SMALL_ICON, icon);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            System.out.println(e.getActionCommand());
        }
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new ShortcutsEx();
            ex.setVisible(true);
        });
    }
}

该示例具有几个助记符和一个加速器。三个菜单项共享一个动作对象。选择这三个菜单项会导致它们的操作命令被打印到控制台。

var fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);

助记符设置为“文件”菜单。现在可以使用 Alt+F 快捷键激活菜单。

var newMenuItem = new JMenuItem(new MenuItemAction("New", iconNew,
        KeyEvent.VK_N));

“新建”菜单项将一个动作对象作为参数。它的构造函数接受文本标签、图标和助记符作为参数。

exitMenuItem.setMnemonic(KeyEvent.VK_E);

“退出”菜单项不使用动作对象。它的功能是单独构建的。我们调用 setMnemonic() 方法来设置助记符。要使用助记符,组件必须在屏幕上可见。因此,我们必须首先激活菜单对象,这会使“退出”菜单项可见,然后我们可以激活此菜单项。这意味着此菜单项由 Alt+F+E 组合键激活。

exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W,
        ActionEvent.CTRL_MASK));

加速器是直接启动菜单项的快捷键。在我们的例子中,通过按 Ctrl+W 我们关闭应用程序。加速器使用 setAccelerator() 方法设置。

private class MenuItemAction extends AbstractAction {
    
    public MenuItemAction(String text, ImageIcon icon, 
            Integer mnemonic) {
        super(text);
        
        putValue(SMALL_ICON, icon);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        
        System.out.println(e.getActionCommand());
    }
}

此动作类的实例由三个菜单项共享。动作使用各种键来定义它们的功能。putValue() 方法将字符串值与指定的键关联起来。

Mnemonics and accelerators
图:助记符和加速器

助记符通过带下划线的字符在视觉上提示,加速器在其菜单项标签旁边显示其快捷键。

JCheckBoxMenuItem

JCheckBoxMenuItem 是一个可以选中或取消选中的菜单项。如果选中,菜单项通常在其旁边显示一个复选标记。如果未选中或取消选中,菜单项将显示,没有复选标记。与普通菜单项一样,复选框菜单项可以关联文本或图形图标,或两者兼而有之。

com/zetcode/CheckBoxMenuItemEx.java
package com.zetcode;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import javax.swing.BorderFactory;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;

public class CheckBoxMenuItemEx extends JFrame {

    private JLabel statusBar;

    public CheckBoxMenuItemEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();

        statusBar = new JLabel("Ready");
        statusBar.setBorder(BorderFactory.createEtchedBorder());
        add(statusBar, BorderLayout.SOUTH);

        setTitle("JCheckBoxMenuItem");
        setSize(360, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();
        var fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);

        var viewMenu = new JMenu("View");
        viewMenu.setMnemonic(KeyEvent.VK_V);

        var showStatusBarMenuItem = new JCheckBoxMenuItem("Show statubar");
        showStatusBarMenuItem.setMnemonic(KeyEvent.VK_S);
        showStatusBarMenuItem.setDisplayedMnemonicIndex(5);
        showStatusBarMenuItem.setSelected(true);

        showStatusBarMenuItem.addItemListener((e) -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                statusBar.setVisible(true);
            } else {
                statusBar.setVisible(false);
            }
        });

        viewMenu.add(showStatusBarMenuItem);

        menuBar.add(fileMenu);
        menuBar.add(viewMenu);

        setJMenuBar(menuBar);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new CheckBoxMenuItemEx();
            ex.setVisible(true);
        });
    }
}

此示例使用 JCheckBoxMenuItem 切换状态栏的可见性。

statusBar = new JLabel("Ready");
statusBar.setBorder(BorderFactory.createEtchedBorder());
add(statusBar, BorderLayout.SOUTH);

状态栏是一个简单的 JLabel 组件。我们在标签周围放置一个凸起的 EtchedBorder,使其可见。

var showStatusBarMenuItem = new JCheckBoxMenuItem("Show statubar");
showStatusBarMenuItem.setMnemonic(KeyEvent.VK_S);
showStatusBarMenuItem.setDisplayedMnemonicIndex(5);

JCheckBoxMenuItem 创建一个复选框菜单项。标签中有两个“s”,因此我们使用 setDisplayedMnemonicIndex() 方法来选择要带下划线的那个。我们选择了第二个。

showStatusBarMenuItem.setSelected(true);

由于状态栏最初是可见的,我们调用 JCheckBoxMenuItemsetSelected() 方法来选择它。

showStatusBarMenuItem.addItemListener((e) -> {
    if (e.getStateChange() == ItemEvent.SELECTED) {
        statusbar.setVisible(true);
    } else {
        statusbar.setVisible(false);
    }
});

JCheckBoxMenuItem 是一种特殊的按钮组件。它实现了 ItemSelectable 接口。可以使用 ItemListener 来监听其状态更改。根据其状态,我们显示或隐藏状态栏。

JCheckBoxMenuItem
图:JCheckBoxMenuItem

JRadioButtonMenuItem

JRadioButtonMenuItem 允许从互斥的选项列表中进行选择。选择特定的 JRadioButtonMenuItem 会取消选择所有其他项目。JRadioButtonMenuItems 放置在 ButtonGroup 中。

com/zetcode/RadioMenuItemEx.java
package com.zetcode;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRadioButtonMenuItem;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;

public class RadioMenuItemEx extends JFrame {

    private JLabel statusBar;

    public RadioMenuItemEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();

        statusBar = new JLabel("Easy");
        statusBar.setBorder(BorderFactory.createEtchedBorder());
        add(statusBar, BorderLayout.SOUTH);

        setTitle("JRadioButtonMenuItem");
        setSize(360, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();
        var difMenu = new JMenu("Difficulty");
        difMenu.setMnemonic(KeyEvent.VK_F);

        var difGroup = new ButtonGroup();

        var easyRMenuItem = new JRadioButtonMenuItem("Easy");
        easyRMenuItem.setSelected(true);
        difMenu.add(easyRMenuItem);

        easyRMenuItem.addItemListener((e) -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                statusBar.setText("Easy");
            }
        });

        var mediumRMenuItem = new JRadioButtonMenuItem("Medium");
        difMenu.add(mediumRMenuItem);

        mediumRMenuItem.addItemListener((e) -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                statusBar.setText("Medium");
            }
        });

        var hardRMenuItem = new JRadioButtonMenuItem("Hard");
        difMenu.add(hardRMenuItem);

        hardRMenuItem.addItemListener((e) -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                statusBar.setText("Hard");
            }
        });

        difGroup.add(easyRMenuItem);
        difGroup.add(mediumRMenuItem);
        difGroup.add(hardRMenuItem);

        menuBar.add(difMenu);

        setJMenuBar(menuBar);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new RadioMenuItemEx();
            ex.setVisible(true);
        });
    }
}

该示例创建了一个包含三个 JRadioButtonMenuItem 组件的菜单。

var difGroup = new ButtonGroup();

ButtonGroup 用于为一组按钮创建多重排除范围。

var easyRMenuItem = new JRadioButtonMenuItem("Easy");
easyRMenuItem.setSelected(true);
difMenu.add(easyRMenuItem);

创建一个新的 JRadioButtonMenuItem。它使用 setSelected() 方法进行选择,并使用 add() 方法将其放入按钮组中。

easyRMenuItem.addItemListener((e) -> {
    if (e.getStateChange() == ItemEvent.SELECTED) {
        statusbar.setText("Easy");
    }
});

ItemListener 用于监听 JRadioButtonMenuItem 的事件。getStateChange() 确定状态更改的类型。如果更改是 ItemEvent.SELECTED,我们更改状态栏上的状态。(另一个状态更改是 ItemEvent.DESELECTED。)

JRadioButtonMenuItem
图:JRadioButtonMenuItem

右侧菜单

某些应用程序在右侧显示菜单。通常,它是“帮助”菜单。

com/zetcode/RightMenuEx.java
package com.zetcode;

import java.awt.EventQueue;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;

public class RightMenuEx extends JFrame {

    public RightMenuEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();

        setTitle("Right menu");
        setSize(300, 200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();

        var fileMenu = new JMenu("File");
        var viewMenu = new JMenu("View");
        var toolsMenu = new JMenu("Tools");
        var helpMenu = new JMenu("Help");

        menuBar.add(fileMenu);
        menuBar.add(viewMenu);
        menuBar.add(toolsMenu);
        menuBar.add(Box.createHorizontalGlue());
        menuBar.add(helpMenu);

        setJMenuBar(menuBar);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new RightMenuEx();
            ex.setVisible(true);
        });
    }
}

该示例在左侧显示三个菜单,在右侧显示一个菜单。

var menubar = new JMenuBar();

var fileMenu = new JMenu("File");
var viewMenu = new JMenu("View");
var toolsMenu = new JMenu("Tools");
var helpMenu = new JMenu("Help");

创建了菜单栏和四个菜单对象。

menuBar.add(fileMenu);
menuBar.add(viewMenu);
menuBar.add(toolsMenu);
menuBar.add(Box.createHorizontalGlue());
menuBar.add(helpMenu);

添加了三个菜单后,我们使用 Box.createHorizontalGlue() 方法向菜单栏添加一个水平胶。胶水吸收所有可用的额外空间。这将把“帮助”菜单推到菜单栏的右侧。

Help menu on the right
图:右侧的“帮助”菜单

弹出菜单

另一种类型的菜单是弹出菜单。Java Swing 具有 JPopupMenu 类来实现此功能。它也称为上下文菜单,通常在我们右键单击一个组件时显示。其想法是仅提供与当前上下文相关的命令。假设我们有一张图片。通过右键单击该图片,我们得到一个弹出窗口,其中包含保存、缩放或移动图片的命令。

com/zetcode/PopupMenuEx.java
package com.zetcode;

import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

public class PopupMenuEx extends JFrame {

    private JPopupMenu popupMenu;

    public PopupMenuEx() {

        initUI();
    }

    private void initUI() {

        createPopupMenu();

        setTitle("JPopupMenu");
        setSize(300, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    private void createPopupMenu() {

        popupMenu = new JPopupMenu();

        var maximizeMenuItem = new JMenuItem("Maximize");
        maximizeMenuItem.addActionListener((e) -> {
            if (getExtendedState() != JFrame.MAXIMIZED_BOTH) {
                setExtendedState(JFrame.MAXIMIZED_BOTH);
                maximizeMenuItem.setEnabled(false);
            }
        });

        popupMenu.add(maximizeMenuItem);

        var quitMenuItem = new JMenuItem("Quit");
        quitMenuItem.addActionListener((e) -> System.exit(0));

        popupMenu.add(quitMenuItem);

        addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {

                if (getExtendedState() != JFrame.MAXIMIZED_BOTH) {
                    maximizeMenuItem.setEnabled(true);
                }

                if (e.getButton() == MouseEvent.BUTTON3) {
                    popupMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new PopupMenuEx();
            ex.setVisible(true);
        });
    }
}

该示例显示一个包含两个命令的弹出菜单。第一个命令最大化窗口,第二个命令退出应用程序。

popupMenu = new JPopupMenu();

JPopupMenu 创建一个弹出菜单。

var maximizeMenuItem = new JMenuItem("Maximize");
maximizeMenuItem.addActionListener((e) -> {
    if (getExtendedState() != JFrame.MAXIMIZED_BOTH) {
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        maximizeMenuItem.setEnabled(false);
    }
});

弹出菜单由 JMenuItems 组成。此项目将最大化框架。getExtendedState() 方法确定框架的状态。可用的状态有:NORMAL, ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT, and MAXIMIZED_BOTH。一旦框架最大化,我们使用 setEnabled() 方法禁用菜单项。

popupMenu.add(quitMenuItem);

菜单项使用 add() 插入到弹出菜单中。

addMouseListener(new MouseAdapter() {

    @Override
    public void mouseReleased(MouseEvent e) {

        if (getExtendedState() != JFrame.MAXIMIZED_BOTH) {
            maximizeMenuItem.setEnabled(true);
        }

        if (e.getButton() == MouseEvent.BUTTON3) {
            popupMenu.show(e.getComponent(), e.getX(), e.getY());
        }
    }
});

弹出菜单显示在我们用鼠标按钮单击的位置。getButton() 方法返回哪个鼠标按钮(如果有)更改了状态。MouseEvent.BUTTON3 仅允许右键单击弹出菜单。一旦窗口未最大化,我们就启用最大化菜单项。

JPopupMenu
图:JPopupMenu

JToolBar

菜单对应用程序中可以使用的命令进行分组。工具栏提供对最常用命令的快速访问。在 Java Swing 中,JToolBar 类在应用程序中创建一个工具栏。

com/zetcode/ToolbarEx.java
package com.zetcode;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JToolBar;
import java.awt.BorderLayout;
import java.awt.EventQueue;

public class ToolbarEx extends JFrame {

    public ToolbarEx() {

        initUI();
    }

    private void initUI() {

        createMenuBar();
        createToolBar();

        setTitle("Simple toolbar");
        setSize(300, 200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createMenuBar() {

        var menuBar = new JMenuBar();
        var fileMenu = new JMenu("File");

        menuBar.add(fileMenu);
        setJMenuBar(menuBar);
    }

    private void createToolBar() {

        var toolbar = new JToolBar();
        var icon = new ImageIcon("src/resources/exit2.png");

        var exitButton = new JButton(icon);
        toolbar.add(exitButton);

        exitButton.addActionListener((e) -> System.exit(0));

        add(toolbar, BorderLayout.NORTH);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new ToolbarEx();
            ex.setVisible(true);
        });
    }
}

该示例创建一个带有退出按钮的工具栏。

var toolbar = new JToolBar();

工具栏使用 JToolBar 创建。

var exitButton = new JButton(icon);
toolbar.add(exitButton);

我们创建一个按钮并将其添加到工具栏。插入到工具栏中的按钮是一个普通的 JButton

add(toolbar, BorderLayout.NORTH);

工具栏放置在 BorderLayout 的北侧区域。(BorderLayoutJFrame, JWindow, JDialog, JInternalFrameJApplet 的内容面板的默认布局管理器。)

JToolBar
图:JToolBar

Swing 工具栏

通常需要在窗口上显示多个工具栏。以下示例演示了如何执行此操作。

com/zetcode/ToolbarsEx.java
package com.zetcode;

import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JToolBar;
import java.awt.EventQueue;

public class ToolbarsEx extends JFrame {

    public ToolbarsEx() {

        initUI();
    }

    private void initUI() {

        createToolBars();

        setTitle("Toolbars");
        setSize(360, 250);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private void createToolBars() {

        var toolbar1 = new JToolBar();
        var toolbar2 = new JToolBar();

        var newIcon = new ImageIcon("src/resources/new2.png");
        var openIcon = new ImageIcon("src/resources/open2.png");
        var saveIcon = new ImageIcon("src/resources/save2.png");
        var exitIcon = new ImageIcon("src/resources/exit2.png");

        var newBtn = new JButton(newIcon);
        var openBtn = new JButton(openIcon);
        var saveBtn = new JButton(saveIcon);

        toolbar1.add(newBtn);
        toolbar1.add(openBtn);
        toolbar1.add(saveBtn);

        var exitBtn = new JButton(exitIcon);
        toolbar2.add(exitBtn);

        exitBtn.addActionListener((e) -> System.exit(0));

        createLayout(toolbar1, toolbar2);
    }

    private void createLayout(JComponent... arg) {

        var pane = getContentPane();
        var gl = new GroupLayout(pane);
        pane.setLayout(gl);

        gl.setHorizontalGroup(gl.createParallelGroup()
                .addComponent(arg[0], GroupLayout.DEFAULT_SIZE,
                        GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(arg[1], GroupLayout.DEFAULT_SIZE,
                        GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        gl.setVerticalGroup(gl.createSequentialGroup()
                .addComponent(arg[0])
                .addComponent(arg[1])
        );
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {

            var ex = new ToolbarsEx();
            ex.setVisible(true);
        });
    }
}

两个工具栏显示在窗口的顶部。

var toolbar1 = new JToolBar();
var toolbar2 = new JToolBar();

两个工具栏对象使用 JToolBar 创建。

private void createLayout(JComponent... arg) {

    var pane = getContentPane();
    var gl = new GroupLayout(pane);
    pane.setLayout(gl);

    gl.setHorizontalGroup(gl.createParallelGroup()
            .addComponent(arg[0], GroupLayout.DEFAULT_SIZE,
                    GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(arg[1], GroupLayout.DEFAULT_SIZE,
                    GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );

    gl.setVerticalGroup(gl.createSequentialGroup()
            .addComponent(arg[0])
            .addComponent(arg[1])
    );
}

GroupLayout 管理器用于将工具栏定位在容器的顶部。

Toolbars
图:工具栏

在本 Java Swing 教程中,我们提到了菜单和工具栏。我们使用了以下组件:JMenuBar, JMenu, JMenuItem, JSeparator, JCheckBoxMenuItem, JRadioButtonMenuItem, ButtonGroup, JPopupMenuJToolBar