Adding global keybinding for JButtons? - java

I have:
for (int i = 0; i <= 9; i++) {
JButton c = new JButton();
c.setText(Integer.toString(i));
ActionListener l = new NumericButtonListener(i);
c.addActionListener(l);
buttonGrid.add(c); }
So basically, some code that creates a grid of numbers. How can I map my pane to allow hitting the appropriate number and trigger my NumericButtonListener?

You can use keyBindings and assign one common Action for the specific key.
Make use of button's doClick() function to generate an Action event and listens to it. You will need to invoke this function on the specific button to which mapped key is pressed. For example:
Action generateClick = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JButton butt = (JButton) e.getSource();
butt.doClick();
}
};

Use keyBinding for each button. See tutorial for KeyBindings
For example add next code in creation:
c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(Integer.toString(i)), "doSomething");
c.getActionMap ().put("doSomething", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(c.getText());
}
});

Related

Java GUI adding buttons with a for loop

Hi i am making a lotto gui where the user picks 4 numbers from a selection of 28. The way i am currently doing it is as follows
private void no1InputButtonActionPerformed(java.awt.event.ActionEvent evt) {
numberSelectionList.add("1");
}
private void no2InputButtonActionPerformed(java.awt.event.ActionEvent evt) {
chosenNumDisplayLabel.setText(chosenNumDisplayLabel.getText()+" 2");
}
private void no3InputButtonActionPerformed(java.awt.event.ActionEvent evt) {
chosenNumDisplayLabel.setText(chosenNumDisplayLabel.getText()+" 3");
}
etc up through the 28 numbers.
Is there a way to add the actions to each button through a for loop
as this seems more logical?
Also is there a way to add each number picked into an array?
Create a single Action that can be shared by all buttons. The Action will then simply get the text of the button and then do some processing.
Check out setText method with panel and button. This example will show you how to:
create a single ActionListener to be shared by each button
"append" the text to the text field instead of replacing the text
use Key Bindings so the user can also just type the number
On each button you can set an action command:
button.setActionCommand("1");
And you can get the value after that using your ActionEvent:
evt.getActionEvent();
More complete:
ActionListener listener = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println(e.getActionCommand()+" clicked");
}
};
int howMuchYouWant = 32;
for(int i = 0; i<howMuchYouWant; i++)
{
JButton button = new JButton(""+(i+1));
button.setActionCommand(""+i);
button.addActionListener(listener);
//add to whatever gui you want here
}

Java how to assign id to button and retrieve them?

I'm getting stuck while building a forum like application which has a vote button.
I have vote up and vote down button for each content which are automatically generated. I want this button to only display the up and down arrow but not any text or label.. how can i find out which button is pressed?
Automated content..
ImageIcon upvote = new ImageIcon(getClass().getResource("vote_up.png"));
ImageIcon downvote = new ImageIcon(getClass().getResource("vote_down.png"));
JButton vote_up = new JButton(upvote);
JButton vote_down = new JButton(downvote);
vote_up.addActionListener(voting);
vote_down.addActionListener(voting);
Action voting = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
//What to do here to find out which button is pressed?
}
};
any help is appreciated.
public void a(){
int crt_cnt = 0;
for(ClassA temp : listofClassA)
{
b(crt_cnt);
crt_cnt++;
}
}
public void b(crt_cnt){
//draw button
}
As from above, I have multiple vote_up and vote_down button created by the b function, how can i differentiate which crt_cnt is the button from?
There are multiple ways you might achieve this
You could...
Simply use the source of the ActionEvent
Action voting = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
if (e.getSource() == vote_up) {
//...
} else if (...) {
//...
}
}
};
This might be okay if you have a reference to the original buttons
You could...
Assign a actionCommand to each button
JButton vote_up = new JButton(upvote);
vote_up.setActionCommand("vote.up");
JButton vote_down = new JButton(downvote);
vote_down .setActionCommand("vote.down");
//...
Action voting = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
if ("vote.up".equals(e.getActionCommand())) {
//...
} else if (...) {
//...
}
}
};
You could...
Take full advantage of the Action API and make indiviual, self contained actions for each button...
public class VoteUpAction extends AbstractAction {
public VoteUpAction() {
putValue(SMALL_ICON, new ImageIcon(getClass().getResource("vote_up.png")));
}
#Override
public void actionPerformed(ActionEvent e) {
// Specific action for up vote
}
}
Then you could simply use
JButton vote_up = new JButton(new VoteUpAction());
//...
Which will configure the button according to the properties of the Action and will trigger it's actionPerformed method when the button is triggered. This way, you know 100% what you should/need to do when the actionPerformed method is called, without any doubts.
Have a closer look at How to Use Actions for more details
You can detect by using the method getSource() of your EventAction
Action voting = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e){
if (e.getSource() == vote_up ) {
// vote up clicked
} else if (e.getSource() == vote_down){
// vote down clicked
}
}
};
hey thanks for all the help and assistance! I've finally got it! I solved it by
assigning a text on the button, +/- for vote up or down, followed by the content id which i required, then change the font size to 0
vote.setText("+"+thistopic.content.get(crt_cnt).get_id());
vote.setFont(heading.getFont().deriveFont(0.0f));
after that i could easily trace which button is pressed by comparing to the
actionEvent.getActionCommand()
which return the text on the button!
I would wrap the JButton similar to this:
JButton createMyButton(final JPanel panel, final String text,
final boolean upOrDown, final int gridx, final int gridy) {
final JButton button = new JButton();
button.setPreferredSize(new Dimension(80, 50));
final GridBagConstraints gbc = Factories.createGridBagConstraints(gridx,
gridy);
panel.add(button, gbc);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
myActionPerformed(text, upOrDown);
}
});
return button;
}
You could use an int instead of the text, if more convenient.

Java: Array of Buttons - get the source

Suppose I have an array of buttons
private JButton[] myButtons = new JButton[5];
for (int i=0; i<5; i++)
{
myButtons[i] = new JButton(Integer.toString(i));
myButtons[i].setSize(50, 50);
panel.add(myButtons[i]);
}
How can I add a listener to these buttons so that when I click on one of them, I know at which array position index it is at?
You kind of don't care, start by adding an ActionListener to the buttons
myButtons[i].addActionListener(this); // Or some other ActionListener
In the actionPeformed method, you can look up which button it is using the ActionEvent#getSource
#Override
public void actionPerformed(ActionEvent evt) {
for (JButton btn : myButtons) {
if (btn.equals(evt.getSource()) {
// Do what ever you need
break;
}
}
}
You can also use the actionCommand property of the JButton
for (int i=0; i<5; i++)
{
myButtons[i] = new JButton(Integer.toString(i));
myButtons[i].setActionCommand("button " + i);
myButtons[i].addActionListener(this);
panel.add(myButtons[i]);
}
And when actionPeformed is called, use ActionEvent#getActionCommand to figure out which button was pressed.
A better idea might be to create a dedicated ActionListener for each button...
public class ButtonActionHandler implements ActionListener {
private final JButton button;
public ButtonActionHandler(JButton button) {
this.button = button;
}
public void actionPerformed(ActionEvent evt) {
// Do what ever you need to do with the button...
}
}
for (int i=0; i<5; i++)
{
myButtons[i] = new JButton(Integer.toString(i));
myButtons[i].addActionListener(new ButtonActionHandler(myButtons[i]));
panel.add(myButtons[i]);
}
Another idea would be to make use of the Action API which would allow you to define a self contained entity which was capable of configuring the button and handling the associated action event by itself. See How to Use Actions for more details
But which you might use will come down to why you need to identify the buttons in the first place.
You can add listener in loop, like below if you implement ActionListener interface with class. For example,
class TestGUI extends JPanel implements ActionListener{
public TestGUI(){
for(int i=0; i< 5; i++){
....
myButtons[i].addActionListener(this);
}
}
or, if you have separate Listener class or method.
myButtons[i].addActionListener(new MyListener());
Than at actionPerformed method you can check with button is clicked,
public void actionPerformed(ActionEvent e){
if("0".equals(e.getActionCommand())){
System.out.println("First button is clicked");
}
... so on
}

Implementing a JMenu with actionPerformed using TextAction

I have a Java Swing interface with multiple JTextArea's and I am implementing an "Edit" menu with various different functions like "Find", "Copy", "Paste", etc. When I click on the JMenuItem I need to know which JTextArea had the focus which is achievable through a TextAction (I haven't gone down the route of a FocusListener and keeping track of what last had the focus):
JMenuItem miFind = new JMenuItem(new EditHandler("Find"));
class EditHandler extends TextAction {
private String s = null;
public EditHandler(String vs) {
super(vs);
s = vs;
}
#Override
public void actionPerformed(ActionEvent e) {
JTextComponent c = getFocusedComponent();
if (s.equals("Find")) {
showFindDialog(c);
}
}
}
This works well and good but I want to be able to disable the "Find" JMenuItem under certain contexts (i.e. if the specific JTextArea is disabled or is empty. I can implement an ActionListener on a JMenu but I can't use getFocusedComponent() to identify what JTextArea has the focus.
According to the Java docs the JMenu constructor takes an Action (like a JMenuItem) and I have tried the following:
mEdit = new JMenu(new EditHandler("Edit"));
However, although the constructor fires, the actionPerformed() event isn't firing within my EditHandler for the JMenu. If I can get it to fire then I was planning to either enable or disable my "Find" JMenuItem.
The best way for you is using of actions map of the text component to place the corresponding action. In this case you can disable it for some text components.
#Override
public void actionPerformed(ActionEvent e) {
JTextComponent c = getFocusedComponent();
if (s.equals("Find")) {
Action a = c.getActionMap().get("Find");
if (a.isEnabled()) {
// generate new event to modify the source (menu item -> text component)
ActionEvent ae = new ActionEvent(c, e.getID(), e.getCommand());
a.actionPerformed(ae);
}
}
}
For each your text component you must provide an action and register it using the action map of the component.
public class UniversalFindAction extends AbstractAction {
public void actionPerformed(ActionEvent ae) {
JTextComponent c = (JTextComponent) ae.getSource();
showFindDialog(c);
}
}
// registering of action
JTextComponent comp = new JTextArea();
comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK), "Find");
comp.getActionMap().put("Find", new UniversalFindAction());
Thanks to #sergiy-medvynskyy I have implemented a Global Focus Listener to keep track of the last JTextArea to be focused:
KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener() {
#Override
public void propertyChange(final PropertyChangeEvent e) {
if (e.getNewValue() instanceof JTextArea) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
tFocused = (JTextArea)e.getNewValue();
}
});
}
}
});
I then check the tFocused object using a MenuListener on my JMenu to verify what JTextArea currently has the focus. I can then call setEnabled() on my respective JMenuItem's depending on the context.

Changing JButton Text or color without final?

Hey all I can change the text of 1 single button easily with "final" but I need to create lots of buttons for a flight booking system, and when the buttons are more, final doesnt work ...
JButton btnBookFlight;
eco = new EconomyClass();
eco.setSeats(5);
for(int i=0;i<20;i++){
btnBookFlight = new JButton("Book" +i);
btnBookFlight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
btnBookFlight.setBackground(Color.RED);
btnBookFlight.setOpaque(true);
btnBookFlight.setText("Clicked");
}
});
btnBookFlight.setBounds(77, 351, 100, 23);
contentPane.add(btnBookFlight);
}
I would be glad if you can suggest me any trick to get over this.I want to change a buttons color or text when it is clicked or maybe some other cool effects when mouse over but for now only text or color will be enough =).Thanks for your time!
Use the source of the ActionEvent in the ActionListener
btnBookFlight.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton)event.getSource();
button.setBackground(Color.RED);
...
}
});
btnBookFlight has to be final for the inner class (ActionListener) to access it.
From JLS 8.1.3
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must be declared final.
If this is not permitted, then the JButton may be accessed using the source component of the ActionEvent itself using getSource.
However, that said, the simplest solution would be to move the JButton declaration within the scope of the for loop and make it final:
for (int i = 0; i < 20; i++) {
final JButton btnBookFlight = new JButton("Book" + i);
btnBookFlight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
btnBookFlight.setBackground(Color.RED);
...
}
});
}
Just avoid using anonymous classes for your action listener and the final constraint will disappear.
What I mean is use:
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton src = (JButton)e.getSource();
// do what you want
}
}

Categories

Resources