![](/img/trans.png)
[英]How To Disable Arrow Key Navigation For Java Swing JRadioButton?
[英]JRadioButton navigation with arrow keys
我試圖使用箭頭鍵使一組JRadioButton
可以導航。 我打算使用KeyListeners手動實現此功能,但是顯然,這種行為至少應該在最近8年內起作用( http://bugs.sun.com/view_bug.do?bug_id=4104452 )。 但是,它對我不起作用:按箭頭鍵不會執行任何操作。 Java版本在Windows上為7u45。
一個獨立的測試用例,看看我在說什么:
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main(final String[] args) {
if (!EventQueue.isDispatchThread()) {
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
main(args);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return;
}
try {
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Throwable t) {
throw new RuntimeException(t);
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ButtonGroup group = new ButtonGroup();
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
JRadioButton rb;
rb = new JRadioButton("Option A");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option B");
panel.add(rb);
group.add(rb);
rb = new JRadioButton("Option C");
panel.add(rb);
group.add(rb);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
我嘗試使用不同的外觀和感覺,不同的容器和不同的布局管理器,但它仍然無法正常工作。
您需要將右/左(上/下?)鍵添加到每個單選按鈕的焦點遍歷策略中。 例如,添加左右箭頭鍵:
Set set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "RIGHT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set );
set = new HashSet( rb.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS ) );
set.add( KeyStroke.getKeyStroke( "LEFT" ) );
rb.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set );
我相信你可以使用KeyBindings而不是KeyListeners來實現你的目標。 在許多情況下,實際上建議綁定比KeyListeners,因為第二個可以產生許多問題(捕獲關鍵活動的幀必須是活動的等等)
謝謝大家的答案。
我發現了造成困惑的原因。 顯然,當Sun bug報告系統說錯誤狀態為“已關閉”且其“已解決日期”為“2005-07-19”時,這並不意味着該錯誤已得到修復。 顯然,它只是記錄為其他一些(較新的?)bug的副本。 自首次報道以來已近16年,它仍未得到修復。 隨你。
所需的行為比我意識到的要微妙得多。 我在各種程序中嘗試了本機Windows對話框:
我在下面實現了循環行為,因為它感覺更加流暢。 導航無聲地跳過了過去的非AbstractButton組件,從而形成了按鈕專用的一種單獨的聚焦周期。 這是可疑的,但有時需要將一組相關的復選框或單選按鈕與其他組件混合使用。 測試一個共同的父組件以識別組也是一種合理的行為,但是在一個對話框中我不能使用單獨的組件純粹出於布局原因(在FlowLayout中實現換行符)。
正如所建議的那樣,我研究了InputMaps和ActionMaps,而不是使用KeyListener。 我總是避免使用地圖,因為它們看起來過於復雜,但是我想我看到了能夠輕松覆蓋綁定的優點。
這段代碼使用輔助外觀為整個應用程序范圍內的所有AbstractButton組件安裝所需的行為(這是我在這里找到的一種不錯的技術)。 我用幾個不同的對話框和窗口測試了它,似乎沒問題。 如果它引起問題,我將更新此帖子。
呼叫:
ButtonArrowKeyNavigation.install();
一旦在應用程序啟動時安裝它。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonArrowKeyNavigation {
private ButtonArrowKeyNavigation() {}
public static void install() {
UIManager.addAuxiliaryLookAndFeel(lookAndFeel);
}
private static final LookAndFeel lookAndFeel = new LookAndFeel() {
private final UIDefaults defaults = new UIDefaults() {
@Override
public javax.swing.plaf.ComponentUI getUI(JComponent c) {
if (c instanceof AbstractButton && !(c instanceof JMenuItem)) {
if (c.getClientProperty(this) == null) {
c.putClientProperty(this, Boolean.TRUE);
configure(c);
}
}
return null;
}
};
@Override public UIDefaults getDefaults() { return defaults; };
@Override public String getID() { return "ButtonArrowKeyNavigation"; }
@Override public String getName() { return getID(); }
@Override public String getDescription() { return getID(); }
@Override public boolean isNativeLookAndFeel() { return false; }
@Override public boolean isSupportedLookAndFeel() { return true; }
};
private static void configure(JComponent c) {
InputMap im = c.getInputMap(JComponent.WHEN_FOCUSED);
ActionMap am = c.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "focusPreviousButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "focusNextButton");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "focusNextButton");
am.put("focusPreviousButton", focusPreviousButton);
am.put("focusNextButton", focusNextButton);
}
private static final Action focusPreviousButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), -1);
}
};
private static final Action focusNextButton = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
move((AbstractButton)e.getSource(), +1);
}
};
private static void move(AbstractButton ab, int direction) {
Container focusRoot = ab.getFocusCycleRootAncestor();
FocusTraversalPolicy focusPolicy = focusRoot.getFocusTraversalPolicy();
Component toFocus = ab, loop = null;
for (;;) {
toFocus = direction > 0
? focusPolicy.getComponentAfter(focusRoot, toFocus)
: focusPolicy.getComponentBefore(focusRoot, toFocus);
if (toFocus instanceof AbstractButton) break;
if (toFocus == null) return;
// infinite loop protection; should not be necessary, but just in
// case all buttons are somehow unfocusable at the moment this
// method is called:
if (loop == null) loop = toFocus; else if (loop == toFocus) return;
}
if (toFocus.requestFocusInWindow()) {
if (toFocus instanceof JRadioButton) {
((JRadioButton)toFocus).setSelected(true);
}
}
}
}
這是我的JRadioButtons示例,可以使用箭頭鍵(向上和向下)進行導航,並為您修改幾個代碼。
public class JRadioButton extends JPanel {
private JRadioButton[] buttons;
public JRadioButtonTest(int row) {
ButtonGroup group = new ButtonGroup();
buttons = new JRadioButton[row];
for (int i = 0; i < buttons.length; i++) {
final int curRow = i;
buttons[i] = new JRadioButton("Option " + i);
buttons[i].addKeyListener(enter);
buttons[i].addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
if (curRow > 0)
buttons[curRow - 1].requestFocus();
break;
case KeyEvent.VK_DOWN:
if (curRow < buttons.length - 1)
buttons[curRow + 1].requestFocus();
break;
default:
break;
}
}
});
group.add(buttons[i]);
add(buttons[i]);
}
}
private KeyListener enter = new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
((JButton) e.getComponent()).doClick();
}
}
};
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JRadioButton(3));
frame.pack();
frame.setVisible(true);
}
}
核心實現方法是在調用箭頭鍵時在正確的JRadioButton上調用requestFocus()。 按下Enter鍵時的額外KeyListener。
您可以將此KeyListener用於您的程序並添加更多密鑰。
祝好運!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.