Well its weird. I am not good with radiobuttons by the way. But I made a JPanel program in netbeans which includes a RadioButton. You enter all this information with JTextFields(no problem) and then lastly I had a JButton which you click the choice you want. Then I have a JButton that takes all the information and outputs this. For the RadioButton, I first entered the usual:
family = new JRadioButton("Family", true);
friend = new JRadioButton("Friend");
relative = new JRadioButton("Relative");
friendFriend = new JRadioButton("Friend of Friend");
ButtonGroup group = new ButtonGroup();
group.add (friend);
group.add (family);
group.add (relative);
group.add (friendFriend);
(I'm not sure if I needed a listner for the RadioButtons or not but my program still seems to "crash" no matter what).
then I had one action listner for the JButton which included all the textfields and radio buttons. But the RadioButton is the issue.
In the action listner I had:
Object source = event.getSource();
if (source == family)
relation1 = true;
else
if (source == friend)
relation2 = true;
else
if(source == relative)
relation3 = true;
else
if(source == friendFriend)
relation4 = true;
Then I made a relation class:
public class Relation {
private boolean arrayFamily, arrayFriend, arrayRelative, arrayFriendFriend;
public Relation(boolean relation1, boolean relation2, boolean relation3,
boolean relation4)
{
this.arrayFamily = relation1;
this.arrayFriend = relation2;
this.arrayRelative = relation3;
this.arrayFriendFriend = relation4;
}
public String relations ()
{
String relationship = null;
if(arrayFamily && !arrayFriend && !arrayRelative && !arrayFriendFriend == true)
{
relationship = "Family";
}
else
if(arrayFriend && !arrayFamily && !arrayRelative &&
!arrayFriendFriend == true)
{
relationship = "Friend";
}
else
if(arrayRelative && !arrayFamily && !arrayFriend &&
!arrayFriendFriend == true)
{
relationship = "Relative";
}
else
if(arrayFriendFriend && !arrayFamily && !arrayFriend &&
!arrayRelative == true)
{
relationship = "Friend of a Friend";
}
return relationship;
}
}
LASTLY back in the action listner, I implementer this class:
Relation relationship = new Relation(relation1, relation2, relation3
, relation4);
String arrayRelation = relationship.relations();
I lastly included arrayRelation in an array but the array worked fine.
My problem is that the output of the array for my RadioButtons keeps reading "null" (most likey because this code: String relationship = null;). I assume this means that none of my if else statements were satisfied and I really dont know why.
Also important to point out is that if I click submit without clicking any radio button (the button stays on "family"), it reads null. If I click a button once it works perfectly reading the string I intended. But if I click another button afterwards and click submit again, the string goes back to "null".
I know its lengthy but I would really appreciate any help because I am lost.
P.S. some parts of my code are repetitive because I was playing around trying to fix the problem.
I suggest you handle your action events separately, for example:
family.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
familyActionPerformed(evt);
}
});
Then implement familyActionPerformed(evt):
private void familyActionPerformed(java.awt.event.ActionEvent evt) {
// every click on family radio button causes the code here to be executed
relation1 = true;
}
Also write an event handler for the button you click, like this:
submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Here test the state of each radio button
relation1 = family.isSelected();
relation2 = friend.isSelected();
relation3 = relative.isSelected();
relation4 = friendFriend.isSelected();
}
MORE EDIT:
Doing what you're doing with NetBeans should be very easy. Here are tutorials that will clear it all up for you:
Tutorial 1
Tutorial 2
I explain the solution again:
Using 'family' button as an example, in your constructor where you have created and initialised your GUI components do this:
JRadioButton family = new JRadioButton();
// do any other thing you want to do to this button and finally..
family.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
familyActionPerformed(evt);
}
});
JButton submit = new JButton("Submit");
submit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
submitActionPerformed(evt);
}
});
Then somewhere create these methods:
private void familyActionPerformed(java.awt.event.ActionEvent evt){
// each time family is selected, you code processes the lines below:
...
}
private void submiteActionPerformed(java.awt.event.ActionEvent evt){
relation1 = family.isSelected();
relation2 = friend.isSelected();
relation3 = relative.isSelected();
relation4 = friendFriend.isSelected();
}
Do something similar for the rest of the RadioButtons.
I think that you're making things way too complex for yourself. If all you want is the String of the JRadioButton pressed, then use the ButtonGroup to get it for you. It can return the ButtonModel of the selected JRadioButton (if any one was selected), and from that you can extract the actionCommand String, although you'll have to remember to set this when you create your JRadioButton.
For example:
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class JRadioExample extends JPanel {
private static final String[] RADIO_TITLES = { "Family", "Friend",
"Relative", "Friend or Relative" };
private ButtonGroup btnGrp = new ButtonGroup();
public JRadioExample() {
for (int i = 0; i < RADIO_TITLES.length; i++) {
JRadioButton rBtn = new JRadioButton(RADIO_TITLES[i]);
rBtn.setActionCommand(RADIO_TITLES[i]); // ***** this is what needs to
// be set
btnGrp.add(rBtn);
add(rBtn);
}
add(new JButton(new BtnAction("Get Chosen Selection")));
}
private class BtnAction extends AbstractAction {
public BtnAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent evt) {
ButtonModel model = btnGrp.getSelection();
if (model != null) {
String actionCommand = model.getActionCommand();
System.out.println("Selected Button: " + actionCommand);
} else {
System.out.println("No Button Selected");
}
}
}
private static void createAndShowGui() {
JRadioExample mainPanel = new JRadioExample();
JFrame frame = new JFrame("JRadioExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I'm making a small game involving a grid of JButtons (MxN) and the main premise is to click on buttonA and then on buttonB, coloring buttonB and adjacent buttons of the same color as buttonB with the color of buttonA. I have made it so you are able to choose 3 possible difficulties. The colors are randomly generated. The main problem is getting the colors to change.
This is the method that I call after selecting the difficulty of the game:
public static void gameMechanics(int m, int n) {
final String[] pickedColour = {""};
final String[] placedColour = {""};
JButton[][] picked = new JButton[m][n];
JButton[][] placed = new JButton[m][n];
picked[m][n].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pickedColour[0] = picked[m][n].getText();
}
});
placed[m][n].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
placedColour[0] = placed[m][n].getText();
}
});
if (pickedColour[0] == "R" && placedColour[0] != "R") {
placed[m][n].setBackground(Color.RED);
placed[m][n].setText("R");
}
else if (pickedColour[0] == "G" && placedColour[0] != "G") {
placed[m][n].setBackground(Color.GREEN);
placed[m][n].setText("G");
}
else if (pickedColour[0] == "B" && placedColour[0] != "B") {
placed[m][n].setBackground(Color.BLUE);
placed[m][n].setText("B");
}
}
I would consider using JPanels and painting them, using a MouseListener instead.
However, if you're set on using JButtons, try this:
button.setBackground(Color.GREEN);
button.setOpaque(true);
Note that this might not work if you're setting the look and feel using UIManager.
Also, you're doing a ton of extra work to map the color to the button - it could get confusing and cause errors down the road. Instead, you might try creating your own class:
class ColoredButton extends JButton {
private static final long serialVersionUID = 3040767030924461426L;
private Color color;
public ColoredButton(Color c) {
this.color = c;
this.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
changeColor();
}
});
}
public void changeColor() {
this.setBackground(this.color);
this.setOpaque(true);
}
}
Now, you can construct a new ColoredButton:
// Now, this button will turn green when clicked
ColoredButton temp = new ColoredButton(Color.GREEN);
I've been searching how to limit my jFrame to open only one each time it's clicked but no success aparently. My code is like this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
login = true;
InserirCliente tela_inserir = new InserirCliente(login);
jDesktopPane1.add(tela_inserir);
tela_inserir.setVisible(true);
}
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
login = false;
InserirCliente tela_inserir = new InserirCliente(login);
jDesktopPane1.add(tela_inserir);
tela_inserir.setVisible(true);
}
And there is a JInternalFrame with:
public InserirCliente(boolean login){
initComponents();
if(login){
jPanel1.setVisible(false);
}
else {
}
}
Pretty simple, just testing it all. But how could it be changed to display only the first one and not more then the first as it is beeing clicked? Are there handles so it receives if there are instances of the JInternalFrame already created?
First, make tela_inserir a public/private variable depending on your need:
private InserirCliente tela_inserir;
Now add the following method to your InserirCliente class:
public Boolean checkVisible(){
if(jPanel1 != null){
return jPanel1.isVisible();
}
return false;
}
Now just check if the inner JPanel is null (Not yet created) and not visible when your buttons are pressed:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//Only show new panel if i is not already visible:
if (tela_inserir == null && tela_inserir.checkVisible() == false){
login = true;
tela_inserir = new InserirCliente(login);
jDesktopPane1.add(tela_inserir);
tela_inserir.setVisible(true);
}
}
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
//Only show new panel if i is not already visible:
if (tela_inserir == null && tela_inserir.checkVisible() == false){
login = false;
InserirCliente tela_inserir = new InserirCliente(login);
jDesktopPane1.add(tela_inserir);
tela_inserir.setVisible(true);
}
}
Is there a way to know if a JButton was clicked consecutively? Consider my code.
public void actionPerformed(ActionEvent arg0) {
String bucky[] = new String[2];
String firstclick = null, secondclick = null;
clicks++;
if (clicks == 1) {
bucky[0] = firstclick;
} else if(clicks == 2) {
bucky[1] = secondclick;
if (bucky[0] == bucky[1]) {
//This JButton was clicked twice in a row.
}
}
This code checks the entire number of times my JButton was clicked and displays the message "This button was clicked twice in a row". What I want is to compare two clicks from that button and see if they come one after the other rather than counting the number of clicks made. Or is there a built-in function that does this?
Just use a field remembering what the last clicked button was:
private JButton lastButtonClicked;
...
someButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (lastButtonClicked == e.getSource()) {
displayError();
}
else {
lastButtonClicked = (JButton) e.getSource();
doSomething();
}
}
});
Of course, you'll have to do the same thing with all the other buttons.
I have a different approach to your problem:
You want to not allow the user to press the same button in some group of buttons twice in a row.
You're solutions so far have tried to check which button was pressed last, and then warn the user if the same button has been pressed in a row.
Perhaps a better solution is to create a construct that simply doesn't allow the user to press the same button twice in a row.
You can create your ButtonGroup like object that selectively disables the last button pressed, and enables all the other buttons.
You would give this class an add(AbstractButton btn) method to allow you to add all the buttons that you wish to behave this way to it. The button would then be added to an ArrayList.
You would give it a single ActionListener that listens to all the buttons. Whenever the actionPerformed method has been pressed, it enables all of the buttons, and then selectively disables the last button pressed.
For instance consider my class below:
public class NoRepeatButtonGroup implements ActionListener {
private List<AbstractButton> btnList = new ArrayList<>();
public void add(AbstractButton btn) {
btnList.add(btn);
btn.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent evt) {
for (AbstractButton btn : btnList) {
btn.setEnabled(true);
}
((AbstractButton) evt.getSource()).setEnabled(false);
}
public void reset() {
for (AbstractButton btn : btnList) {
btn.setEnabled(true);
}
}
}
If you create a single object of this in your class that creates the buttons, and add each button to the object of this class, your code will automatically disable the last button pressed, and re-enable it once another button has been pressed.
You could use it like so:
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
NoRepeatButtonGroup noRepeatButtonGroup = new NoRepeatButtonGroup();
JButton yesButton = new JButton(new YesAction());
noRepeatButtonGroup.add(yesButton);
buttonPanel.add(yesButton);
JButton noButton = new JButton(new NoAction());
noRepeatButtonGroup.add(noButton);
buttonPanel.add(noButton);
JButton maybeButton = new JButton(new MaybeAction());
noRepeatButtonGroup.add(maybeButton);
buttonPanel.add(maybeButton);
For example, here is a proof of concept minimal runnable example:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class NoneInARowBtns {
private static void createAndShowGui() {
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
NoRepeatButtonGroup noRepeatButtonGroup = new NoRepeatButtonGroup();
int buttonCount = 5;
for (int i = 0; i < buttonCount; i++) {
JButton btn = new JButton(new ButtonAction(i + 1));
noRepeatButtonGroup.add(btn);
buttonPanel.add(btn);
}
JOptionPane.showMessageDialog(null, buttonPanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class ButtonAction extends AbstractAction {
public ButtonAction(int i) {
super("Button " + i);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand() + " Pressed");
}
}
class NoRepeatButtonGroup implements ActionListener {
private List<AbstractButton> btnList = new ArrayList<>();
public void add(AbstractButton btn) {
btnList.add(btn);
btn.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent evt) {
for (AbstractButton btn : btnList) {
btn.setEnabled(true);
}
((AbstractButton) evt.getSource()).setEnabled(false);
}
public void reset() {
for (AbstractButton btn : btnList) {
btn.setEnabled(true);
}
}
}
When the above program runs, and when the second button is pressed, you will see that it is disabled:
Then when the 3rd button has been pressed, the 2nd is re-enabled, and the 3rd one is disabled:
And etc for the 4th button....
A global variable arrau of booleans, one for each button, set true on first click, set false or second, sjould do it
I have fully working calculator using java.Can tell me how to add decimal point.I already have the button and the variables are in type double.I just can't make the button work.
I tried to do it myself,but I ended up with error messages every time.
Here is the code:
package oop;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Kalkulator2 extends Applet {
String arg1= "", arg2="";
double ergebnis;
Button zahl[] =new Button[10];
Button funktion[] = new Button[4];
Button ausfuehren;
Button decimalpoint;
char dec='.';
Panel zahlPanel,funktionPanel,ergebnisPanel;
TextField ergebnisFeld = new TextField(5);
int operationArgument;
char operation;
public void init () {
operationArgument= 1; operation =' ';
setLayout(new BorderLayout());
zahlPanel = new Panel();
zahlPanel.setLayout(new GridLayout (4,3));
for (int i=9; i>=0; i--) {
zahl[i] = new Button(String.valueOf(i));
zahl[i].addActionListener(new ButtonZahlen());
zahlPanel.add(zahl[i]);
}
decimalpoint = new Button(String.valueOf(dec)); //decimal point
//decimalpoint.addActionListener(new Button ());
ausfuehren = new Button("=");
ausfuehren.addActionListener(new ButtonAusfuehren()); //zu dem Listener
zahlPanel.add(decimalpoint);
zahlPanel.add(ausfuehren);
add("Center",zahlPanel);
funktionPanel = new Panel();
funktionPanel.setLayout(new GridLayout(4,1));
funktion[0] = new Button("+");
funktion[0].addActionListener(new ButtonOperation());
funktionPanel.add(funktion[0]);
funktion[1] = new Button("-");
funktion[1].addActionListener(new ButtonOperation());
funktionPanel.add(funktion[1]);
funktion[2] = new Button("*");
funktion[2].addActionListener (new ButtonOperation());
funktionPanel.add(funktion[2]);
funktion[3] = new Button("/");
funktion[3].addActionListener (new ButtonOperation());
funktionPanel.add(funktion[3]);
add("East",funktionPanel);
ergebnisPanel = new Panel();
ergebnisPanel.add(ergebnisFeld);
add("North",ergebnisPanel);
}
class ButtonZahlen implements ActionListener{
public void actionPerformed(ActionEvent e) {
switch (operationArgument) {
case 1 : {
arg1+=e.getActionCommand();
ergebnisFeld.setText(arg1);
break;
}
case 2 : {
arg2 +=e.getActionCommand();
ergebnisFeld.setText(arg2);
break;
}
default: { }
}
}
}
class ButtonAusfuehren implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(operation =='+')
ergebnis = new Double(arg1) + new Double(arg2);
else if (operation == '-')
ergebnis = new Double(arg1) - new Double(arg2);
else if(operation =='*')
ergebnis = new Double(arg1) * new Double(arg2);
else if(operation =='/')
ergebnis = new Double(arg1) / new Double(arg2);
ergebnisFeld.setText(String.valueOf(ergebnis));
}
}
class ButtonOperation implements ActionListener{
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("+")) {
operation = '+'; operationArgument = 2;
}
else if(e.getActionCommand().equals("-")) {
operation = '-'; operationArgument = 2;
}
else if(e.getActionCommand().equals("*")) {
operation = '*' ; operationArgument =2;
}
else if(e.getActionCommand().equals("/")) {
operation = '/' ; operationArgument =2;
}
}
}
}
public void paint(Graphics g){ }
}
When the button got clicked, it is trying to create a new button object which doesn't implement an actionListener. Thus it will throw an error saying " what must i do with a new button while i need an object with 'actionPerformed' method " Here is a possible solution;
// create button object
decimalpoint = new Button(".");
// not good : decimalpoint.addActionListener(new Button ());
// event on click
decimalpoint.addActionListener(new YourClassName());
and YourClassName is an instance to handle the button event
class YourClassName implements ActionListener {
public void actionPerformed(ActionEvent e) {
// add decimal point
}
}
I also agree with Andrew Thompson that AWT is not a preferred way to handle your tasks. If your teacher has suggested you to use AWT, then please use Swing. Swing is far better then AWT and should be educated to people who is writing GUI-based java for the first time.
To answer the question, to add a DECIMAL POINT to java code (my example is for GUI NetBeans IDE 8.0.2) I have stumbled across this code. I must admit I have not come across this code having looked for an answer on the net.
private void PointActionPerformed(java.awt.event.ActionEvent evt) {
txtDisplay.setText(txtDisplay.getText()+Point.getText());
}
you can do that simply
specify the button -
Button Decimal;
caste the button you specified in your xml file to (Button)Decimal -
Decimal = findViewById(R.id.the id you gave to the button);
Now set on click listener
Decimal.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
edit.setText(edit.getText().toString() + ".");
}
where edit is the field you want the text to be filled.
I am trying to get a group of JRadioButtons to be navigable using the arrow keys. I was going to implement this manually with KeyListeners, but apparently this behavior is already supposed to work for at least the last 8 years (http://bugs.sun.com/view_bug.do?bug_id=4104452). However, it's not working for me: pressing the arrow keys does nothing. Java version is 7u45 on Windows.
A standalone test case to see what I'm talking about:
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);
}
}
I have tried using different look & feels, different containers, and different layout managers, but it still does not work.
You need to add the right/left (up/down?) keys to the focus traversal policy of each radio button. For example to add the right/left arrow keys:
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 );
Read the section from the Swing tutorial on How to Use the Focus Subsystem for more information.
I believe you can achieve your goal using KeyBindings instead of KeyListeners. In many cases bindings are actually recommended over KeyListeners, as the second ones can generate many problems (frame catching the key activity must be active one etc.)
Thank you everyone for the answers.
I discovered the reason for my confusion. Apparently, when the Sun bug report system says that a bug's status is "Closed" and its "Resolved Date" is "2005-07-19", that doesn't mean the bug is fixed at all. Apparently, it's just logged as a duplicate of some other (newer?) bug. Nearly 16 years since it was first reported it still isn't fixed. Whatever.
The needed behavior is much more subtle than I realized. I experimented in native Windows dialogs in various programs:
Most button-like components: buttons, checkboxes, and radio buttons, implement the arrow keys for focus navigation. In Java this corresponds to the AbstractButton class. (JMenuItem is also a subclass of that, but that has its own distinct arrow key behavior.)
Only radio buttons get selected/checked during this navigation.
Unfocusable (including disabled or invisible) components must be skipped.
Attempting to navigate before the first button in a group or after the last one is inconsistent: on some dialogs it loops from end to end; on others it moves irreversibly onto non-button components; and on yet others it does nothing. I experimented with all these different behaviors and none of them was particularly better than the others.
I implemented a looping behavior below as it felt slightly more fluent. The navigation silently skips past non-AbstractButton components, forming a sort-of separate focus cycle private to buttons. This is dubious but sometimes needed when a set of related checkboxes or radio buttons are mixed with other components. Testing for a common parent component to identify groups would also be a reasonable behavior, but that didn't work in one dialog where I'd used separate components purely for layout reasons (to implement a line break in a FlowLayout).
As suggested I studied up on InputMaps and ActionMaps instead of using a KeyListener. I've always avoided the maps as they seem overcomplicated but I guess I see the advantage of being able to easily override the binding.
This code uses an auxialiary look and feel to install the desired behavior for all AbstractButton components application-wide (which is a nice technique I found out about here). I've tested it with several different dialog boxes and windows and it seems to be okay. If it causes issues I'll update this post.
Call:
ButtonArrowKeyNavigation.install();
once at application startup to install it.
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);
}
}
}
}
Here is my example of JRadioButtons can be navigable using the arrow keys(UP and Down) and modified few codes for you.
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);
}
}
The core implement method is calling requestFocus() on the correct JRadioButton when an arrow key is called. Extra KeyListener for when the Enter key is pressed.
You can use this KeyListener to your program and add more key.
Good luck!