概要

Swingでメニューバーを扱うときはJMenuBarを使います。メニューバーのメニューはJMenu、さらにそのメニューを押したときに表示される一覧はJMenuItemを使います。JMenuBarにJMenuを追加するときにaddメソッドを使いますが、このaddメソッドは返り値として追加したJMenuを返してくれます。なので

var fileMenu = new JMenu("ファイル(F)");
menubar.add(fileMenu);

としてもいいのですが下記のように書くこともできます。

var fileMenu = menubar.add(new JMenu("ファイル(F)"));

addメソッドの引数に直接JMenuのコンストラクタ書いて受け取ると行数が減るのと同時に、JMenuを作ったけどJMenuBarに追加し忘れた!ということを防ぐ効果があります。私はよく作ったけど追加し忘れた!をよくやるので後者の呼び方をよく使います。これはJMenuItemをJMenuに追加するときも同じで下記のように書けます。

var openItem = fileMenu.add(new JMenuItem("開く(O)", 'O'));

ちなみにJMenuItemの引数には上記のように2番目の引数に文字を指定できます。これを設定しておくとShift+指定した文字の組み合わせでメニューを呼び出すことができます。JMenuItemの場合はJMenuを押して一覧がでているときにしか効果がありませんが、JMenuにも文字を指定することで、Shift+Fでファイルメニューを選びそこからShift+Oで開くを選ぶことが可能です。悲しいことにJMenuitemはコンストラクタの引数で文字を設定できますが、JMenuではコンストラクタで文字が指定できないので、setMnemonicメソッドで文字をしてします。まぁ、これはJMenuItemにアクセラレータを設定するとJMenuを開かずしていきなり開くを押したときの処理が呼び出せるのでそれほど重要じゃないかもしれないですが…アクセラレータはよくCtrl+文字の組み合わせでメニューに表示されています。Swingでは以下のように書くと、JMenuItemにCtrl+O(Swingだと実際はCtrl-Oのように表示されていたりしますが…)のようなテキストが自動的に付与されます。

openItem.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK));

今回のサンプルのスクリーンショットを載せます。JFrameにJTextAreaを追加してJMenuItemも最低限のものを置いています。JMenuに表示されている線はaddSeparatorで追加できます。

ソースコード

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JOptionPane;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;

import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import java.awt.Dimension;
import java.awt.event.InputEvent;

public class JMenuSample{
    public static void main(String... args){
        SwingUtilities.invokeLater(JMenuSample::start);
    }
    
    private static void start(){
        var frame = new JFrame();

        var area = new JTextArea();
        area.setPreferredSize(new Dimension(400, 300));

        //メニューバー作成
        var menubar = new JMenuBar();
        
        //JMenuを作成してメニューバーに追加
        var fileMenu = menubar.add(new JMenu("ファイル(F)"));
        
        //Shift+Fの組み合わせで選択可能にする
        fileMenu.setMnemonic('F');
        
        //JMenuItemの作成と追加を同時に行う。コンストラクタで文字を指定することでShift+Oの組み合わせで選択可能に出来る。
        var openItem = fileMenu.add(new JMenuItem("開く(O)", 'O'));
        
        //今回のサンプルでは選択されたときはメッセージダイアログを表示するのみ
        openItem.addActionListener(e -> JOptionPane.showMessageDialog(frame, "開くが押されました"));
        
        //アクセラレータの設定。この例ではCtrl+OでJMenuを経由せずに選択可能になる
        openItem.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.CTRL_DOWN_MASK));
        
        var saveItem = fileMenu.add(new JMenuItem("上書き保存(S)", 'S'));
        saveItem.addActionListener(e -> JOptionPane.showMessageDialog(frame, "上書き保存が押されました"));
        saveItem.setAccelerator(KeyStroke.getKeyStroke('S', InputEvent.CTRL_DOWN_MASK));
        
        //区切り線の追加
        fileMenu.addSeparator();
        
        var printItem = fileMenu.add(new JMenuItem("印刷(P)", 'P'));
        printItem.addActionListener(e -> JOptionPane.showMessageDialog(frame, "印刷が押されました"));
        printItem.setAccelerator(KeyStroke.getKeyStroke('P', InputEvent.CTRL_DOWN_MASK));
        
        frame.add(area);
        frame.setJMenuBar(menubar);
        
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
    }
}