已编辑--提供所需类(class)
编辑#2 - 所需的类(class)来自 here因此不需要调试,尽管我确实将 Vector
更改为 ArrayList
。
我通过使用 showMessageDialog
并将方法 (popup
) 传递给 Object message
参数创建了此弹出(模式)表单。我添加了遍历策略,扩展为允许光标键移动焦点,除了以下情况外,它的效果很好。
我唯一解决不了的问题是如何让光标键立即起作用。 “确定”按钮最初具有焦点,唯一可以移动焦点的键是 TAB
。一旦 JRadioButton 获得焦点,光标键就可以很好地移动焦点。
// LOSE THIS!! import Main.MyFocusTraversalPolicy;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.*;
import static java.awt.event.KeyEvent.*;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
public class NewMain {
static JPanel pnlPopup;
static MyFocusTraversalPolicy ftPolicy;
static JRadioButton rbtAsShown = new JRadioButton();
static JRadioButton rbtRandomly = new JRadioButton();
static JRadioButton rbtUser = new JRadioButton();
static JLabel lblAvailableDefinitionMethod = new JLabel();
private static int popup() {
pnlPopup = new JPanel(new GridLayout(4, 1));
ButtonGroup buttonGroup1 = new ButtonGroup();
buttonGroup1.add(rbtAsShown);
rbtAsShown.setSelected(false);
rbtRandomly.setSelected(true);
rbtUser.setSelected(false);
rbtAsShown.setText("As already shown above");
rbtAsShown.addFocusListener(new FocusAdapter(){
public void focusGained(FocusEvent e){
rbtAsShown.setSelected(true);
}});
rbtRandomly.addFocusListener(new FocusAdapter(){
public void focusGained(FocusEvent e){
rbtRandomly.setSelected(true);
}});
rbtUser.addFocusListener(new FocusAdapter(){
public void focusGained(FocusEvent e){
rbtUser.setSelected(true);
}});
rbtAsShown.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent evt){
rbtRandomly.setSelected(false);
rbtUser.setSelected(false);
}});
buttonGroup1.add(rbtRandomly);
rbtRandomly.setText("Randomly");
rbtRandomly.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent evt){
rbtAsShown.setSelected(false);
rbtUser.setSelected(false);
}});
buttonGroup1.add(rbtUser);
rbtUser.setText("I'll type them");
rbtUser.addItemListener(new java.awt.event.ItemListener(){
public void itemStateChanged(java.awt.event.ItemEvent evt){
rbtRandomly.setSelected(false);
rbtAsShown.setSelected(false);
}});
lblAvailableDefinitionMethod.setText("How should 'Available letters' be defined?");
rbtUser.setMnemonic(VK_I);
rbtRandomly.setMnemonic(VK_R);
rbtAsShown.setMnemonic(VK_A);
pnlPopup.add(lblAvailableDefinitionMethod);
pnlPopup.add(rbtRandomly);
pnlPopup.add(rbtUser);
pnlPopup.add(rbtAsShown);
Set downKeys;
downKeys = pnlPopup.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
Set newDownKeys = new HashSet(downKeys);
newDownKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
pnlPopup.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newDownKeys);
Set upKeys;
upKeys = pnlPopup.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
Set newUpKeys = new HashSet(upKeys);
newUpKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
pnlPopup.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, newUpKeys);
pnlPopup.setFocusTraversalPolicy(ftPolicy);
rbtRandomly.requestFocusInWindow();
pnlPopup.setFocusCycleRoot(true);
return JOptionPane.showConfirmDialog(null,
pnlPopup,
"Define Available letters",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
}
public static void main(String[] args){
if(popup() == -1) JOptionPane.showMessageDialog(null,"Cancelled");
else JOptionPane.showMessageDialog(null,"OK");
}
}
这是类MyFocusTraversalPolicy
。抱歉我忘了。
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.util.ArrayList;
public class MyFocusTraversalPolicy extends FocusTraversalPolicy
{
ArrayList<Component> order; // class var
public MyFocusTraversalPolicy(ArrayList<Component> o) {
this.order = new ArrayList<> (o.size());
this.order.addAll (o);
}
public Component getComponentAfter(Container focusCycleRoot,
Component aComponent)
{
int idx = (order.indexOf(aComponent) + 1) % order.size();
return order.get(idx);
}
public Component getComponentBefore(Container focusCycleRoot,
Component aComponent)
{
int idx = order.indexOf(aComponent) - 1;
if (idx < 0) {
idx = order.size() - 1;
}
return order.get(idx);
}
public Component getDefaultComponent(Container focusCycleRoot) {
return order.get(0);
}
public Component getLastComponent(Container focusCycleRoot) {
return order.get(order.size());
}
public Component getFirstComponent(Container focusCycleRoot) {
return order.get(0);
}
}
由于 showOptionDialog
的工作原理,我认为 rbtRandomly.requestFocusInWindow();
不会将焦点赋予按钮 rbtRandomly
。
如何才能使光标键在表单弹出时立即在按钮之间移动光标?
附注
我使用弹出表单是因为我需要 OK
和 Cancel
按钮来确认用户选择或希望不继续。我想要一个带有按钮的弹出表单,否则 UI 看起来和感觉都很粗糙。
最佳答案
当 @Aqua 用链接发表评论时,我几乎已经解决了我的问题。 “按照我的方式”做这件事需要做更多的工作,所以我打算点击链接。以下是生成此窗口的方法,其中光标键在 3 个按钮之间移动焦点,并且还有一个好处是让 Esc
和 Enter
执行Cancel
code> 和 OK
操作。它还基于 @HovercraftFullOfEels here 提供的答案,建议使用 JDialog
而不是 JOptionPane.showMessageDialog
。
static JDialog dialog = null;
static boolean retval ;
static MyFocusTraversalPolicy ftPolicy;
static JRadioButton rbtAsShown = new JRadioButton();
static JRadioButton rbtRandomly = new JRadioButton();
static JRadioButton rbtUser = new JRadioButton();
private static boolean popup() {
JLabel lblAvailableDefinitionMethod = new JLabel();
KeyBoundButton btnOK;
JPanel pnlPopup;
ButtonGroup buttonGroup1 = new ButtonGroup();
buttonGroup1.add(rbtAsShown);
rbtAsShown.setSelected(false);
rbtRandomly.setSelected(false);
rbtUser.setSelected(false);
rbtAsShown.setText("As already shown above");
rbtAsShown.addFocusListener(new FocusAdapter(){
public void focusGained(FocusEvent e){
rbtAsShown.setSelected(true);
}});
rbtRandomly.addFocusListener(new FocusAdapter(){
public void focusGained(FocusEvent e){
rbtRandomly.setSelected(true);
}});
rbtUser.addFocusListener(new FocusAdapter(){
public void focusGained(FocusEvent e){
rbtUser.setSelected(true);
}});
rbtAsShown.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent evt){
rbtRandomly.setSelected(false);
rbtUser.setSelected(false);
}});
buttonGroup1.add(rbtRandomly);
rbtRandomly.setText("Randomly");
rbtRandomly.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent evt){
rbtAsShown.setSelected(false);
rbtUser.setSelected(false);
}});
buttonGroup1.add(rbtUser);
rbtUser.setText("I'll type them");
rbtUser.addItemListener(new java.awt.event.ItemListener(){
public void itemStateChanged(java.awt.event.ItemEvent evt){
rbtRandomly.setSelected(false);
rbtAsShown.setSelected(false);
}});
lblAvailableDefinitionMethod.setText("How should 'Available letters' be defined?");
rbtUser.setMnemonic(VK_I);
rbtRandomly.setMnemonic(VK_R);
rbtAsShown.setMnemonic(VK_A);
btnOK = new KeyBoundButton("OK", VK_ENTER, 0){
@Override public void action(ActionEvent e){
retval = true;
dialog.dispose();
}};
KeyBoundButton btnCancel = new KeyBoundButton("Cancel", VK_ESCAPE, 0){
@Override public void action(ActionEvent e){
retval = false;
dialog.dispose();
}};
pnlPopup = new JPanel(new GridBagLayout());
pnlPopup.add(lblAvailableDefinitionMethod, new GBConstraints(0,0));
pnlPopup.add(rbtRandomly, new GBConstraints(0,1));
pnlPopup.add(rbtUser, new GBConstraints(0,2));
pnlPopup.add(rbtAsShown, new GBConstraints(0,3));
pnlPopup.add(btnOK, new GBConstraints(0,4).anchor(WEST));
pnlPopup.add(btnCancel, new GBConstraints(0,4).anchor(EAST));
Set downKeys;
downKeys = pnlPopup.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
Set newDownKeys = new HashSet(downKeys);
newDownKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
pnlPopup.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newDownKeys);
Set upKeys;
upKeys = pnlPopup.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
Set newUpKeys = new HashSet(upKeys);
newUpKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
pnlPopup.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, newUpKeys);
ArrayList<Component> order1 = new ArrayList<>(3);
order1.add(rbtRandomly);
order1.add(rbtUser);
order1.add(rbtAsShown);
ftPolicy = new MyFocusTraversalPolicy(order1);
pnlPopup.setFocusTraversalPolicy(ftPolicy);
pnlPopup.setFocusCycleRoot(true);
dialog = new JDialog(null, "Dialog Title", Dialog.ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(pnlPopup);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
return retval && (rbtAsShown.isSelected() || rbtUser.isSelected() || rbtRandomly.isSelected());
}
public static void main(String[] args){
if(popup()){
if(rbtAsShown.isSelected()) JOptionPane.showMessageDialog(null,"As shown");
if(rbtRandomly.isSelected())JOptionPane.showMessageDialog(null,"Random");
if(rbtUser.isSelected()) JOptionPane.showMessageDialog(null,"User");
}
else
JOptionPane.showMessageDialog(null,"Cancelled");
}
这里是KeyBoundButton
,它将转义映射为取消,输入映射为确定。
import java.awt.event.ActionEvent;
import javax.swing.*;
import static javax.swing.KeyStroke.getKeyStroke;
public abstract class KeyBoundButton extends JButton{
public abstract void action(ActionEvent e);
public KeyBoundButton(String buttonText, char acc, int key, int mask){
Action myAction = new AbstractAction()
{
@Override public void actionPerformed(ActionEvent e)
{
action(e);
}
};
setAction(myAction);
setText(buttonText);
setMnemonic(acc);
getInputMap(WHEN_IN_FOCUSED_WINDOW)
.put(getKeyStroke(key, mask),buttonText);
getActionMap().put( buttonText, myAction);
}
public KeyBoundButton(String buttonText, int key, int mask)
{
this(buttonText, buttonText.charAt(0), key, mask );
}
}
关于java - 如何使 JRadioButton 在通过向 showMessageDialog 传递方法创建的弹出表单中具有焦点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29658650/