This question already has an answer here:
Add key bindings to JButtons that get their actions from action commands?
(1 answer)
Closed 7 years ago.
I have been looking for an answer to attach keybinding to a JButton for many-many hours, and still didn't manage to do it.
I have the following simple program consisting of two classes. I tried using getInputMap() and getActionMap() several ways, but without success. I want it to do the following:
When I press key "1" on the keyboard, it would press JButton btn1, and when I press key "2", it would press JButton btn2 (and 1 or 2 would appear on JLabel consequently).
//class1://
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class event06 extends JFrame {
event06b base = new event06b(this);
JButton btn1 = new JButton("1");
JButton btn2 = new JButton("2");
JLabel label = new JLabel("");
public event06() {
super();
setBounds(300,300, 200,150);
setResizable(true);
setTitle("Button with keybinding");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
btn1.addActionListener(base);
btn2.addActionListener(base);
FlowLayout flo = new FlowLayout(FlowLayout.CENTER);
setLayout(flo);
add(btn1);
add(btn2);
add(label);
setVisible(true);
}
public static void main(String[] args) {
event06 window = new event06();
}
}
//class 2://
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class event06b implements ActionListener {
event06 gui;
public event06b (event06 in) {
gui = in;
}
public void actionPerformed(ActionEvent pressed) {
Object source = pressed.getSource();
if (source == gui.btn1) {gui.label.setText("1");}
else if (source == gui.btn2) {gui.label.setText("2");}
}
}
Update:
(I still don't have a reputation of 15 yet, so I cannot answer my own question, and as far as I know I cannot post codes or long answers in comments, so I'm modifying my question instead).
What I managed to find out is that using KeyListeners only work, if no button has the focus.
See the following example:
//in class 1://
FlowLayout flo = new FlowLayout(FlowLayout.CENTER);
setLayout(flo);
add(btn1);
btn1.setEnabled(false);
btn2.setEnabled(false);
add(btn2);
add(label);
btn1.addActionListener(base);
btn2.addActionListener(base);
addKeyListener(base);
Here, the two buttons, btn1 and btn2 are disabled, so they don't have focus, instead the window is on focus. That's why the KeyListener can work:
public void keyPressed (KeyEvent evt) {
int keycode = evt.getKeyCode();
gui.label.setText(Integer.toString(keycode));
}
public void keyReleased(KeyEvent txt) {}
public void keyTyped(KeyEvent txt) {}
In this case, tha JLabel in class1 shows the keycode of the key that has been pressed. (Note, that you can get the keycode under the keyPressed method, and not under the keyTyped method - this latter is good for getting key character by using getKeyChar. It is also better to use getKeyCode instead of getKeyChar, since specific keys have a keycode, but not a keychar).
For the buttons I use the actionPerformed method:
public void actionPerformed(ActionEvent pressed) {
Object source = pressed.getSource();
if (source == gui.btn1) {gui.label.setText("1");}
else if (source == gui.btn2) {gui.label.setText("2");}
}
Since the buttons are disabled here, this doesn't work. So far, I couldn't connect the keyCode to this actionPerformed method.
In the example presented by Veluria, this actionPerformed method is a part of an AbstractAction, and InputMaps and ActionMaps were used there.
That seems to be the correct answer here, though I get this error, when I'm trying to use that suggestion:
error: identifier expected
YEAH, I FOUND THE SOLUTION!!!:
(first I show you the code, then I will explain what I modified).
//class 1://
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class event06 extends JFrame {
event06b base = new event06b(this);
JButton btn1 = new JButton("1");
JButton btn2 = new JButton("2");
JLabel label = new JLabel("");
public event06() {
super();
setBounds(300,300,250,75);
setResizable(false);
setTitle("Buttons with key");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout(FlowLayout.CENTER);
setLayout(flo);
add(btn1);
btn1.setEnabled(true);
btn2.setEnabled(true);
add(btn2);
add(label);
btn1.addActionListener(base.act);
btn1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('1'), "pressed");
btn1.getActionMap().put("pressed", base.act);
btn2.addActionListener(base.act);
btn2.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('2'), "pressed");
btn2.getActionMap().put("pressed", base.act);
setVisible(true);
}
public static void main(String[] args) {
event06 window = new event06();
}
}
class2:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class event06b {
event06 gui;
public event06b (event06 in) {
gui = in;
}
Action act = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent pressed) {
Object source = pressed.getSource();
if (source == gui.btn1) {gui.label.setText("1");}
else if (source == gui.btn2) {gui.label.setText("2");}
}
};
}
So, I did the following:
- added an ActionListener in class 1 to btn1 and btn2:
btn1.addActionListener(base.act);
I also used the InputMap:
btn1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke('1'), "pressed");
Two things to note here: You have to put that "JComponent.WHEN_IN_FOCUSED_WINDOW" text in round brackets, so that you could get the input from the key even when the button does not have the focus. The other thing is, that when you use getKeyStroke('1'), you have to give a character, so use ' ' instead of " ". (I saw "" being used in many examples).
Then I used the ActionMap, like so:
btn1.getActionMap().put("pressed", base.act);
Please note, that here, and also at the ActionListener, I was referring to the other class by using base.act (base refers to class2, and act refers to the Action inside)
In class2, I put the actionPerformed method inside the AbstractAction, and used #Override. I don't know, why #Override has to be used, because it also works without it.
I'm sorry, if I misinterpreted something and didn't give the right explanation. I'm just a hobby programmer, having no education in computer science. But I hope, that this question and the provided answer might bring help to many others being in the same boat.
Here's one way to do it:
Action action = new AbstractAction("1") {
#Override
public void actionPerformed(ActionEvent e) {
label.setText("1");
}
};
action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("1"));
btn1.setAction(action);
btn1.getActionMap().put("setOneAction", action);
btn1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
(KeyStroke) action.getValue(Action.ACCELERATOR_KEY), "setOneAction");
Related
I am quite new to Java and only after researching and googling and reading many answers, I am posting this. I am kinda lost. A little guidance would be of great help. The following is a method from a class that implements the "ActionListener" interface. What I am trying to do is this: There is a button which one clicked should open a new window with two options in the form of two Radio Buttons. I need to know the Radio Button which was selected for further use in my code. I declared, the "scoreOption" variable as a class variable and static, and then attempt to update it in the "actionPerformed" abstract method. But when I refer to it (after the method call), the value stays the same - null, or whatever I set it to initially. Here is the code:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class StartEvents implements ActionListener {
StartPanel startingPanel;
static String scoreOption;
public StartEvents(StartPanel startPanel) {
startingPanel = startPanel;
}
// Scoring System Window - 1
public void scoringSystem() {
startingPanel.scoringSystem.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Panel scoringSystemPanel = new Panel();
JFrame scoreSystemFrame = scoringSystemPanel.frame(150, 250, "Scoring System", 2, true);
JPanel scoreSystemPanel = scoringSystemPanel.panel(Color.lightGray);
JButton confirmSelection = scoringSystemPanel.button(40, 20, "Confirm");
JRadioButton scoreSystem1 = scoringSystemPanel.radioButton("Option 1: Same Points Per Hit");
scoreSystem1.setActionCommand("Option 1");
JRadioButton scoreSystem2 = scoringSystemPanel.radioButton("Option 2: Unique Points Per Hit");
scoreSystem2.setActionCommand("Option 2");
ButtonGroup scoreSys = new ButtonGroup();
scoreSys.add(scoreSystem1);
scoreSys.add(scoreSystem2);
scoreSystemFrame.getContentPane().add(scoreSystemPanel);
scoreSystemPanel.add(scoreSystem1);
scoreSystemPanel.add(scoreSystem2);
scoreSystemPanel.add(confirmSelection);
// Get Selection Event
// Option 1
scoreSystem1.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
if (scoreSystem1.isSelected()) {
scoreOption = scoreSystem1.getActionCommand();
}
}
});
// Option 2
scoreSystem2.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
if (scoreSystem2.isSelected()) {
scoreOption = scoreSystem2.getActionCommand();
}
}
});
// Confirm Event
confirmSelection.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
scoreSystemFrame.dispose();
}
});
}
});
}
Main Game Class where the method scoringsystem is called.
import java.util.ArrayList;
public class Game {
public static void main(String[] args) {
StartPanel startingPanel = new StartPanel();
startingPanel.makeStartPanel();
StartEvents starter = new StartEvents(startingPanel);
starter.rulesButton();
starter.exitButton();
starter.highScoresButton();
ArrayList<Integer> dimensions = starter.boardSizeSelector();
// Problem Zone
System.out.println(StartEvents.scoreOption);
starter.scoringSystem();
System.out.println(StartEvents.scoreOption);
// The two values of scoreOption should be different
String[] playPanelDetails = {"970", "Player 1", "450"};
// Final Start of the Game
starter.startGameButton(playPanelDetails, dimensions);
}
}
Furthermore, could you please let me know regarding the following questions:
Implementing "ActionListener" within another "ActionListener" is recommended? Good Practice?
Can there only be one declaration of the "actionPerformed" method or can it be overloaded too?
Is it possible to get a return value from "actionPerformed" method?
I would be really grateful if even some hints could be provided. I really tried a lot and only then posting it here. Thank you very much in advance.
Small Edit: When I "System.out.println" the "actioncommand" there itself, it does work perfectly, printing in the console. But not when I try to update the class variable and then try to print it after the method call. Dunno if this helps.
JFrames are not modal -- you create one and display it, it does not block the code flow, and so you are extracting the value of scoreOption right as the JFrame is being displayed and before the user has had any chance to change it. You need to use a modal dialog such as a JDialog that is created as a modal dialog or use a JOptionPane (which is actually just a modal JDialog under the hood). This will block the flow of code so that you extract the data only after it has been changed by the user.
An example that proves the point:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FooGui01 extends JPanel {
private String frameTest = "";
private String dialogTest = "";
private JFrame mainFrame = new JFrame("Main GUI");
private JFrame subFrame;
private JDialog dialog;
public FooGui01() {
JButton showFrameBtn = new JButton("Show JFrame");
showFrameBtn.addActionListener(e -> {
changeTest1WithJFrame();
System.out.println("frameTest: " + frameTest);
});
JButton showDialogBtn = new JButton("Show JDialog");
showDialogBtn.addActionListener(e -> {
changeTest2WithModalDialog();
System.out.println("dialogTest: " + dialogTest);
});
JPanel panel = new JPanel();
panel.add(showDialogBtn);
panel.add(showFrameBtn);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.add(panel);
mainFrame.pack();
mainFrame.setLocationByPlatform(true);
mainFrame.setVisible(true);
}
public void changeTest1WithJFrame() {
if (subFrame == null) {
subFrame = new JFrame("Frame");
JButton button = new JButton("Press me");
button.addActionListener(e -> {
frameTest = "Hello World and frameTest";
subFrame.setVisible(false);
});
JPanel panel = new JPanel();
panel.add(button);
subFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
subFrame.add(panel);
subFrame.pack();
subFrame.setLocationByPlatform(true);
}
subFrame.setVisible(true);
}
public void changeTest2WithModalDialog() {
if (dialog == null) {
dialog = new JDialog(mainFrame, "Dialog", Dialog.ModalityType.APPLICATION_MODAL);
JButton button = new JButton("Press me");
button.addActionListener(e -> {
dialogTest = "Hello World and dialogTest";
dialog.setVisible(false);
});
JPanel panel = new JPanel();
panel.add(button);
dialog.add(panel);
dialog.pack();
dialog.setLocationByPlatform(true);
}
dialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new FooGui01());
}
}
If you run the code, when you show the sub JFrame, the test text is displayed immediately in the console before the dialog has been dealt with. If you press the button to show the dialog, the test text display is delayed until after the button has been pushed, changing the text.
Pressing the frame button twice will finally show the correct text since the text was set by the first time it was displayed.
A JDialig is just like a JFrame. That is you add components to it like you do any frame.
The difference is that you can make a JDialog modal. This means that when you use:
dialog.setVisible(true);
System.out.println("here");
The code after the setVisible(...) statement will not be executed until the dialog is closed. It also means you can't click on the parent JFrame until the dialog is closed.
An easy way to create a modal JDialog is to use a JOptionPane. It has some predefined methods that make prompting for user input easy.
For example in your case you could do something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
private int scoringOption = -1;
public SSCCE()
{
JButton button = new JButton("Change Points Option");
add(button);
button.addActionListener((e) -> displayOptionDialog());
}
private void displayOptionDialog()
{
Window window = SwingUtilities.windowForComponent( this );
// Custom button text
Object[] options = {"Option 1: Same Points Per Hit", "Option 2: Unique Points Per Hit"};
scoringOption = JOptionPane.showOptionDialog(
window,
"Select your scoring option:",
"Scoring Option",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
null);
System.out.println( scoringOption );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
The above is also an example of an "MRE". The code is simple and contained in a single class that you can copy/paste/compile and test.
Read the section from the Swing tutorial on How to Use Dialogs for more examples of using a JOptionPane.
If you really want to use radio buttons, then you can create a panel with the radio buttons and display them on the option pane using the showConfirmDialog(...) method. When the dialog closes you would then need to get the action command from the ButtonModel of the ButtonGroup.
See: how to set & manage the layout of JOptionPane for a basic example of this approach to get you started.
I have run into the issue of not being able to collect the real text from my JTextField when calling getText(). I have provided a simplified version of the code I was running that includes only the aspects of the program to where it will reproduce the issue. I am attempting to collect the text from the JTextField upon the clicking of the button b.
The correct value returned from getText() should be what ever was input, but instead here it simply returns an empty String. In testing I have found that initializing the TJextField with a String will have it return that String no matter what, even if it is changed before pressing the button. and if one uses setText() inside of init() for example, it will continue to return an empty String.
public class TopClass {
public static void main(String[] args){
BottomClass bottom = new BottomClass();
bottom.init();
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class BottomClass implements ActionListener{
JFrame frame = new JFrame();
JTextField tf = new JTextField();
JButton b = new JButton("BUTTON");
public void init(){
BottomClass bc = new BottomClass();
b.addActionListener((ActionListener) bc);
frame.add(tf, BorderLayout.NORTH);
frame.add(b, BorderLayout.SOUTH);
frame.setSize(100,100);
frame.show();
}
public void actionPerformed(ActionEvent e) {
System.out.println("TEXT: "+tf.getText());
}
}
Several things aren't clean at all in this code, so I just rewrote most of BottomClass.
You can do it by implementing ActionListener, but BottomClass is more than just an EventListener, so (in the name of realistic responsibility) I just added a new instance of ActionListener to the component that needs it (JButton)
You create an instance bc of BottomClass inside the method init() IN BottomClass. This makes no sense at all and was simply deleted.
You initialize your components at the wrong point. They should either be initialized in the constructor, or inside your nice and fitting init() method. I'm 99% sure that the placement of your initializations is what caused your trouble.
I'm not sure how much of an error this is, but when adding your components you specify BorderLayout constraints despite never defining BorderLayout as the LayoutManager to use. I added the setLayout(new BorderLayout()) call.
It's usually good form to have a constructor, especially if you have a different class calling it. Even if it's empty, a written empty constructor is more easily readable and understandable than an invisible one.
All that said, here's a working version of BottomClass, TopClass doesn't need any adjustments:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class BottomClass
{
JFrame frame;
JTextField tf;
JButton b;
public BottomClass()
{
// Empty constructor
}
public void init()
{
frame = new JFrame();
frame.setLayout(new BorderLayout());
tf = new JTextField();
b = new JButton("Button");
b.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println("TEXT: " + tf.getText());
}
});
frame.add(tf, BorderLayout.NORTH);
frame.add(b, BorderLayout.SOUTH);
frame.setSize(100, 100);
frame.setVisible(true);
}
}
I have created a small app that uses JButtons to increment numbers. The buttons aren't supposed to be clickable but rather be activated by keyboard (ie the numbers in the textField increase with the keyboard pushed and not by using a mouse to click the button). My issue is that when the app is first launched, the keyboard doesn't do anything until I first click one of the buttons - even though clicking the button doesn't progress anything. I have tried to make one of the buttons requestFocusInWindow() thinking that if it was already focused on, the the keys would work, but that hasn't seemed to work whether I put it in my main method or controller class. I've tried to figure out if I need to do a KeyboardFocusManager or a addFocusListener() (but I don't want something always happening if a button gains/loses focus). I've tried so many things my head is spinning, trying to add either to my main method with frame or my controller class. Below is what my current code is:
Class with Main
import javax.swing.JFrame;
public class Count {
public static void main(String[] args) {
CountController frame = new CountController();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(560, 150);
frame.setVisible(true);
//I've tried to add the button and requestFocusInWindow here
//as well as tried a frame.addWindowFocusListener
}
} // end class
Controller Class
imports ...
public class CountController extends JFrame implements KeyListener {
private JLabel ...
private JTextField ...
private JButton ....
int ...
// no-argument constructor
public CountController() {
super("Title");
setLayout(null); // position GUI components explicitly
//set up JLabels in following manner
label = new JLabel("some label");
label.setBounds(47, 5, 45, 25);
label.setHorizontalAlignment(JLabel.CENTER);
add(label);
//set up JTextFields in following manner
textField = new JTextField("0");
textField.setBounds(47, 30, 45, 25);
textField.setHorizontalAlignment(JTextField.CENTER);
textField.setBackground(Color.WHITE);
textField.setEditable(false);
add(textField);
//set up JButtons in the following manner
button = new JButton("some text");
button.setBounds(15, 70, 110, 25);
button.setBackground(Color.WHITE);
add(button);
button.addKeyListener(this);
//I've tried adding requestFocusInWindow() here as well
} // end constructor
//begin KeyListener stuff
#Override
public void keyPressed(KeyEvent event){
int keyCode = event.getKeyCode();
switch(keyCode){
case #: //# is ASCII #
do some things;
call a method();
break;
}
}
#Override
public void keyReleased(KeyEvent event){
button.setBackground(Color.WHITE);
}
#Override
public void keyTyped(KeyEvent event){
// nothing but this is needed for implementing KeyListener
}
//List of methods that are called from switch
...
//I've tried to add a public void initialize(){}
}//end CountController class
I would appreciate any input on getting this to work so that I don't have to first click a button before my keys work.
Thanks!
In order for the listener to trigger an event, the component it is registered to must first BE focused AND have focus. Use the key bindings API instead.
The following uses JComponent.WHEN_IN_FOCUSED_WINDOW to define the context under which the key events will be generated. In this configuration, it won't matter what has focus, the events will still be generated, so long as the window is currently focused
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
public class Count {
public static void main(String[] args) {
CountController frame = new CountController();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(560, 150);
frame.setVisible(true);
//I've tried to add the button and requestFocusInWindow here
//as well as tried a frame.addWindowFocusListener
}
public static class CountController extends JFrame {
// no-argument constructor
public CountController() {
super("Title");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
//set up JLabels in following manner
JLabel label = new JLabel("some label");
label.setHorizontalAlignment(JLabel.CENTER);
add(label, gbc);
//set up JTextFields in following manner
JTextField textField = new JTextField("0", 20);
textField.setHorizontalAlignment(JTextField.CENTER);
textField.setBackground(Color.WHITE);
textField.setEditable(false);
add(textField, gbc);
//set up JButtons in the following manner
JButton button = new JButton("some text");
add(button, gbc);
InputMap im = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = button.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_3, KeyEvent.SHIFT_DOWN_MASK), "Pressed.#");
am.put("Pressed.#", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
textField.setText(textField.getText() + "#");
}
});
} // end constructor
}//end CountController class
} // end class
Although I'd register the bindings against the parent container and not the buttons, but that's just me.
And, reasons for not using null layouts ... this is what your original code looks like on my PC
Although it's not quite clear to me what your code should accomplish, your problem is that you addKeyListener(this) to the button but your button doesn't have the focus and the key doesn't do anything when pressed. Try adding the KeyListener() to some other GUI component, like the textfield for example, since it's the first component and has the focus on start(from the code you've provided), and see if it works.
I am new to java.
Can someone tell me how to add ActionListener with my code?
Do I need to make a different function for it? I want to retrieve value from textfield which is entered by user. I am getting error.
Please explain me the background logic behind when to make function of methods that already exists in java or can we use them directly? My code is:
Also tell me how by pressing ENTER I can get value attached with text field in string?
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComboBox;
import javax.swing.JButton;
import javax.swing.*;
import javax.swing.JList;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Clientgui
{
public static void main(String[] args)
{
JFrame guiFrame=new JFrame();
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setTitle("Client GUI");
guiFrame.setSize(30,30);
guiFrame.setLocationRelativeTo(null);
final JPanel comboPanel = new JPanel();
JLabel Msg = new JLabel("Type Message");
JTextField textbox=new JTextField(10);
comboPanel.add(Msg);
comboPanel.add(textbox);
textbox.addActionListener(this);
String text = textbox.getText();
//textArea.append(text + newline);
//textbox.selectAll();
textbox.setText("Enter message here");
//final JPanel comboPanel1 = new JPanel();
//JLabel listLb2 = new JLabel("Connect");
//comboPanel.add(listLb2 );
JButton connect=new JButton("Connect");
guiFrame.add(comboPanel,BorderLayout.NORTH);
guiFrame.add(connect,BorderLayout.SOUTH);
guiFrame.setVisible(true);
}
}
You need an instance of something that implements ActionListener, you are getting a compilation error here -
textbox.addActionListener(this); // <-- no instance "this".
// You may have new Clientgui(), but
// Clientgui does not implement ActionListener.
As mentioned by Elliott Frisch You can add the Action to the instance of something that implements ActionListener which you can achieve in two way
textbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Write your action here.
}
});
OR
public class Clientgui implements ActionListener{
// content of class goes here
textbox.addActionListener(this);
// content of class goes here
}
In order to bind the enter key with your text box you should implements KeyListener
textbo.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
System.out.println("ENTER key pressed");
}
}
});
I'm doing some very basic coding, just trying to learn the basic concepts behind keybinding. It all seems very straightforward but there's something wrong with my logic or structure that is keeping my code from executing the way I want it to.
Here is my code
public class Board {
ButtonListener buttonlistener;
EnterAction enterAction;
public Board(){
JFrame skeleton = new JFrame();
skeleton.setDefaultCloseOperation(EXIT_ON_CLOSE);
skeleton.setVisible(true);
skeleton.setSize(400, 400);
buttonlistener = new ButtonListener();
enterAction = new EnterAction();
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
JButton button = new JButton("button");
button.addActionListener(buttonlistener);
panel.add(button);
skeleton.add(panel);
panel.getInputMap().put(KeyStroke.getKeyStroke("s"), "doEnterAction");
panel.getActionMap().put("doEnterAction", enterAction);
}
public class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("button pressed");
}
}
public class EnterAction extends AbstractAction{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("enter pressed");
}
}
public static void main(String[] args){
new Board();
}
So, it should be pretty simple. As you can see I'm just trying to make it print out "enter pressed" whenever you press enter, but it isn't printing out anything (unless you click the button also shown in the code above). Also, in eclipse, the EnterAction class is underlined in yellow, I think it may not be being called right, but I don't know why it wouldn't be.
Any help is appreciated, thanks.
Change
panel.getInputMap().put(KeyStroke.getKeyStroke("s"), "doEnterAction");
To
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "doEnterAction");
Also
skeleton.setDefaultCloseOperation(EXIT_ON_CLOSE);
the parameter must be JFrame.EXIT_ON_CLOSE or just put number 3.
The immediate issue I can see is with the following statement
panel.getInputMap().put(KeyStroke.getKeyStroke("s"), "doEnterAction");
KeyStroke.getKeyStroke("s") is going to return null. The requirements for the String passed to this method are very particular and not well documented (IMHO).
You could use KeyStroke.getKeyStroke("S") instead, but I prefer to use KeyStroke.getKeyStroke(KeyEvent.VK_S, 0) as there is no chance of ambiguity in the statement.
I would also recommend that you define the focus boundaries as well for the input map...
Instead of panel.getInputMap(), try using panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) to ensure that the key event will be triggered if the window is focused
Take a look at JComponent#getInputMap for more details.
If you haven't already done so, you should also take a look at How to use Key Bindings
I think Azad and MadProgrammer are correct, I only had to make one more simple change in addition to what they recommended to get the program running. I have numbered the three items for you as a comment in the code: (copy and paste and you are good to go).
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Board {
ButtonListener buttonlistener;
EnterAction enterAction;
public Board() {
JFrame skeleton = new JFrame();
//Change #1 below
skeleton.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
skeleton.setVisible(true);
skeleton.setSize(400, 400);
buttonlistener = new ButtonListener();
enterAction = new EnterAction();
JPanel panel = new JPanel();
panel.setBackground(Color.BLACK);
JButton button = new JButton("button");
button.addActionListener(buttonlistener);
panel.add(button);
skeleton.add(panel);
//Change #2 below
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("S"), "doEnterAction");
panel.getActionMap().put("doEnterAction", (Action) enterAction);
}
public class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("button pressed");
}
}
public class EnterAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("enter pressed");
}
}
public static void main(String[] args) {
new Board();
}
//Change #3 below
}
here is the screenshot: