Reading last character entered from JTextArea [duplicate] - java

This question already has an answer here:
Java - JTextField - Call function when user press "space bar"
(1 answer)
Closed 8 years ago.
I am making a simple text editor in Java so that I can write programs. I am stuck on making an ActionListener that is activated whenever a space is entered.
So, when you are typing into the text area and you press space, it will read the last word you typed.
Here are the essential parts of my code.
I have made an action listener and all of the other stuff, now I just need to make it read spaces.
JTextArea textarea = new JTextArea("#ECHO off" + "\n");
Font textareaFont = new Font("Arial", Font.BOLD, 15);
action event = new action();
textarea.setFont(textareaFont);
textarea.setForeground(Color.BLUE);
textarea.setLineWrap(true);
textframe.getContentPane().add(new JScrollPane(textarea));
textframe.setSize(525,715);
textframe.setLocationRelativeTo(null);
textframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textframe.setVisible(true);
}
private class action implements ActionListener {
public void actionPerformed(ActionEvent event) {
}
}
Sorry if I am not being clear.

I think you would want a KeyListener, not an ActionListener.
Perhaps something like this:
textarea.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
if (evt.getKeyCode() == KeyEvent.VK_SPACE) {
//do your stuff here
}
}
}

You cannot do this job with an ActionListener because Swing text components do not fire ActionEvents in response to (most) keystrokes. Consult the key binding docs for information about how to achieve what you're after, but perhaps a refresher on Swing overall would be in order.

Related

Adding ActionListener for a typing game

Have been looking at lots of documents about use of ActionListener with JTextField and have seen a lot of the other questions asked for similar reasons, but I cant seem to apply the solutions to my problem.
The basic premise of what I need is there will be a text field on the screen for the user to type words into.
I want a timer to start running in the background after a certain key press. (preferably enter or spacebar) and then the timer should stop when the entire sentence has been written. So far I have not had much luck with getting an event to start with a key press. Below is some code that doesn't really work, I can successfully create the frame with the text box I just can't get the action listener to work for the purpose I want it for.
input = new JTextField();
input.setBounds(10, 150, 780, 35);
panel.add(input);
input.addActionListener(new ActionListener());
public void actionPerformed(ActionEvent e) {
}
Haven't added anything in the actionPerformed method as all the tests I ran weren't successful. Not asking for full code but a pointer in the right direction could help. Yes I have read the docs on how to use addActionListener() but I can't apply it to what I want to do.
You want a KeyListener, not an ActionListener.
Implement KeyListener, and then in the method keyPressed(KeyEvent name),
type e.getKeyCode using either a switch or if statement.
eg(pseudo code):
javax.swing.JTextField input=null;
javax.swing.JPanel panel=null;
public class X implements java.awt.event.KeyListener{
input = new javax.swing.JTextField();
input.setBounds(10, 150, 780, 35);
panel.add(input);
input.addActionListener(new ActionListener());
input.addKeyListener(this);
public void keyPressed(java.awt.event.KeyEvent e){
if(e.getKeyCode==e.VK_W){
//Enter code here
}}public void actionPerformed(ActionEvent e) {
//then upon enter the timer stops
}
}

My JDialog sometimes receives a redundant keystroke from the calling app ? (code provided)

I develop a complex music application in java (8) based on the Netbeans RCP 8.2 and I have a strange problem that occurs randomly.
I have a JFrame with a panel which contains many JComponents. I use the panel's InputMap/ActionMap to capture "a","b",...,"g" key presses and call an action.
The action retrieves the key char then shows a JDialog which contains a JTextField used to edit some text data.
Before showing the dialog with dialog.setVisible(true), the action calls dialog.prepare(char key) so that the JDialog can initialize itself before being shown. Actually dialog.prepare(char key) only appends the passed char (converted to uppercase) in the JTextField.
This works most of the time: I press for example "c" in the JFrame then the JDialog appears with "C" at the end of the JTextField.
But sometimes, maybe 1/20 times, I get "Cc" at the end of the JTextfield !
It's like the original key press event (which comes from a JComponent in the JFrame's panel and was processed using InputMap/ActionMap) was also redundantly processed by the JDialog.
I verified that it's not a keyboard hardware problem. I reproduced the issue on a second computer with Win8 (mine is Win10).
I tried without success 1/ using a KeyListener instead of InputMap/ActionMap
and 2/ use java.awt.EventQueue.invokeLater() to append the key char in the JTextField.
I created a small independant app (see below) to reproduce the issue and facilitate debugging...but this small app works fine, I could not reproduce the issue :-( Then I compared again with my real app code, and it's really the same code, except the real app is a complete Netbeans RCP application.
So could it be that Netbeans RCP impacts the way Swing handle key events ? It looks odd to me...
I'm lost, any hint/suggested test would be greatly appreciated !
/**
* Try to reproduce double key problem... Failed because this works OK !! :-(
*/
public class PbKeyDouble extends JFrame {
MyDialog dialog;
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PbKeyDouble o = new PbKeyDouble();
o.setVisible(true);
}
});
}
public PbKeyDouble() {
// GUI INITIALIZATION
// Add a basic panel
JPanel panel = new JPanel();
getContentPane().add(panel);
panel.setPreferredSize(new Dimension(300, 200));
JButton button = new JButton("BUTTON");
panel.add(button);
// Button not used, it's only to simulate the real app where a component in the panel has the focus
button.requestFocusInWindow();
// If "A" or "B" key is pressed anywhere, MyAction.actionPerformed() will be called
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("A"), "MyAction");
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("B"), "MyAction");
panel.getActionMap().put("MyAction", new MyAction());
// Prepare JFrame
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
}
private class MyAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("EDT? " + SwingUtilities.isEventDispatchThread()); // Always prints TRUE
if (dialog == null) {
dialog = new MyDialog();
}
// Retrieve the key used to trigger the action
char c = e.getActionCommand().charAt(0);
// Prepare the dialog (insert the char)
dialog.prepare(c);
// Show dialog
dialog.setVisible(true);
}
}
private class MyDialog extends JDialog {
JTextField textfield;
/**
* A simple dialog with just a textfield.
*/
public MyDialog() {
textfield = new JTextField("Hello");
textfield.setColumns(100);
getContentPane().add(textfield);
pack();
setLocationRelativeTo(null);
}
/**
* Append the key (uppercased) at the end of the textfield
*/
public void prepare(char c) {
String text = textfield.getText();
textfield.setText(text + " " + Character.toUpperCase(c));
}
/**
* Overridden to add a global key binding on ESC key to exit the dialog.
* <p>
* This is only to facilitate the test where I need to try many times the process pressing "a" ESC "a" ESC etc.
*
* #return
*/
#Override
protected JRootPane createRootPane() {
JRootPane contentPane = new JRootPane();
contentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("ESCAPE"), "actionCancel");
contentPane.getActionMap().put("actionCancel", new AbstractAction("Cancel") {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
return contentPane;
}
}
}
I found the problem, though it is still not logical to me. Explanation welcome !
All Swing components should be created and modified on the Event Dispatch Thread (EDT).
Yes, it was the case in my code and still it was not working...
To try to understand what happens I attached a KeyListener to the JTextField of the JDialog.
I found out that when it was working (key not doubled) my KeyListener received only a keyReleased() event. When it was not working (key doubled "Cc") my KeyListener received a keyTyped() event then keyReleased().
So I understand that AWT/Swing event handler mechanism "sends" each KeyEvent to the currently focused component (instead of to the component which the KeyEvent originates from). As I show the Dialog somewhere in the middle of the keyPressed/keyTyped/keyReleased sequence, sometimes the keyTyped was "wrongly" directed to the JTextField.
To solve this I executed the whole actionPerformed() code using SwingUtilities.invokeLater(), to make sure Dialog is shown after all EDT pending events are processed, and it seems to work so far...
I could find some good information in Java keybinding but what I don't understand is that it is recommended to use InputMap/ActionMap to avoid all the KeyListeners problems with focus changes etc. I used only InputMap/ActionMap and still it did not help...
So why InputMap does not react only to keyTyped() event ?
But sometimes, maybe 1/20 times, I get "Cc" at the end of the JTextfield !
Random issues are usually the result of threading issues.
All Swing components should be created and modified on the Event Dispatch Thread (EDT).
The code from your main() method is not executed on the EDT which could be the problem.
The code to create the GUI should be wrapped in a SwingUtilities.invokeLater(...).
Check out the Swing tutorial on Concurrency for more information.

Honestly confused on how to apply Swing Timers to my program, can someone take a look?

I was reading about Swing Timers and the example really looks nothing like I was trying to do so I found it logically confusing to apply it to my program. I'm starting to think I don't even need a timer for this.
Here is what I am trying to do:
I am making a JFrame program that has the user enter a credit card number into a JTextField. Before they do this there is a JLabel that says "Please enter your number into the text field", then once they enter this into the field and hit enter, depending on whether my code determines that the card number is valid or not valid, the JLabel will change to "Invalid" or "Thank you, processing."
However, I have unsuccessfully found a way to make it change text based, it just seems to stay with whatever text I initially give it.
So could someone please look at my code and change it to do what I am asking? That would be excellent. You guys have been helpful in the past.
public class CreditGraphics {
public String cardNum;
public JFrame frame;
public JPanel panel;
public JLabel label;
public JTextField text;
public Timer timer;
public CreditGraphics() {
frame = new JFrame("HI");
panel = new JPanel();
label = new JLabel();
text = new JTextField(16);
panel.add(label);
panel.add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(500, 500));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
label.setText("Hi");
label.setText("Hello");
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardNum = text.getText();
timer = new Timer(2000,this);
timer.setInitialDelay(1000);
timer.start();
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CreditGraphics();
}
});
}
public void checkCard(){
}
}
You have some major problems with your Timer's ActionListener as it is adding the anonymous inner ActionListener object, the this in the Timer's constructor, to itself. So it will call the very same actionPerformed inside the Timer that is called by the JButton that starts the Timer -- quite confusing. If your program were to need a Timer, you would do well to make sure to give it its own ActionListener, and not the same ActionListener that you add to your JButton as you're doing now.
Most importantly, do you even need a Swing Timer? I don't think so since you don't appear to be wanting an action repeatedly happening every xxx milliseconds, or an action that occurs once after xxx milliseconds, and since all you want to do is change the text. I suggest that instead you simply change your JLabel's text in the anonymous inner ActionListener class, and just leave it at that. If your requirements are different, then you will want to clarify and expand on your question.
So in semi-pseudocode, something like:
public void actionPerformed(ActionEvent e) {
String userText = text.getText();
if (testIfTextValid(userText)) { // some method to test if input OK
label.setText(INPUT_VALID); // String constant for JLabel to display
// here pass the userText to other parts of your code that needs to use it
} else {
label.setText(INPUT_INVALID);
}
}

JTextField's getText() to printable variable

I've just taken up playing with GUIs, and I'm experimenting with getting text input from the user, and assigning it to a variable for later use.
Easy, I thought. Wrong, I was.
I wanted my frame to look something like:
public class firstFrame extends JFrame {
JTextField f1 = new JTextField();
String text;
public firstFrame(String title) {
super(title);
setLayout(new BorderLayout());
Container c = getContentPane();
c.add(f1);
text = f1.getText();
System.out.println(text);
}
}
Where the variable text would get whatever text the user typed in, then print it out to the console. Simple.
I've got a feeling I'm missing something pretty fundamental here, and would appreciate it if anyone could fill me in on what that something is.
The variable won't be updated until an event occurs on the component. For this a DocumentListener or ActionListener can be used
f1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String text = f1.getText();
...
}
});
getText() only get the text that is in the JTextArea at the time it is called.
You are calling it in the constructor. So when you instantiate new firstFrame, there is no initiital text.
One thing to keep in mind is that GUIs are event driven, meaning you need an event handler to capture and process events.
One option is to add an ActionListener to the JTextField so when you press Enter after entering text, the text will print.
f1.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String text = f1.getText();
System.out.println(text);
}
});
See more at how to Create GUI with Swing and Writing Event Listeners

Java action performed when text is entered into a textarea

I'm wondering if someone can help me out. I entered a character into a text area from a button, and want to use the string entered into the textarea to retrieve words from a list. Bear in mind, there could be numerous characters entered. Is it possible for a text area to detect when text has been entered and to action it?
You can add a DocumentListener to your JTextArea;
class YourClass {
...
public void attachTextAreaToPanel(JPanel panel) {
JTextArea textArea = new JTextArea();
textArea.getDocument().addDocumentListener(new MyDocumentListener());
panel.add(textArea);
}
}
class MyDocumentListener implements javax.swing.event.DocumentListener {
public void changedUpdate(javax.swing.event.DocumentEvent e) {
// text has been altered in the textarea
}
public void insertUpdate(javax.swing.event.DocumentEvent e) {
// text has been added to the textarea
}
public void removeUpdate(javax.swing.event.DocumentEvent e) {
// text has been removed from the textarea
}
}
Edit, this requires that you use Swing - and not AWT.
I assume you are refering to swing JTextArea ?
look at:
http://java.sun.com/docs/books/tutorial/uiswing/components/textarea.html
There is a part that is exactly what you are looking for.
Implements the TextListener for that textarea. Then use the conditions.
Otherwise implements ActionListener to your button. Then specify the action you want, while pressing your button.

Categories