Get caret position when key pressed using KeyboardFocusManager - java

I'm trying to get the current caret position when the "<" character is typed, using a KeyboardFocusManager. Code below. If the text field is empty when they character is typed I would expect the caret position to be 0. However, the result I actually get is this: 0 0 1. Could anyone explain why this is happening?
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TextEditor {
#SuppressWarnings("serial")
public static class TextClass extends JTextArea {
static int startpos = 0;
public boolean checkKeyTyped (KeyEvent e) {
String keystr = Character.toString(e.getKeyChar());
switch (keystr) {
case "<":
startpos = getSelectionStart();
System.out.print(" " + startpos);
}
return false;
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
final JTextArea textArea = new TextClass();
frame.add(textArea);
frame.setVisible(true);
// Add keyboard listener
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
return ((TextClass) textArea).checkKeyTyped(e);
}
});
}
}

You are using a general Key Event dispatcher. The possible events are KEY_PRESSED, KEY_TYPED and KEY_RELEASED. Based on what you say, you need KEY_TYPED. So filter for that:
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.KEY_TYPED) {
return ((TextClass) textArea).checkKeyTyped(e);
}
}
});

It is not how you are supposed to do it, you are supposed to implement a KeyListener and add it to your JTextArea using addKeyListener(KeyListener), as next:
final JTextArea textArea = new TextClass();
...
textArea.addKeyListener(new KeyListener() {
#Override
public void keyTyped(final KeyEvent e) {
char key = e.getKeyChar();
switch (key) {
case '<':
System.out.print(" " + textArea.getSelectionStart());
}
}
#Override
public void keyPressed(final KeyEvent e) {
}
#Override
public void keyReleased(final KeyEvent e) {
}
});
Up to now, you get it printed 3 times because your method is called for each type of KeyEvent that is triggered whenever you type on a key:
KEY_TYPED
The "key typed" event. This event is generated when a character is
entered. In the simplest case, it is produced by a single key press.
Often, however, characters are produced by series of key presses, and
the mapping from key pressed events to key typed events may be
many-to-one or many-to-many.
KEY_PRESSED
The "key pressed" event. This event is generated when a key is pushed
down.
KEY_RELEASED
The "key released" event. This event is generated when a key is let
up.

Related

Adding a Key Listener to a JtextArea

I have a JTextArea called input and I am trying to get the string inputValue loaded into it when I press the up arrow key. so far this code does not seem to work and I am unsure as to why. Please help.
input.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
System.out.println("test");
if(e.getKeyCode() == KeyEvent.VK_UP) {
input.setText(inputValue);
System.out.println("up is pressed");
}
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
});
You should take care when using low level listeners like KeyListeners on Swing text components like JTextAreas, since messing with these can cause the text component to misbehave.
Much better is to use a DocumentListener if you're looking for changes to the document or a DocumentFilter if you want to listen for and block or change text entry before it occurs.
If you just want to be notified of keys such as the up arrow, I'd use Key Bindings -- what the JTextArea uses itself to be notified of and react to key presses, and would replace the key binding with the new one. If you do this with care, you can even call the original action tied to the key press in your new Action. For instance:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TextAreaTrapUp extends JPanel {
private JTextArea textArea = new JTextArea(20, 40);
public TextAreaTrapUp() {
// get JTextArea's InputMap and ActionMap
int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = textArea.getInputMap(condition);
ActionMap actionMap = textArea.getActionMap();
// get the up keystroke
KeyStroke upKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
String upKey = (String) inputMap.get(upKeyStroke); // get the input map's key for this keystorke
Action originalUpAction = actionMap.get(upKey); // and get the action map's original action for this key
Action newUpAction = new NewUpAction(originalUpAction); // create our new up action passing in the old one
actionMap.put(upKey, newUpAction); // and set this into our ActionMap
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);
add(new JScrollPane(textArea));
}
// Action called when up-arrow pressed
private class NewUpAction extends AbstractAction {
private Action originalUpAction; // the original action
public NewUpAction(Action originalUpAction) {
this.originalUpAction = originalUpAction;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Up Arrow Pressed");
// if you want to move the caret up, then call the original action
// as well
if (originalUpAction != null) {
originalUpAction.actionPerformed(e);
}
}
}
private static void createAndShowGui() {
TextAreaTrapUp mainPanel = new TextAreaTrapUp();
JFrame frame = new JFrame("TextAreaTrapUp");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
you should override void keypressed instead of keytyped
#Override
public void keyPressed(KeyEvent e) {
System.out.println("test");
if(e.getKeyCode() == KeyEvent.VK_UP) {
input.setText(inputValue);
System.out.println("up is pressed");
}
because it's not a caracter

How to add keyListner to a JOptionPane.showInputDialog()?

I want to add keyListner on Input Dialog. When i press a key it will gives key code of pressed key. Below is complete code for JTextField its working for JTextField. I tried it on Input Dialog via String n = JOptionPane.showInputDialog("enter a key") but it says that keyListner unidentified for String operation.
*please edit my code for Input dialog
import java.awt.event.*;
import javax.swing.*;
public class KeyListnerExample extends JFrame implements KeyListener{
String KeyCodeT = JOptionPane.showInputDialog("enter a key");//A Text Field that will display the key code.
public KeyListnerExample(){
KeyCodeT.addKeyListener(this);//Listens for key inputs in the text field
KeyCodeT.setEditable(false);//disallow user input into the Text field.
add(KeyCodeT);//add the text field to the screen
setSize(300,300);//set the screen size
setVisible(true);//show the window on screen.
}
//Called when the key is pressed down.
public void keyPressed(KeyEvent e){
System.out.println("Key Pressed!!!");
e.getKeyCode();
System.out.println("key code is: " +e.getKeyCode());
}
//Called when the key is released
public void keyReleased(KeyEvent e){
System.out.println("Key Released!!!");
KeyCodeT.setText("Key Code:" + e.getKeyCode());//displays the key code in the text box
}
//Called when a key is typed
public void keyTyped(KeyEvent e){
}
public static void main(String[] args){
KeyListnerExample key = new KeyListnerExample();
}
}
You can try something like below :
Here you can create a text field by adding keyListener and that text field can be passed to the JoptionPane .
public static void main(String[] args) {
JFrame parent = new JFrame();
JOptionPane optionPane = new JOptionPane();
JTextField field = getField();
optionPane.setMessage(new Object[]{"Type something: ", field});
optionPane.setMessageType(JOptionPane.QUESTION_MESSAGE);
optionPane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
JDialog dialog = optionPane.createDialog(parent, "My Customized OptionPane");
dialog.setVisible(true);
}
private static JTextField getField() {
JTextField field = new JTextField();
field.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Input: " + e.getKeyChar());
}
#Override
public void keyReleased(KeyEvent e) {
}
});
return field;
}
Here's a hint for what you can do:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class KeyListnerExample extends JFrame implements KeyListener{
JTextField KeyCodeT;
public KeyListnerExample(){
JPanel panel = new JPanel();
KeyCodeT = new JTextField();
KeyCodeT.setOpaque(false);
panel.setLayout(new GridLayout(1,1));
panel.add(KeyCodeT);
JOptionPane.showOptionDialog(null, panel, "Enter Key Code", JOptionPane.CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null);
KeyCodeT.addKeyListener(this);//Listens for key inputs in the text field
KeyCodeT.setEditable(false);//disallow user input into the Text field.
add(KeyCodeT);//add the text field to the screen
setSize(300,300);//set the screen size
setVisible(true);//show the window on screen.
}
//Called when the key is pressed down.
public void keyPressed(KeyEvent e){
System.out.println("Key Pressed!!!");
e.getKeyCode();
System.out.println("key code is: " +e.getKeyCode());
}
//Called when the key is released
public void keyReleased(KeyEvent e){
System.out.println("Key Released!!!");
KeyCodeT.setText("Key Code:" + e.getKeyCode());//displays the key code in the text box
}
//Called when a key is typed
public void keyTyped(KeyEvent e){
}
public static void main(String[] args){
KeyListnerExample key = new KeyListnerExample();
}
}
As you can see, I created a JPanel and added text field to it instead. Its easier to manage that way. Then finally used JOptionPane's OptionDialog to display stuff.
You can also use KeyCodeT.setBorder(null); if you dont want that black border. But that will give you an absurd dialog where you will have to make a guess-click in the middle.
EDIT: (Practically what #kamel2005 said in his answer).
Create a JPane Control that contains the control that will broadcast the key event to your key Listener.
for example JTextField and then add your key listener to text field.
the Pane can be passed as a parameter to "JOptionPane"
JPanel jPane = new JPanel();
TextField field = new TextField();
jPane.add(field);
field.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});
if (JOptionPane.showConfirmDialog(null,jPane,"Panel Title", JOptionPane.OK_CANCEL_OPTION)== JOptionPane.OK_OPTION) {
System.out.println(field.getText());
}

Java AWT KeyListener not working

I have been playing around with Java and I added a KeyListener. When I type a key it prints "0" and I would like it to print the key code.
Key.java
import java.awt.event.*;
public class Key implements KeyListener {
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
System.out.println("TYPED: " + Integer.toString(e.getKeyCode()));
}
}
Main.java
public void init() {
addKeyListener(new Key());
addMouseListener(new Mouse());
this.setBackground(new Color(100, 100, 255));
this.setSize(screen);
}
Thanks for all the help!
Just read the doc :
void keyTyped(KeyEvent e)
Invoked when a key has been typed. See the class description for
KeyEvent for a definition of a key typed event.
So go through the description :
public int getKeyCode()
Returns the integer keyCode associated with the key in this event.
Returns: the integer code for an actual key on the keyboard. (For
KEY_TYPED events, the keyCode is VK_UNDEFINED.)
And the constant VK_UNDEFINED is :
public static final int VK_UNDEFINED = 0;
So that's totally normal you only get 0.
You should use :
public void keyTyped(KeyEvent e) {
System.out.println("TYPED: " + e.getKeyChar());
}
Here's an example using the three methods.
For KEY_TYPED event, the Key Code is undefined. Check the java docs:
http://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html#getKeyCode()
Use getKeyChar() instead.

How to create a KeyEvent

When i create the KeyListener, it requires the following fields:
public void keyPressed(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
When i put System.out.println(e) into the keyPressed method, though, it returns this when i press the enter key:
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=10,keyText=?,keyChar=?,keyLocation=KEY_LOCATION_STANDARD,rawCode=0,primaryLevelUnicode=0,scancode=0] on javax.swing.JButton[,1,1,100x100,alignmentX=0.0,alignmentY=0.5,border=com.apple.laf.AquaButtonBorder$Dynamic#13b33a0e,flags=288,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=0,left=2,bottom=0,right=2],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=HI,defaultCapable=true]
This is obviously not a KeyEvent, so I cannot use it to call the keyPressed(KeyEvent e). What I want to be able to do is simulate the pressing of a key, specifically the enter key, in a way that would activate the keyListener and would output that text into a JTextArea.
Note: I looked at the accepted answer for How can I perfectly simulate KeyEvents?, and understood little of how it actually works, and i want code i understand. I also looked here How to simulate keyboard presses in java?, but not i could not get the robot to work; nothing happened when a key was supposed to be pressed.
e is the KeyEvent.
if you want to see the e value, then you can try this
System.out.println(e.getKeyChar());
Creating KeyEvent :
KeyEvent e = new KeyEvent(Component source, int id, long when, int modifiers, int keyCode, char keyChar, int keyLocation);
Example (dunno if this is the right way, but it produce the right output):
Button a = new Button("click");
KeyEvent e;
e = new KeyEvent(a, 1, 20, 1, 10, 'a');
System.out.println(""+e.getKeyChar());
System.out.println(""+e.getKeyCode());
Here is the all type of KeyEvent parameters
java.​awt.​event.​KeyEvent
#Deprecated public KeyEvent(Component source, int id, long when, int modifiers, int keyCode)
Deprecated. as of JDK1.1
===
java.​awt.​event.​KeyEvent
public KeyEvent(Component source, int id, long when, int modifiers, int keyCode, char keyChar)
Constructs a KeyEvent object.
Note that passing in an invalid id results in unspecified behavior. This method throws an IllegalArgumentException if source is null.
Parameters:
source - the Component that originated the event id - an integer identifying the type of event when - a long integer that specifies the time the event occurred modifiers - the modifier keys down during event (shift, ctrl, alt, meta) Either extended _DOWN_MASK or old _MASK modifiers should be used, but both models should not be mixed in one event. Use of the extended modifiers is preferred. keyCode - the integer code for an actual key, or VK_UNDEFINED (for a key-typed event) keyChar - the Unicode character generated by this event, or CHAR_UNDEFINED (for key-pressed and key-released events which do not map to a valid Unicode character)
Throws:
IllegalArgumentException - if id is KEY_TYPED and keyChar is CHAR_UNDEFINED; or if id is KEY_TYPED and keyCode is not VK_UNDEFINED IllegalArgumentException - if source is null
===
java.​awt.​event.​KeyEvent
public KeyEvent(Component source, int id, long when, int modifiers, int keyCode, char keyChar, int keyLocation)
When using robot, first obtain focus of component to which you add your KeyListener to. Then you can use robot to simulte key presses. As an alternative, you can just use dispatchEvent on component to which your listener is added.
KeyEvent key = new KeyEvent(inputField, KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, 'Z');
inputField.dispatchEvent(key);
Providing you have:
JInputField InputField = new JInputField();
You can as well create KeyEvent as described above and pass it to keyTyped method of your listener.
As for keyPrssed, you can do the same.
You state:
I believe it would make part of my code more efficient. When certain conditions are met (I am doing hang man, and this is a "cheat" that is a joke with my teacher) the computer will press the correct keys to "guess" the answer. and then there is the simple, i wonder if i can? part of it. that got started when i saw JButton.doClick() and wondered if it had one for JTextFields
As I suspected, you are going about this all wrong. If you want your program to press keys for you, there's no need to create KeyEvents. If the "keys" are JButtons, then simply calling doClick() on the button will do. If you are desiring to fill text into a JTextField, then simply setting the text is all that is needed. i.e.,
For instance if you called the bit of text below in a Swing Timer (to slow it down so that you see the text being added:
String myText = myTextField.getText();
myText += nextBitOfText;
myTextField.setText(myText);
You would likely get the effect you desire.
For example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class AddTextToTextField extends JPanel {
public static final String[] POSSIBLE_TEXTS = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
public static final int TIMER_DELAY = 500;
private JTextField myTextField = new JTextField(20);
private JButton myButton = new JButton(new BtnAction("Press Me"));
private Random random = new Random();
public AddTextToTextField() {
add(myTextField);
add(myButton);
}
private class BtnAction extends AbstractAction {
public BtnAction(String text) {
super(text);
}
#Override
public void actionPerformed(ActionEvent arg0) {
setEnabled(false);
myTextField.setText("");
myTextField.setFocusable(false);
String randomText = POSSIBLE_TEXTS[random.nextInt(POSSIBLE_TEXTS.length)];
new Timer(TIMER_DELAY, new TimerAction(this, randomText)).start();
}
}
private class TimerAction implements ActionListener {
private AbstractAction btnAction;
private String text;
private int count = 0;
public TimerAction(AbstractAction btnAction, String text) {
this.btnAction = btnAction;
this.text = text;
}
#Override
public void actionPerformed(ActionEvent e) {
if (count <= text.length()) {
myTextField.setText(text.substring(0, count));
count++;
} else {
((Timer)e.getSource()).stop();
btnAction.setEnabled(true);
myTextField.setFocusable(true);
}
}
}
private static void createAndShowGui() {
AddTextToTextField mainPanel = new AddTextToTextField();
JFrame frame = new JFrame("AddTextToTextField");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can use this to dispatch a virtual event:
textArea.dispatchEvent(new KeyEvent(jFrame,
KeyEvent.KEY_TYPED, System.currentTimeMillis(),
0,
KeyEvent.VK_ENTER));
Try that out, it should work but that was from memory

Mac/Java-7: Why does TextField not get the expected KEY_PRESSED events when Alt is down?

When executing a keyboard event that includes an 'Alt,' Mac/Java-7 does not propagate a KEY_PRESSED against a non-modifier key in the key sequence against TextFields.
This behavior is not reproducible against other modifier keys like Cmd or Ctrl.
For example, when compiling and running the below code and executing a 'Alt + o' keystroke in the TextField, all platforms, except Mac/Java 7, output the following key event sequence (note that there is a KEY_PRESSED for both the 'alt' and the 'o'):
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=18,keyText=?,keyChar=Undefined keyChar,modifiers=?
java.awt.event.KeyEvent[KEY_PRESSED,keyCode=79,keyText=O,keyChar='ø',modifiers=?
java.awt.event.KeyEvent[KEY_TYPED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar='ø',modifiers=?
java.awt.event.KeyEvent[KEY_RELEASED,keyCode=79,keyText=O,keyChar='ø',modifiers=?...
java.awt.event.KeyEvent[KEY_RELEASED,keyCode=18,keyText=?,keyChar=Undefined...
However, on Mac/Java-7 (tested up to patch 10), you get the above without the KEY_PRESSED representing the 'o' (KEY_PRESSED,keyCode=79,keyText=O,keyChar='ø'). The KEY_TYPED event might not be the most helpful substitute because it doesn't have modifiers or a keyCode, at least without tracking some state.
import javax.swing.*;
import java.awt.event.*;
public class ScratchKeyEvent {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JTextField field = new JTextField(10);
field.addKeyListener(createListener());
frame.add(panel);
panel.add(field);
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static KeyListener createListener() {
return new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped " + e);
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed " + e);
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased " + e);
}
};
}
}

Categories