Using Keybinding - java

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:

Related

Why is my program not listening to keyEvents?

I am trying to develop a main menu for a game in java, but my JMenuItems wouldn't listen to the KeyEvents and I don't understand why. Note that I don't want to set any JMenuBars nor JMenus as this program is intended to be a game used with screen readers, so I don't want accessibility roles to be read. Furthermore, adding a menu complicates the access to the elements with the keyboard and I want the focus to start in the first option.
This is my code:
import java.util.Set;
import java.util.HashSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.MenuKeyEvent;
import javax.swing.event.MenuKeyListener;
public class Screen {
public Screen() {
// Accept arrow keys as focus traversal keys
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTrave rsalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,set);
// definition of Menu Items
JMenuItem mi=new JMenuItem("play");
JMenuItem mi2=new JMenuItem("exit");
mi.setFocusable(true);
mi2.setFocusable(true);
// Attempt with MenuKeyListener
mi.addMenuKeyListener(new MenuKeyListener() {
public void menuKeyReleased(MenuKeyEvent e) {
System.out.println("Play released");
}
public void menuKeyTyped(MenuKeyEvent e) {}
public void menuKeyPressed(MenuKeyEvent e) {}
});
// Attempt with ActionListener
mi2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
mi.setVisible(true);
mi2.setVisible(true);
JPanel mp = new JPanel();
JFrame mf = new JFrame("Game");
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mp.add(mi);
mp.add(mi2);
mf.add(mp);
mf.setVisible(true);
}
public static void main(String args[]) {
new Screen();
}
}
I've tried with both ActionListener and MenuKeyListener, with and without the JPanel, changing visibilities... I also tried to use KeyEventDispatcher but I didn't know how to send a KeyEvent to the component that returns KeyboardFocusManager.getFocusOwner().
Please help.
There's a lot to help with in this case. For starters,
public static void main(String args[]) {
new Screen();
}
is wrong. It is not appropriate to perform any operation that alters the Swing layout or presentation on the main thread. Instead do
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Screen();
}
});
}
if you decide that you want to put swing calls into an object's constructor in this way.
Ideally your Screen would be a JFrame but one that is customized to meet your needs. That means you might want to create a new class GamePanel that extends JPanel
public class Screen extends JFrame {
public Screen() {
super("Game"); // to remind us that the JFrame is created
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
pack();
setVisible(true);
}
}
public class GamePanel extends JPanel {
public GamePanel() {
super();
}
}
Now, if you want that panel to listen to keys, you need to add a KeyListener interface. This only gives it the capability to listen, it doesn't make it listen.
public class GamePanel extends JPanel implements KeyListener {
...
public void keyTyped(KeyEvent e) {
System.out.println("KEY TYPED: " + e);
}
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED: " + e);
}
public void keyReleased(KeyEvent e) {
System.out.println("KEY RELEASED: " + e);
}
}
Now you can add your key listener to the Screen or to the GamePanel (it will listen to itself). Whenever the focus is in one of these items, and a key is pressed, the even will be routed to the listener.
public class GamePanel extends JPanel implements KeyListener {
public GamePanel() {
super();
addKeyListener(this);
}
...
}
Ideally, you might want to not combine your key listener with the panel itself, but make it a "Command Processor" of some sort. In that case, remove the KeyListener code from the JPanel and make a completely new CommmandHandler object that implements KeyListener.
As far as Actions go, they are convenience items that pre-configure menu entries with lots of things (icons, acceleration keys, text, callback functions). If you are avoiding menus for whatever reason, you will find that much of their utility in setting up menus is misdirected for your purpose. Effectively, they are configuration entries that configure the MenuItem objects to handle a key (through the KeyListener interface and then dispatch a swing Event object. This provide "better than key" tracking of items through an application as it converts a keyboard letter k to a class ActionEvent which is passed to the registered "action handler" typically a subclass of AbstractAction.
An example of an Action would be
public class MoveLeft extends AbstractAction { // which extends ActionListener
private final GameState gameState;
public MoveLeft(GameState gameState) {
super("move left", new ImageIcon(MoveLeft.class.getResource("/images/moveleft.png"));
putValue("SHORT_DESCRIPTION", "left");
putValue("MNEMONIC_KEY", "l");
this.gameState = gameState;
}
public void actionPerformed(ActionEvent e) {
gamestate.getSelected().moveLeft();
}
}
Assuming you wanted this convenience, you would initialize your CommandHandler with Actions, maybe like so:
public CommandHandler implements KeyListener {
private int actionId;
...
public void addAction(Action action) {
handlers.put(action.getValue("MNEMONIC_KEY")., action);
}
public void keyTyped(KeyEvent e) {
Action action = handlers.get(String.valueOf(e.getKeyChar());
ActionEvent event = new ActionEvent(this, id, action.getValue("NAME"));
action.actionPerformed( event );
}
}
As you can see, the added convenience of having Actions defined for the actions within your game is a balanced by making your components that use them be configured by them (and using them in the KeyListener implementations).
For large projects, the simplicity of having all your actions listed generally makes creating Actions well worth the effort; but, for smaller projects that are mostly using custom components, the added one-time-cost of making the KeyListener components use actions might outweigh the benefits.
Don't use JMenuItem this way, that's not how it's intended to be used
Instead, I'd start with JButton. The following makes use of your focus transversal code, the Action API and the key bindings API
import java.awt.AWTKeyStroke;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set);
Action playAction = new AbstractAction("Play") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("play");
}
};
playAction.putValue(Action.MNEMONIC_KEY, (int)'P');
Action exitAction = new AbstractAction("Exit") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("exit");
}
};
exitAction.putValue(Action.MNEMONIC_KEY, (int)'x');
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "play");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), "exit");
am.put("play", playAction);
am.put("exit", exitAction);
JButton playButton = new JButton(playAction);
JButton exitButton = new JButton(exitAction);
add(playButton, gbc);
add(exitButton, gbc);
}
}
}
Now, you could do something similar with JLabel, but, JLabel isn't focusable by default, nor does it render any kind of focus indication. Instead, I might be tempted to just strip down a JButton so it didn't paint its border or content/background instead

class variable not updating after method call

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.

Binding a key to a JButton [duplicate]

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");

GUI close issue?

I have a program which displays two buttons and changes the image of one of the buttons on roll over. I am getting an error on my
press.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
part, And it looks like this: The method setDefaultCloseOperation(int) is undefined for the type ButtonClass. Even with the exit on close commented out there are more errors, please help.
Main class (with error):
package Buttons;
import javax.swing.JFrame;
public class Main_buttons{
public static void main(String[] args) {
ButtonClass press = new ButtonClass();
press.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
press.setSize(300,200);
press.setVisible(true);
}
}
ButtonClass class:
package Buttons;
import java.awt.FlowLayout; //layout proper
import java.awt.event.ActionListener; //Waits for users action
import java.awt.event.ActionEvent; //Users action
import javax.swing.JFrame; //Window
import javax.swing.JButton; //BUTTON!!!
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane; //Standard dialogue box
public class ButtonClass extends JButton {
private JButton regular;
private JButton custom;
public ButtonClass() { // Constructor
super("The title"); // Title
setLayout(new FlowLayout()); // Default layout
regular = new JButton("Regular Button");
add(regular);
Icon b = new ImageIcon(getClass().getResource("img.png"));
Icon x = new ImageIcon(getClass().getResource("swag.png"));
custom = new JButton("Custom", b);
custom.setRolloverIcon(x); //When you roll over the button that says custom the image will change from b to x
add(custom);
Handlerclass handler = new Handlerclass();
regular.addActionListener(handler);
custom.addActionListener(handler);
}
private class Handlerclass implements ActionListener { // This class is inside the other class
public void actionPerformed(ActionEvent eventvar) { // This will happen
// when button is
// clicked
JOptionPane.showMessageDialog(null, String.format("%s", eventvar.getActionCommand()));//Opens a new window with the name of the button
}
}
}
I have searched everywhere for this problem and found nothing. Please tell me how to resolve this issue about exiting my window.
Thanks!
You're a little confused as you're creating a class that extends JButton, and calling setVisible(true) on it as if it were a top-level window such as a JFrame or JDialog, and that doesn't make sense. Since it isn't a top-level window it also makes sense to not have a default close operation or understand what that means.
I suggest that you call this method only on top-level windows such as on a JFrame or JDialog and the like. As a side recommendation, I usually avoid setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); and instead more often do setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); which gives it a little more flexibility.
Edit: actually, just change your class to extends JFrame not extends JButton.
Make sure your image path to your resources is correct. For example:
that method is defined for JFrame, not JButton. You're calling it on an instance of a class that extends JButton
The JFrame.Exit_on_close must be used in a JFrame, and you are extending from JButton.
To set a JButton to close a JFrame its something like this.
public class MyClass extends JFrame implements ActionListener{
private JButton button = new JButton("Button");
private JPanel panel = new JPanel();
public static void main(String args[]) {
new MyClass();
}
public MyClass() {
setSize(300, 300);
button.addActionListener(this);
panel.add(button);
add(panel);
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
this.dispose();
}
}

How to bind action with any gui interface in java

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");
}
}
});

Categories