Keybinding not calling AbstractAction - java

I am making a game where the user has to press keys to move around. I am using keybindings but they are not working. The keybindings are supposed to call the Wp class and print "W pressed", but nothing happens. Here's the code:
public class SO extends JFrame {
public static void main(String[] args) {
new SO();
}
C c;
public SO(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500, 500);
c=new C();
c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "wp");
c.getActionMap().put("wp", new Wp());
this.setVisible(true);
}
private class C extends JComponent {
public void paint(Graphics g){}
}
private class Wp extends AbstractAction {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("W pressed");
}
}
}

Use Action to call like component.getActionMap().put("doSomething", anAction);
Refer Key Binding for more information. Below is a sample code I have referred in another Stackoverflow Question reference link SO Ref link
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonBinding {
private JPanel contentPane;
private JTextField tField;
private JButton button;
private KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
private Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Action Performed");
contentPane.setBackground(Color.BLUE);
}
};
private MouseAdapter mouseActions = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
System.out.println("Mouse Entered");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "enter");
button.getActionMap().put("enter", action);
}
#Override
public void mouseExited(MouseEvent me) {
System.out.println("Mouse Exited");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "none");
contentPane.setBackground(Color.RED);
}
};
private void displayGUI() {
JFrame frame = new JFrame("Button Binding Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
tField = new JTextField(10);
button = new JButton("Click Me");
button.addMouseListener(mouseActions);
contentPane.add(tField);
contentPane.add(button);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ButtonBinding().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}

Related

JButton with both ActionListener / MouseListener

Is it possible to create a Jbutton with both an ActionListener and MouseListener
Meaning so i create a button and then when i press it ( throught actionListener) it changes the frame so that AFTER then button was pressed i can press anywhere on the frame and MouseListener would in use.
JButton button = new JButton();//Creates Button
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Insert MouseListener
//Then do something with mouseListener
}
});
Heres the curent code: however they're now in sync when i try to click the button and i cannot call mouseListener a 2nd time
JButton button2 = new JButton("Click");
button2.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("You clicked the button");
newCube.stopCube();
}
});
button2.addMouseListener(new java.awt.event.MouseAdapter()
{
public void mousePressed(java.awt.event.MouseEvent evt)
{
double x = evt.getX();
double y = evt.getY();
newCube.setCube(x,y);
}
});
If you want to move something by clicking on it, you can use a mouse listener on that node directly, instead of using it on the button.
To add both the action listener and a mouse listener on a button, you can use the addActionListener and addMouseListener methods on the button.
Look at the api for information about these methods... http://docs.oracle.com/javase/7/docs/api/javax/swing/JButton.html
If I understood you correctly, this sample might help you (add this to your own ActionListener)
#Override
public void actionPerformed(ActionEvent e) {
((JButton)e.getSource()).addMouseListener(yourMouseListener);
}
I tried this, it works.
Here is example with JToggleButton which add/remove MouseListener to JFrame.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
public class Example extends JFrame {
private MouseAdapter mouseListener;
public Example(){
init();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private void init() {
mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
System.out.println("clicked");
}
};
setLayout(new FlowLayout());
JToggleButton b = new JToggleButton("add listener");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(((JToggleButton)e.getSource()).isSelected()){
Example.this.addMouseListener(mouseListener);
((JToggleButton)e.getSource()).setText("remove listener");
} else {
Example.this.removeMouseListener(mouseListener);
((JToggleButton)e.getSource()).setText("add listener");
}
}
});
add(b);
}
public static void main(String... s){
new Example();
}
}
EDIT: examle with JButton:
public class Example extends JFrame {
private MouseAdapter mouseListener;
public Example(){
init();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private void init() {
mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
System.out.println("clicked");
}
};
setLayout(new FlowLayout());
JButton b = new JButton("add listener");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(((JButton)e.getSource()).getText().equals("add listener")){
Example.this.addMouseListener(mouseListener);
((JButton)e.getSource()).setText("remove listener");
} else {
Example.this.removeMouseListener(mouseListener);
((JButton)e.getSource()).setText("add listener");
}
}
});
add(b);
}
public static void main(String... s){
new Example();
}
}
What you want to do is still not clear to me. Though this can help you. It will add a mouse listner to the component when the start button is clicked and remove the mouse listner when stop button is clicked. Thus you can stop the two listeners from working in sync..
JButton startButton = new JButton();
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Add MouseListener to move the component
}
});
JButton stopButton = new JButton();
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Remove the MouseListener
}
});

Java JTextArea KeyListener

When I pressed the ENTER my JTextArea starts a new row and I only want do to the doClick() method nothing else.
How should I do that?
textarea.addKeyListener(new KeyListener(){
#Override
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
button.doClick();
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});
Use .consume():
Consumes this event so that it will not be processed in the default
manner by the source which originated it.
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
e.consume();
button.doClick();
}
}
Documentation
You should use KeyBindings with any JTextComponent in question. KeyListeners are way too low level from Swing's perspective. You are using the concept which was related to AWT, Swing uses KeyBindings to do the same task with more efficiency and provides desired results :-)
A small program for your help :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class KeyBindingExample {
private static final String key = "ENTER";
private KeyStroke keyStroke;
private JButton button;
private JTextArea textArea;
private Action wrapper = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
button.doClick();
}
};
private void displayGUI() {
JFrame frame = new JFrame("Key Binding Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new BorderLayout(5, 5));
textArea = new JTextArea(10, 10);
keyStroke = KeyStroke.getKeyStroke(key);
Object actionKey = textArea.getInputMap(
JComponent.WHEN_FOCUSED).get(keyStroke);
textArea.getActionMap().put(actionKey, wrapper);
button = new JButton("Click Me!");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.format("Button Clicked :-)%n");
}
});
contentPane.add(textArea, BorderLayout.CENTER);
contentPane.add(button, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new KeyBindingExample().displayGUI();
}
};
EventQueue.invokeLater(r);
}
}

How to add KeyListener to JComponent when mouse is entered?

I have created custom button class which extends JComponent and want to add KeyListener on mouseEntered event (and later remove on mouseExited). So my goal is - when the mouse enters this JComponent - then if I press Enter - some code will be executed, related to only this button. How can I do that?
Use Key Bindings instead of KeyListeners, since the latter is way to low level for Swing. Just bring your mouse over the JButton, and then press ENTER, then take your mouse outside the bounds of the JButton and try pressing ENTER again. Have a look at this example and see if this is what you wanted :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonBinding {
private JPanel contentPane;
private JTextField tField;
private JButton button;
private KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
private Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Action Performed");
contentPane.setBackground(Color.BLUE);
}
};
private MouseAdapter mouseActions = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
System.out.println("Mouse Entered");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "enter");
button.getActionMap().put("enter", action);
}
#Override
public void mouseExited(MouseEvent me) {
System.out.println("Mouse Exited");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "none");
contentPane.setBackground(Color.RED);
}
};
private void displayGUI() {
JFrame frame = new JFrame("Button Binding Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
tField = new JTextField(10);
button = new JButton("Click Me");
button.addMouseListener(mouseActions);
contentPane.add(tField);
contentPane.add(button);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ButtonBinding().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}

Close a swing Dialog after done operations

I have a jdialog and want close it on confirmation after that store the data of a text box... now I have no problem to store the data from the box but,
How can I close this dialog after the operation???
Seems a simple thing but I haven't found the solution.
public class test extends JDialog {
private final JPanel contentPanel = new JPanel();
public test() {
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setLayout(new FlowLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
try{
int x=Integer.parseInt(textField.getText());
saver.saveN(x);
}catch(Exception ecc){
JOptionPane.showMessageDialog(Test.this,"error");
}
}
});
}
}
}
}
Either use Window#dispose or Window#setVisible(false).
if you use this dialog only once time then there is same to use dispose() as setVisible(false)
in the case that you invoke this method more than once time, then you can use HIDE_ON_CLOSE
or setVisible(false), better would be re_use this JDialog
EDIT
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class Test {
private static final long serialVersionUID = 1L;
private JDialog dialog = new JDialog();
private final JPanel contentPanel = new JPanel();
private Timer timer1;
private JButton killkButton = new JButton("Kill JDialog");
public Test() {
contentPanel.setLayout(new FlowLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
JPanel buttonPane = new JPanel();
JButton okButton = new JButton("OK");
okButton.setActionCommand("OK");
buttonPane.add(okButton);
killkButton.setActionCommand("Kill JDialog");
buttonPane.add(killkButton);
dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
dialog.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
startTimer();
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
});
dialog.setLayout(new BorderLayout());
dialog.getRootPane().setDefaultButton(okButton);
dialog.add(buttonPane, BorderLayout.SOUTH);
dialog.add(contentPanel, BorderLayout.CENTER);
dialog.pack();
dialog.setLocation(100, 100);
dialog.setVisible(true);
setKeyBindings();
}
private void setKeyBindings() {
killkButton.getInputMap(
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke("ENTER"), "clickENTER");
killkButton.getActionMap().put("clickENTER", new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
}
private void startTimer() {
timer1 = new Timer(1000, new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
dialog.setVisible(true);
}
});
}
});
timer1.setDelay(500);
timer1.setRepeats(false);
timer1.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test test = new Test();
}
});
}
}
If you plan to use a jDialog again with all the field values and component states left the same when you close it, use setVisible(false).
In any other case, call dispose(), to avoid the jDialog remaining in the memory when it is no longer required.

show two dialogs on top of each other using java swing

i have a situation where i show a dialog where user has to fill some menus and then press OK. It works fine, but now i have another button on this dialog that if user wants to add some certain value, i want another dialog to popup where user fills the additional value and while pressing ok, this dialog disappears and user comes back to the main dialog.
I have tried this, but every time i call the new dialog, the focus does not go away from the main dialog, how can i do such a task.
Is there any relevant example or what is the proper way of doing such things.
EDIT:
public static class EdgeMenu extends JPopupMenu {
// private JFrame frame;
public MyMenu(final JFrame frame) {
super("My Menu");
// this.frame = frame;
this.addSeparator();
this.add(new EdgePropItem(frame));
}
}
//this shows the first dialog, another class because i have some other
//functions to be performed here
public static class EdgePropItem extends JMenuItem{
//...
public EdgePropItem(final JFrame frame) {
super("Edit Properties");
this.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
EdgePropertyDialog dialog = new EdgePropertyDialog(frame, edge);
dialog.setVisible(true);
}
});
}
}
and now in other dialog, in the button even listener i am trying to call another dialog:
private void newDialogHandler(java.awt.event.ActionEvent evt) {
MyNewDialog rdialog = new MyNewDialog(edge);
rdialog.setVisible(true);
}
It appears fine, but the previous dialog, does not leave the focus, and it goes away only if i press finish/done on that dialog, what i want is the new dialog to come in focus, while pressing ok on here, focus should come back to the old main dialog, but it is not working?
maybe this code could be demonstate your issues,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SuperConstructor extends JFrame {
private static final long serialVersionUID = 1L;
public SuperConstructor() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300, 300));
setTitle("Super constructor");
Container cp = getContentPane();
JButton b = new JButton("Show dialog");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
FirstDialog firstDialog = new FirstDialog(SuperConstructor.this);
}
});
cp.add(b, BorderLayout.SOUTH);
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.exit(0);
}
});
add(bClose, BorderLayout.NORTH);
pack();
setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SuperConstructor superConstructor = new SuperConstructor();
}
});
}
private class FirstDialog extends JDialog {
private static final long serialVersionUID = 1L;
FirstDialog(final Frame parent) {
super(parent, "FirstDialog");
setPreferredSize(new Dimension(200, 200));
setLocationRelativeTo(parent);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
JButton bNext = new JButton("Show next dialog");
bNext.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
SecondDialog secondDialog = new SecondDialog(parent, false);
}
});
add(bNext, BorderLayout.NORTH);
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
add(bClose, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}
private int i;
private class SecondDialog extends JDialog {
private static final long serialVersionUID = 1L;
SecondDialog(final Frame parent, boolean modal) {
//super(parent); // < --- Makes this dialog
//unfocusable as long as FirstDialog is visible
setPreferredSize(new Dimension(200, 200));
setLocation(300, 50);
setModal(modal);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setTitle("SecondDialog " + (i++));
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
add(bClose, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}
}
You can achieve this as follows:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;
public class MultipleDialogs
{
public MultipleDialogs()
{
JButton btnOpen = new JButton("Open another dialog!");
btnOpen.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JOptionPane.showMessageDialog(null, "This is the second dialog!");
}
});
Object[] options = {"OK", "Cancel", btnOpen};
int selectedOption = JOptionPane.showOptionDialog(null,
"This is the first dialog!", "The title",
JOptionPane.NO_OPTION, JOptionPane.PLAIN_MESSAGE,
null, options, options[0]);
if(selectedOption == 0) // Clicking "OK"
{
}
else if(selectedOption == 1) // Clicking "Cancel"
{
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new MultipleDialogs();
});
}
}
}
You can replace "This is the first dialog!" and "This is the second dialog!" with JPanel's which can contain any swing components you want.
Create the second dialog from a constructor that takes dialog and boolean as parameters and that solves the problem.

Categories