メニューの特定の項目をプログラムで選択して表示し、Enter キーを押すと対応するアクションが実行されるようにしたいと考えています。残念ながら、JMenuItem.setSelected() も JPopupMenu.setSelectedItem() も私が望むことをしないことがわかりました。基本的に、矢印キーが押されたとき、またはマウスが特定のアイテムのスペースに移動したときに何が起こるかを知りたいです-背景色が変わり、選択を示します。私はそれをプログラムしませんでした。これらの API が同じことをしないのはなぜですか? これは私を夢中にさせています。そんなに難しくないはずです。私が望むことをするAPIはありますか?
5 に答える
これはちょっとうまくいきました:
JMenuItem#setArmed(boolean);
JMenusをトラバースしてそこに到達しない限り、表示されませんが。おそらく、その上の各メニューでそれを呼び出すとしたらどうでしょうか。
編集: おそらくあなたはあなたのメニュー項目のための加速器が欲しいですか?参照:メニューの使用方法:キーボード操作の有効化
java.awt.Robot
トリックを行うことができます ;)
以下に示すコードを検討してください。
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.Robot;
public class JMenuFrame extends JFrame implements ActionListener
{
JMenuBar bar;
JMenu menu ;
String[] items;
JMenuItem[] menuItems;
JButton start;
Robot robot;
public void prepareAndShowGUI()
{
try
{
robot = new Robot();
}
catch (Exception ex){}
bar = new JMenuBar();
menu = new JMenu("File");
items = new String[]{"Open","Save","Save As","Quit"};
menuItems = new JMenuItem[items.length];
start = new JButton("Click me");
for (int i = 0 ; i < items.length ; i++)
{
menuItems[i] = new JMenuItem(items[i]);
menuItems[i].addActionListener(this);
menu.add(menuItems[i]);
}
bar.add(menu);
setJMenuBar(bar);
start.addActionListener(this);
getContentPane().add(start,BorderLayout.SOUTH);
setPreferredSize(new Dimension(300,400));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent evt)
{
if ("Click me".equals(evt.getActionCommand()))
{
menu.doClick();
if (robot!=null)
{
for (int i = 0 ; i<=2 ; i++) //Suppose you want to select 3rd MenuItem
{
if (!menuItems[i].isEnabled())
{
continue;
}
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_UP);
}
}
}
else
{
JOptionPane.showMessageDialog(this,evt.getActionCommand()+" is pressed","Information",JOptionPane.INFORMATION_MESSAGE);
}
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
JMenuFrame mf = new JMenuFrame();
mf.prepareAndShowGUI();
}
});
}
}
jMenu1.doClick(); // this open the menu again
それは罪のように醜いですが、これは、上記の splungebob の setArmed() の回答に関連して、完全な解決策です。最初に、メニューを MenuKeyListener にして、それ自体に MenuKeyListener を追加します。それで:
public void menuKeyReleased(MenuKeyEvent e) {
if (e.getModifiers() == 0) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ENTER:
case KeyEvent.VK_SPACE:
for (MenuElement elem : this.getSubElements()) {
if (elem instanceof JMenuItem) {
JMenuItem item = (JMenuItem) elem;
if (item.isArmed()) {
Action action = item.getAction();
if (action != null) {
action.actionPerformed(new ActionEvent(this, 0, null));
e.consume();
setVisible(false);
}
}
}
}
}
}
}
これがこんなに大変だったなんて信じられない。キーボード中心のインターフェースを構築する場合、Swing には明確な制限があります。
要件に同意するかどうかはわかりませんが (OP のコメントを参照してください)、それでも試してみたいと思いました。コードの前半は、ユーザーが条件を作成できるように GUI をセットアップするだけです。
- メニューは 3 つの項目で作成され、メニュー項目の状態を制御するために 3 つの個別のチェックボックスが作成されます。
- 常に 1 つのメニュー項目のみが有効になっている場合は、メニューを自動展開し、項目を「事前選択」します。メニューを自動展開するコードは、JMenu から取り出されました。
- MenuKeyListener をメニューに追加して、メニュー ツリーが展開されている間にスペース バーを押すユーザーをキャプチャします。
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
public class JMenuDemo implements Runnable
{
private final String[] ACTIONS = new String[]{"Open", "Print", "Close"};
private JMenu fileMenu;
private JMenuItem[] menuItems;
private JCheckBox[] checkBoxes;
public static void main(String args[])
{
SwingUtilities.invokeLater(new JMenuDemo());
}
public void run()
{
JPanel panel = new JPanel(new GridLayout(0,1));
panel.setBorder(BorderFactory.createTitledBorder("Enabled"));
menuItems = new JMenuItem[ACTIONS.length];
checkBoxes = new JCheckBox[ACTIONS.length];
for (int i = 0; i < ACTIONS.length; i++)
{
final int index = i;
final String action = ACTIONS[i];
menuItems[i] = new JMenuItem(action);
menuItems[i].setAccelerator(KeyStroke.getKeyStroke(action.charAt(0),
ActionEvent.ALT_MASK));
menuItems[i].setMnemonic(action.charAt(0));
menuItems[i].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.out.println(action);
}
});
checkBoxes[i] = new JCheckBox(action);
checkBoxes[i].setSelected(true);
checkBoxes[i].addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent event)
{
checkBoxChanged(index);
}
});
panel.add(checkBoxes[i]);
}
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(createJMenuBar());
frame.add(panel, BorderLayout.SOUTH);
frame.setSize(300, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void checkBoxChanged(int index)
{
menuItems[index].setEnabled(checkBoxes[index].isSelected());
evaluate();
}
private JMenuBar createJMenuBar()
{
fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
fileMenu.addMenuKeyListener(new MenuKeyListener()
{
@Override
public void menuKeyTyped(MenuKeyEvent event)
{
autoClick(event);
}
@Override
public void menuKeyPressed(MenuKeyEvent event) {}
@Override
public void menuKeyReleased(MenuKeyEvent event) {}
});
for (int i = 0; i < menuItems.length; i++)
{
fileMenu.add(menuItems[i]);
}
JMenuBar menuBar = new JMenuBar();
menuBar.add(fileMenu);
return menuBar;
}
private void autoClick(MenuKeyEvent event)
{
if (event.getModifiers() == 0 && event.getKeyChar() == KeyEvent.VK_SPACE)
{
for (JMenuItem menuItem : menuItems)
{
if (menuItem.isArmed())
{
menuItem.doClick();
MenuSelectionManager.defaultManager().setSelectedPath(null);
}
}
}
}
private void evaluate()
{
JMenuItem onlyOne = null;
for (JMenuItem menuItem : menuItems)
{
menuItem.setArmed(false);
if (menuItem.isEnabled())
{
if (onlyOne == null)
{
onlyOne = menuItem;
}
else
{
onlyOne = null;
break;
}
}
}
// Show the path if only one is enabled
if (onlyOne != null)
{
onlyOne.setArmed(true);
MenuElement me[] = buildMenuElementArray(fileMenu);
MenuSelectionManager.defaultManager().setSelectedPath(me);
}
}
/*
* Copied from JMenu
*/
private MenuElement[] buildMenuElementArray(JMenu leaf)
{
Vector<JComponent> elements = new Vector<JComponent>();
Component current = leaf.getPopupMenu();
while (true)
{
if (current instanceof JPopupMenu)
{
JPopupMenu pop = (JPopupMenu) current;
elements.insertElementAt(pop, 0);
current = pop.getInvoker();
}
else if (current instanceof JMenu)
{
JMenu menu = (JMenu) current;
elements.insertElementAt(menu, 0);
current = menu.getParent();
}
else if (current instanceof JMenuBar)
{
JMenuBar bar = (JMenuBar) current;
elements.insertElementAt(bar, 0);
MenuElement me[] = new MenuElement[elements.size()];
elements.copyInto(me);
return me;
}
}
}
}