How to capture keyboard inputs in my JWindow using Java? - java

When i press keyboard with F1 to 12 or 0 to 9 or A to Z (all buttons). I do not see its capturing my keyboard inputs. How do i fix this?
public class Boot extends JWindow implements KeyListener
{
public Boot()
{
.....
this.addKeyListener(this);
....
}
public void keyTyped(KeyEvent ke)
{
System.out.println( ke.getKeyChar());
}
public void keyPressed(KeyEvent ke)
{
System.out.println( ke.getKeyChar());
/* KEY EVENTS */
// KeyEvent.KEY_TYPED
// KeyEvent.KEY_PRESSED
// int id = id.getId();
}
public void keyReleased(KeyEvent ke)
{
System.out.println( ke.getKeyChar());
}
}

KeyEvents are only passed to components that are focusable.
Read the API for the JWindow() constructor. It states:
Creates a window with no specified owner. This window will not be focusable.
Read the API for the JWindow(Frame) constructor. It states:
Creates a window with the specified owner frame. If owner is null, the shared owner will be used and this window will not be focusable. Also, this window will not be focusable unless its owner is showing on the screen.
So basically you also need to create a visible JFrame when using a JWindow.
JFrame frame = new JFrame();
frame.setVisible( true );
JWindow window = new JWindow(frame);
A hack I've seen on the forums is to use:
JWindow window = new JWindow(new JFrame("is Showing")
{
public boolean isShowing()
{
return true;
}
});
Or a better approach is to use an undecorated JFrame and you don't have to worry about this.

[Java API of KeyEvent]
The getKeyChar method always returns a valid Unicode character or CHAR_UNDEFINED. Character input is reported by KEY_TYPED events: KEY_PRESSED and KEY_RELEASED events are not necessarily associated with character input. Therefore, the result of the getKeyChar method is guaranteed to be meaningful only for KEY_TYPED events.
For key pressed and key released events, the getKeyCode method returns the event's keyCode. For key typed events, the getKeyCode method always returns VK_UNDEFINED.
Use getKeyCode on key released.
KeyEvent.F1, F2, ... are usable for the function keys.

Related

Is there a way in swing to capture all keyboard input regardless of focus

The problem
In Swing (Java), I want to capture all keyboard input, regardless of which control has focus.
So, if I press a key on my keyboard (not just alphanumeric, function keys and such included), while the window is in focus, a callback should run, allowing me to do what I want with the given input.
What I've tried
Using the panel I've tried to add a key listener, which implements the KeyListener class in java.awt.event, like so:
// MainApplicationWindow.java
// ...
mPanel.addKeyListener(
new SwingKeyListener()
);
With the actual listener being:
// SwingKeyListener.java
public class SwingKeyListener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {/*...*/}
#Override
public void keyPressed(KeyEvent e) {/*...*/}
#Override
public void keyReleased(KeyEvent e) {/*...*/}
}
Results
GUI is displayed, no errors or exceptions are outputted, key listener does not work.
Solutions
Solution was to use the KeyEventPostProcessor class to poll for input.
KeyEventPostProcessor pp = e -> {
SwingKeyListener.keyPressed(e);
return true;
};
DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(pp);

Add KeyListener to Jframe issue

I have a jframe of which I have made in Netbeans, this jframe is being "launched" by another java class, but for the current question that doesn't matter. What matters is the fact that I can't seem to figure out how to add my key listener to this jframe of mine. I have implemented the key listener, added the required functions (key typed, key pressed and key released). But I can't figure out how to actually add/initiate the actual key listener, to make it work.
As of right now I have tried two different things, first I have tried to add the line addKeylistener(new JFrameList()); in the start of the code, where the actual jframe is being initiated, but doing so the actual frame won't even show. Apart from this I have tried to add the same line within another function callJframFForm(), which is called from another class at the same time as the jframe is called. But this just returns the error non-static method addKeyListener(KeyListener) cannot be referenced from a static context. I am not sure what other ways I could add the key listener and thus am looking for a little help.
Currently my code looks like the one below.
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class JFrameList extends javax.swing.JFrame implements KeyListener{
public static String keyPresCod = "";
public JFrameList() {
initComponents();
addKeyListener(new JFrameList()); //This is where I am currently trying to call from, but frame won't show
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new JFrameList().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
// End of variables declaration
static void callJframFForm(){
try {
//This is where I have also tried to add the initialization line
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void keyTyped(KeyEvent e) {
int codeFKey = e.getKeyCode();
if (codeFKey == KeyEvent.VK_A) {
System.out.println("Button A clicked");
keyPresCod = "A";
} else if (codeFKey == KeyEvent.VK_B) {
System.out.println("Button B clicked");
keyPresCod = "B";
} else {
System.out.println("Different key pressed");
keyPresCod = "Another key";
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Problem
addKeyListener(new JFrameList())
This creates a new JFrameList object and uses it's listener. This means any keystrokes are being stored in the new object's member. To see the results, you would have to do
JFrameList list = new JFrameList();
addKeyListener(list);
//use list variable to access keyPressed code
Of course this isn't the behavior you want. You want the keys strokes to be stored in the current instance, not a new object. This means you should be doing
addKeyListener(this)
Although you may notice the listener only works "sometimes", or maybe not at all depending on how you're testing it.
Swing uses a focus system to manage which listeners should be receiving events, and since you are adding the listener to a JFrame, the listener will receive events only when the frame is in focus.
Solution
You should use key bindings rather than a key listener.
If you choose to continue using the listener, you should add it to your buttons, not your frame:
jButton1.addKeyListener(this);
jButton2.addKeyListener(this);
Instead of checking the key code of the event, you could grab the source of the event (your button) by calling event.getSource().
Key bindings allows you to set flexible focus settings for your components. All you need to do is access the input map of the component:
String actionCommand = "Press Button A";
jButton1.setActionCommand(actionCommand);
jButton1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), actionCommand);
jButton1.getActionMap(actionCommand, this);
Your JFrameList should now implement ActionListener rather than KeyListener, as it will be receiving your events as actions:
class JFrameList extends JFrame implements ActionListener {
private JButton jButton1;
public JFrameList() {
jButton1 = new JButton("A");
//set action command, add to input map, add to action map
}
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
System.out.println(button.getActionCommand() + " was performed.");
}
}
Alternative
JButton has built-in mnemonic handling. You can specify a mnemonic via JButton#setMnemonic(int), where the argument is a key code:
jButton1.setMnemonic(KeyEvent.VK_A);
This is the standard way of handling hotkeys in graphical interfaces. Simply hold down the Alt key (windows) then press the key you set the mnemonic to.
Key Events are only dispatched to the component with focus. You didn't post the entire code but I'm guessing that focus is on the button that you add to the frame, so the button gets the KeyEvent.
Not sure what you are trying to do with the KeyListener. You can't tell which button was clicked by looking at the character typed in the KeyEvent.
If you want to know what button is clicked then you need to add an ActionListener to each button. Read the section from the Swing tutorial on How to Use Buttons for more information and examples.

Where to addKeyListener in order to 'always' be listening

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)

Remove the listener for defaultButton in java

i have a Jframe application with the defaultbutton set to btnClose_ (Close Button: this button closes the window).
I have 2 textfields that must also fire an event when user clicks the Enter key on the textfields. What happens is that when I press the Enter key while the cursor is on the textfield, the event on the Close button is fired causing the window to close.
Is it possible to remove the listener of the default button if the Enter key is pressed on the textfield? Here's my code for the textfield listener
/**
* Receives the two textfield instance
*/
private void addFilterListener(JTextField txf) {
txf.addKeyListener(new KeyAdapter() {
/**
* Invoked when a key has been pressed.
*/
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
ActionListener al = btnClose_.getActionListeners()[0];
btnClose_.removeActionListener(al);
btnFilter_.doClick();
e.consume();
btnClose_.addActionListener(al);
}
}
});
}
private JButton getBtnClose(){
if(btnClose == null){
btnClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getWindow().dispose();
}
});
}
return btnClose;
}
}
Where to start?
The first thing that springs out at me is the bad variable names. txf? What's wrong with proper words? textField or field, say. Or much better, a name descriptive of its purpose, not what it is.
Secondly, the first comment is wrong (not uncommon) and the second comment is redundant (already specified in the KeyListener interface, you don't need to try and half-heartedly specify it again).
Next up, low level key listeners tend not to work so well on Swing components (JComboBox being the most notorious example - it typically is implemented with child components). In general you can use JComponent.registerKeyboardAction (the API docs says this is obsolete but not deprecated, and to use more verbose code). For text components, you often want to play with the document (typically through DocumentFilter). In this particular case, looks like you just want to add an ActionListener.
Now doClick. It's a bit of an evil method. For one thing it blocks the EDT. It is probably the easiest way to make it look as if a button is pressed. From a programming logic point of view, it's best to keep away from modifying Swing components, when you can keep everything in your abstracted code.
Removing and adding listeners from components is generally a bad idea. Your code should determine what to do with an event including whether to ignore it. Do that at an appropriate point when handling the event. Don't duplicate state unnecessarily.
A potential issue is that the code seems to assume that there is precisely one action listener. There could be others. The code is not robust under unexpected behaviour. Set your components up at initialisation time, and you shouldn't need to refer to them again.
As far as I understood your question, you want that buttonClick should not get fired if Enter is pressed .
This won't fire doClick() if enter is pressed
if (e.getKeyCode() != KeyEvent.VK_ENTER) {
btnFilter_.doClick();
}
In the ActionListener of the close button, assuming you can change its code, don't close if one of the text fields have the focus.
public void actionPerformed(ActionEvent e) {
if (field1.hasFocus() || field2.hasFocus())
return; // don't close if text field has focus
frame.dispose();
}
If you can not change the ActionListener of the close button, add a FocusListener to the text fields. If one of them gets the focus, remove the default button. If the text field lost the focus, reset the default button.
FocusAdapter listener = new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
frame.getRootPane().setDefaultButton(null);
}
#Override
public void focusLost(FocusEvent e) {
frame.getRootPane().setDefaultButton(close);
}
};
field1.addFocusListener(listener);
field2.addFocusListener(listener);
This should be better than depending on the listeners being called in the correct sequence - it is of no avail to remove the listener if it was already called...

Stopping default behavior of events in Swing

I have the following bit of code in a method called by clicking the send button, or pressing enter in the message text field in a piece of code.
// In class ChatWindow
private void messageTextAreaKeyPressed(java.awt.event.KeyEvent evt) { // Event handler created by Netbeans GUI designer to call this method.
if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) {
sendMessage();
}
}
public void sendMessage() {
String currentMessage = messageTextArea.getText();
addMessage("You", currentMessage);
app.sendMessage(currentMessage, 1);
messageTextArea.setText("");
}
The last bit of code blanks the text area. However, after a message is sent by pressing the enter button, rather than being empty, the text box contains a newline.
My guess is that after my event handler runs, THEN the newline character is being added. How to I stop the newline being added?
try adding evt.consume() after your call to sendMessage()
private void messageTextAreaKeyPressed(java.awt.event.KeyEvent evt) {
if(evt.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) {
sendMessage();
evt.consume();
}
}
The default Action for the Enter key in a JTextArea is to insert a new line as you have seen. So the solution is to replace the default Action with a custom Action. The benefit of this approach is that this Action can also be used by the JButton (or JMenuItem etc.). An Action is basically the same as an ActionListener, all you need to do is implement the actionPerformed() method.
Read up on Key Bindings to see how this is done. All Swing components use Key Bindings.
as camickr said,
you should bind action to enter key;
Action sendAction = new AbstractAction("Send"){
public void actionPerformed(ActionEvent ae){
// do your stuff here
}
};
textarea.registerKeyboardAction(sendAction,
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
sendButton.setAction(sendAction);
if you are more interesed, I implemented Autoindent feature for textarea, using this technique:
here

Categories

Resources