I am Trying to make the program respond when the button ESC is clicked so that it will dispose the jframe. I am Not sure what the problem is but it seems to be in the if statement in the main menu.
*Note: te is the object name for the class (Text Editor)
This part is in the main method
f.add(text);
f.addKeyListener(te);
f.setVisible(true);
while(true){
if (exiting == true){
f.dispose();
}
}
This part is outside the main method
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE){
exiting = true;
}
}
Don't use KeyListeners, as a general rule, the component they are attached MUST have key board focus in order to be triggered.
Instead, use a key binding...
InputMap im = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getRootPane().getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
am.put("cancel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
See How to Use Key Bindings for more details
Because of the power of the Action API, I would create a basic "dispose" action to start with:
public class DisposeWindowAction extends AbstractAction {
private Window window;
public DisposeWindowAction(Window window) {
this.window = window;
putValue(NAME, "Dispose");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0));
}
public Window getWindow() {
return window;
}
#Override
public void actionPerformed(ActionEvent e) {
getWindow().dispose();
}
}
I'd then bind this to the ActionMap...
am.put("cancel", new DisposeWindowAction(this));
Why you ask? Because you can then use the same Action in JMenuItems and JButtons`....
JButton disposeButton = new JButton(new DisposeWindowAction(this));
...
(You can use the same instance of the Action, but you get the idea) and now the user has something like three more ways to dispose of the window...
See How to Use Actions for more details
there is an easier way to add a listener to the jframe. All you have to do is create a keylistener overriding keypressed and then check what type of object e.getComponent() is. If it is a window type you can call dispose on it when the escape key is pressed.
public void keyPressed(KeyEvent e){
If(e.getKeyCode() == KeyEvent.VK_ESCAPE){
If( e.getComponent() instanceof Window){
((Window)e.getComponent()).dispose();
}
}
}
You can of course change window to JFrame, and put the two if statements together.
Also you do not need the while loop.
Related
Here is what's inside my keyPressed:
public class Movie extends JFrame implements KeyListener {
public static Sprite star1 = new Sprite("Assets/star1.png");
public static Sprite star2 = new Sprite("Assets/star2.png");
public static Sprite star3 = new Sprite("Assets/star3.png");
public void init(){
this.addKeyListener(this);
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED: " + e.getKeyChar());
animation window = new animation(500, 450); //length , height
if (e.getKeyCode() == KeyEvent.VK_DOWN)
{
setFocusable(true);
Movie.star1.setPosition( Movie.star1.getXposition() -100, 0);
window.frameFinished();
}
else if (e.getKeyCode() == KeyEvent.VK_UP)
{
setFocusable(true);
Movie.star1.setPosition( Movie.star1.getXposition() +100, 0);
window.repaint();
}
}
My object does not move when the arrow keys are pressed.
All I want to know is - is this because I need to call the keyPressed(KeyEvent e) method in my main? When I do call it, I get an error that states:
cannot be resolved in a variable
The objects that I want to move are in a giant loop.
If you never add the key listener to some Swing component, then it will never receive events.
KeyListener itself isn't magical and doesn't listen for keypresses. What you do with a KeyListener is: you tell some other Swing component (like a window or a textbox) to call your KeyListener when a key is pressed. The component is what looks for keypresses, not the listener.
In your case, it looks like you meant to add the key listener to the window, with this.addKeyListener(this); (since in your case this is both a KeyListener and a JFrame).
However, if nothing calls your init method, then the code inside your init method (like any method) never runs, so the key listener doesn't get added to the window, so the window doesn't call it when a key is pressed!
One possible solution would be to make sure to call init after creating a new Movie (you haven't shown the code where that happens).
Another solution would be to use a constructor, instead of a method, like this:
public Movie() {
this.addKeyListener(this);
}
- constructors run when the object is created, so that way, addKeyListener will be called whenever a Movie object is created, without the creator having to remember to call init.
I found this code in several forums to close a frame on ESC keypress. But, I am confused reagrding where to put this peice of code
KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
Action action = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
jDesktopPane1.getSelectedFrame().dispose();
}
};
jDesktopPane1.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
escape,"escape");
jDesktopPane1.getActionMap().put("escape", action);
Any help will be appreciated.
Wherever you initialize jDesktopPane1, you can put it right after that and it will bind it to it. If there is an init() method for your pane, put it in there so that it gets bound.
We must add a key listener to the java component like frame. Or in your case jdesktoppane.
For an example frame's constructor,
this.addKeyAdapter(
new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyChar()==VK_ESCAPE)
this.dispose();
}
});
I have a JTable that has a delete button to delete its rows.
I want to create a shortcut, for example when user selects a row and presses the 'Delete' button on keyboard , that line should be deleted.
My line is deleted with my JButton1 perfectly.
if (e.getSource() == KeyEvent.VK_DELETE) {
// Delete row Method
}
But it doesn't work.
don't to use KeyListener for this job, and in Swing never, use KeyBindings instead
add ListSelectionListener to JTable, notice to test if(table.getSelectedRow > 0)
use KeyBindings for JTable, override Delete key
I don't know what is the exact problem because you provide too few code. However, you can't use getSource() to test which key is typed (pressed, or released). Use getKeyChar() and getKeyCode().
The following is explanation of my code:
You need to add a KeyListener to a component(of course)
The component must have focus
The component must be focusable (set focusable to true)
The component need to request for focus
Override keyTyped keyPressed or keyReleased to retrieve KeyEvent
To check which key is typed in keyTyped, use getKeyChar()
To check which key is pressed or released in keyPressed and keyReleased, use getKeyCode()
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Test {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(new Dimension(410, 330));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBackground(Color.GREEN);
panel.setBounds(50, 50, 300, 200);
panel.addKeyListener(new MyKeyListener()); // add KeyListener
panel.setFocusable(true); // set focusable to true
panel.requestFocusInWindow(); // request focus
f.getContentPane().add(panel);
f.setVisible(true);
}
static class MyKeyListener extends KeyAdapter {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == '\177') {
// delete row method (when "delete" is typed)
System.out.println("Key \"Delete\" Typed");
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
// delete row method (when "delete" is pressed)
System.out.println("Key \"Delete\" Pressed");
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
// delete row method (when "delete" is released)
System.out.println("Key \"Delete\" Released");
}
}
}
}
Take a look to this page:
http://www.coderanch.com/t/341332/GUI/java/setting-keyboard-navigation-shortcut-keys
Taken from there:
Create a key listener for that button (it seems you have already made that):
Button btn = new Button("Press Me");
btn.addKeyListener(myKeyListener);
And implement the keylistener:
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_DELETE ){
//Do whatever you want
}
}
Try it and tell me if it works.
I need a keylistener to be always 'listening' for the escape key to be pressed, to then exit the program.
I have tried typing addKeyListener(this); in my main constructor (the one with the panel being drawn in) and have used
public void keyPressed( KeyEvent e)
{
int code = e.getKeyCode();
if(code == KeyEvent.VK_ESCAPE)
{
System.exit( 0 );
}
}
I get no errors, but pressing the escape key doesn't seem to do anything, any suggestions?
Top-Level Container by default never receiving KeyEvent from KeyListener, by default, but is possible with a few code lines, wrong idea, wrong listener
JPanel by defaul react to KeyEvent, but only in the case that isFocusable, is FocusOwner, wrong idea, wrong listener, (for example) because you needed to move Focus from JTextField to JPanel programatically, wrong idea
add KeyBindings to JFrame/ JDialog / JWindow, accesible by default for Swing JComponent, not for AWT Components
You can use the InputMap/ActionMap mechanism :
Object escapeActionKey = new Object();
pnl.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), escapeActionKey);
pnl.getActionMap().put(escapeActionKey, new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.err.println("escape 1");
}
});
JComponent.WHEN_IN_FOCUSED_WINDOW means that this keystroke is available when the pnl component is in the focused window.
Or you can also add a global AWTEventListener listener :
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
public void eventDispatched(AWTEvent event) {
if(event.getID() == KeyEvent.KEY_PRESSED) {
KeyEvent kEvent = (KeyEvent) event;
boolean isEsc = (kEvent.getKeyCode() == KeyEvent.VK_ESCAPE);
if(isEsc) {
System.err.println("escape 2");
}
}
}
}, AWTEvent.KEY_EVENT_MASK);
In Swing there is a top layer panel : the GlassPane which allow to handle event at top level (to avoid other widget to comsume the event)
I have 2 classes.
One extends canvas and inside creates a jframe and add the canvas to that jframe and add another keyadapter class to receive key events. I also have main function to test the code. When running from main, the form is displayed and recieves key events too.
Now i create another class that extends jframe and implements keylistener to receive events in this form.
Once the functionality done in the second class i want to close the second form and show the first form. When showing it from the key event functions in the second class the first class key listener is not working.
Please just have a glimpse at my code and tell me how to correct my prob. Thanks for your time and valuable suggestion.
Class 1
public class Test extends Canvas {
private JFrame container;
public Test() {
container = new JFrame("Space Invaders");
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(screenSize.width, screenSize.height));
panel.setLayout(null);
setBounds(0, 0, screenSize.width, screenSize.height);
panel.add(this);
container.pack();
container.setResizable(false);
container.setVisible(true);
try {
addKeyListener(new KeyInputHandler(this));
} catch (Exception e) {
e.printStackTrace();
}
requestFocus();
}
private class KeyInputHandler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
//Some Action
}
public void keyReleased(KeyEvent e) {
//Some Action
}
public void keyTyped(KeyEvent e) {
//Some Action
}
}
public static void main(String args[]){
//Running this canvas here works perfectly with all added keylisteners
}
}
Class 2
public class Sample extends JFrame implements KeyListener {
public Sample() {
init();
this.setSize(100, 100);
this.setVisible(true);
Sample.this.dispose();
// Created a window here and doing some operation and finally redirecting
// to the previous test window. Even now the test window works perfectly
// with all keylisteners
new Test();
}
public static void main(String[] args) {
new Sample();
}
private void init() {
addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
removeKeyListener(this);
Sample.this.dispose();
// But when calling the previous Test window here, the window
// gets displayed but the keylistener is not added to the
// window. No keys are detected in test window.
new Test();
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Simple dont use KeyListener/KeyAdapter that is for AWT components and has known focus issues when used with Swing.
The issues can be got around by making sure your component is focusable via setFocusable(true) and than call requestFocusInWindow() after component has been added/is visible.
Rather use KeyBindings for Swing.
For example say now we wanted to listen for D pressed and released:
public static void addKeyBindings(JComponent jc) {
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "D pressed");
jc.getActionMap().put("D pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("D pressed");
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "D released");
jc.getActionMap().put("D released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("D released");
}
});
}
We would call this method like:
JPanel ourPanel=new JPanel();
...
addKeyBindings(ourPanel);//adds keybindings to the panel
Other suggestions on code
Always create and manipulate Swing components on Event Dispatch Thread, via SwingUtilities.invokeLater(Runnable r) block
Dont extend JFrame class unnecessarily
Dont implement interfaces on a class unless the class will be used for that purpose, or other classes need access to the interfaces methods.
As mentioned by #AndrewThompson, dont use multiple JFrames, either swap the rest for JDialog, or use CardLayout. See here for an example.