show character count in swing gui - java

I have a JTextArea called taMessage which displays a message string. This string can be edited by the user at run time.
I have a JLabel lblLength to show the number of characters. I am using lblLength.setText(taMessage.getText().length()+"/ 160"); to display the character count.
What event listener should I use for taMessage so that as I keep typing text in my text area, lblLength keeps on updating itself?
Something like we see in sites like way2sms or 160by2, where it shows the number of characters left.

Swing text fields and text areas are backed by a class called Document that can have a Document Listener attached to it.
The official docs have a decent tutorial on Document Listeners.
You would want to attach the document listener, and since you're interested in character counts then you'd simply want to use the same code you used above to initialize the label in all three of the Document Listener's callback methods.

In an MVC like way you can listen to the document's change.
JTextArea ta = ...;
JLabel lblLength = ...;
Document taDoc = ta.getDocument();
taDoc.addDocumentListener(new CharacterCounterDocumentListener(lblLength))
public class CharacterCounterDocumentListener implements DocumentListener {
private JLabel counterLabel;
public CharacterCounterDocumentListener(JLabel counterLabel){
this.counterLabel = counterLabel;
}
public void changedUpdate(DocumentEvent e) {
Document d = e.getDocument();
int length = d.getLength();
counterLabel.setText(Integer.toString(length));
}
public void insertUpdate(DocumentEvent e) {
}
public void removeUpdate(DocumentEvent e) {
}
}

A DocumentListener is probably your best bet. You don't even need to create a new class, you can just define it inline.
// Listen for changes in the text
taMessage.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
update();
}
public void removeUpdate(DocumentEvent e) {
update();
}
public void insertUpdate(DocumentEvent e) {
update();
}
public void update() {
lblLength.setText(taMessage.getText().length()+"/ 160");
}
});

Related

How to detect changes in text in many JTextPane

I would like to create simply text editor with dynamic amount of tabs. Every tab consist of text field, where someone can load text file and edit or write own text.
I would like to detect changes in tabs, I mean when someone change file and wants close then I'd like to show a dialog about whether you want save changes or no. this is reason why I'd like to follow changes which user committed.
So I have
JTabbedPane tabbedPane with JtextPane textPane
private LinkedList<Boolean> changedList = new LinkedList<Boolean>(); // here I thought of collecting information about changes but it was silly idea.
This is function which I create new Tab
public void newTab()
{
tabbedPane.addTab("tab-" + counter++, new JTextPane());
int totalTabs = tabbedPane.getTabCount();
selected = tabbedPane.getComponentAt(totalTabs-1);
changedList.add( totalTabs-1, false);
textPane = (JTextPane)selected;
textPane.getDocument().addDocumentListener(this);
}
these are function from interface
#Override
public void insertUpdate(DocumentEvent e)
{
changedList.add(tabbedPane.getSelectedIndex(), true);
}
#Override
public void removeUpdate(DocumentEvent e)
{
changedList.add(tabbedPane.getSelectedIndex(), true);
}
#Override
public void changedUpdate(DocumentEvent e)
{
changedList.add(tabbedPane.getSelectedIndex(), true);
}
This is how I've tried to save
public void saveAfterChange()
{
if (changedList.get(tabbedPane.getSelectedIndex()))
{
int reply = JOptionPane.showConfirmDialog(null, "Save?", null, JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_NO_OPTION)
{
save();
}
}
}

Need my GUI to read from a JTextField and show in a JPanel

I have added an action listener to the text field. When the btnReadString (Button Read String) is pressed the program should read what is on the text field and show on the JPanel. but nothing shows on the panel.
stringTextField.addActionListener(new ActionListener() {
public void stringTextField (java.awt.event.ActionEvent e) {
if(e.getSource()==btnReadString) //when the button is pressed
{
String stringParameter = stringTextField.getText(); //gets the text and puts it on this string called "stringParameter"
textPane.setText(stringParameter);//the JPanel is set to what is on the string.
}
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
});
The functionality for the ActionListener should go in the actionPerformed method, as nothings calling the stringTextField method...
stringTextField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btnReadString) //when the button is pressed
{
String stringParameter = stringTextField.getText(); //gets the text and puts it on this string called "stringParameter"
textPane.setText(stringParameter);//the JPanel is set to what is on the string.
}
}
});
But, based on the code, the ActionListener should be attached to the btnReadString and not the field, as the above logic will never result in anything been executed (as the source of the event will never be btnReadString)
btnReadString.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String stringParameter = stringTextField.getText(); //gets the text and puts it on this string called "stringParameter"
textPane.setText(stringParameter);//the JPanel is set to what is on the string.
}
});
I would suggest having a closer look at How to Write an Action Listener and How to Use Buttons, Check Boxes, and Radio Buttons for more details
You have added the ActionListener to the text field. So the event source is never going to be the button and hence, the code is never going to execute. What you want is to add the ActionListener to the JButton.
Also, the actionPerformed() is there for a reason. All your 'action' code goes inside this method.
So your code should look like this:
btnReadString.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String stringParameter = stringTextField.getText();
textPane.setText(stringParameter);
}
});

Higlight text in JTextField but only when tabbing

I want to create a JDialog where the text in the textfields is selected but only if the focus is gained from keyboard (TAB, CTRL+TAB). I have found several topics on this matter but had problems with implementing it.
Here is one which I was trying.
And my code:
public class Dialogg extends JDialog implements FocusListener, MouseListener {
private boolean focusFromMouse = false;
public Dialogg() {
JTextField tf1 = new JTextField("text1");
JTextField tf2 = new JTextField("text2");
tf1.addMouseListener(this);
tf2.addMouseListener(this);
tf1.addFocusListener(this);
tf2.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
if (!focusFromMouse) {
JTextField tf = (JTextField) e.getComponent();
tf.selectAll();
focusFromMouse = true;
}
}
#Override
public void focusLost(FocusEvent e) {
focusFromMouse = false;
}
#Override
public void mouseClicked(MouseEvent e) {
focusFromMouse = true;
}
}
It does not work as intended, it does not matter what is focus source the text always highlights. When I run the code and follow it step by step it turns out that focusGained code happens before mouseClicked code so the flag is not reset when it should. Any hints?
EDIT:
As suggested by M. Prokhorov I have deleted less relevant (for the question) lines from the code.Thank you.
EDIT 2:
I am trying to wrap focus listener as suggested by camickr. It looks like this now:
tf1.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (!focusFromMouse){
tf1.selectAll();
focusFromMouse=true;
}
}
});
}
public void focusLost(FocusEvent evt){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
focusFromMouse=false;
}
});
}
});
public void mouseClicked(MouseEvent e) {
focusFromMouse=true;
I am printing line after each event to see the action order and still mouseClicked happens last. What am I doing wrong?
EDIT 3:
OK, I have found a solution which fulfils requirements of my simple Dialog.
I could not find a way of doing this with use of invokeLater or EventQueue. Vladislav's method works but as I understand it restricts the user to only use the keyboard.
I have used the initial approach but I have added an auxiliary variable and few conditions which allow to pass the flag "unharmed" trough Events that should not change the flag at given moment. It may not be subtle or universal but works for my app. Here is the code:
public void focusGained(FocusEvent e) {
if(!focusFromMouse){
if (higlight){
JTextField tf = (JTextField) e.getComponent();
tf.selectAll();
focusFromMouse=false;
}
}
}
public void focusLost(FocusEvent e) {
if (focusFromMouse){
higlight=false;
focusFromMouse=false;
}else{
higlight=true;
}
}
public void mousePressed(MouseEvent e) {
focusFromMouse=true;
}
At the first, by default, focus on JTextField is requested by mouse-press event, not by mouse-click.
So, this method:
public void mouseClicked(MouseEvent e) {
focusFromMouse = true;
}
is useless because the mouse-click event is triggered after the mouse-press event.
One way to solve your problem is to remove all native MouseListeners from JTextField:
...
for( MouseListener ml : tf1.getMouseListeners() ){
tf1.removeMouseListener(ml);
}
for( MouseMotionListener mml : tf1.getMouseMotionListeners() ){
tf1.removeMouseMotionListener(mml);
}
...
Another way is to handle all mouse events and consume those of them, which are triggered by JTextField:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if( event.getSource() == tf1 ){
((MouseEvent)event).consume();
}
}
}, AWTEvent.MOUSE_EVENT_MASK);
When I run the code and follow it step by step it turns out that focusGained code happens before mouseClicked
Wrap the code in the FocusListener in a SwingUtilities.invokeLater(). The will place the code on the end of the Event Dispatch Thread (EDT), so the code will run after the variable in the MouseListener has been set.
See Concurrency in Swing for more information about the EDT.
Edit:
Just noticed the other answer. You might be able to do something simpler. Istead of listener for mouseClicked, listen for mousePressed. A mouseClicked event is only generated AFTER the mouseReleased event, so by that time the FocusListener logic has already been executed, even when added to the end of the EDT.
Edit 2:
If the above doesn't work then you might be able to use the EventQueue.peek() method to see if a MouseEvent is on the queue. This might even be easier than worrying about using the invokeLater.

Clicking the textfield and clear the text?

Is it possible that when I clicked the textfield it would clear the recent text that was inputed there?. Mine was like, suppose these are textfields.
Name: Last Name First Name Middle Initial
Then I would click the Last Name and it would be cleared, same as First Name and Middle Initial. thanks for reading, hope you can help me.
Consider a FocusListener, one where all the text is selected:
myTextField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fEvt) {
JTextField tField = (JTextField)fEvt.getSource();
tField.selectAll();
}
});
By selecting all of the text, you give the user the option of either typing and thus deleting the current text and replacing it with the new text, or using the mouse or arrow keys to keep the current text and possibly change it.
I think Hovercraft is right. Better to use a FocusListener for this purpose.
I would write a utility class that could deal with this, I've done something similar for auto select. Means I don't have to extend every text component that comes along or mess around with lost of small focus listeners that do the same thing.
public class AutoClearOnFocusManager extends FocusAdapter {
private static final AutoClearOnFocusManager SHARED_INSTANCE = new AutoClearOnFocusManager();
private AutoClearOnFocusManager() {
}
public static AutoClearOnFocusManager getInstance() {
return SHARED_INSTANCE;
}
#Override
public void focusGained(FocusEvent e) {
Component component = e.getComponent();
if (component instanceof JTextComponent) {
((JTextComponent)component).setText(null);
}
}
public static void install(JTextComponent comp) {
comp.addFocusListener(getInstance());
}
public static void uninstall(JTextComponent comp) {
comp.removeFocusListener(getInstance());
}
}
Then you just need to use
JTextField textField = new JTextField("Some text");
AutoClearOnFocusManager.install(textField);
If you're just looking to supply a "prompt" (text inside the field that prompts the user), you could also look at the Prompt API
Why don't use the mouseClicked event?
So, you can have something like
jTextFieldMyText.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jTextFieldMyTextMouseClicked(evt);
}
});
private void jTextFieldMyTextMouseClicked(java.awt.event.MouseEvent evt) {
jTextFieldMyText.setText("");
}
In the case of focus
jTextFieldMyText.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
jTextFieldMyTextFocusGained(evt);
}
});
private void jTextFieldMyTextFocusGained(java.awt.event.MouseEvent evt) {
jTextFieldMyText.setText("");
}
If deleting text inmediatelly isn't what's wanted, use selectAll() instead of setText("") as suggested many times

How to know whether any changes in the jtextarea have been made or not?

I've created a jtextarea where a user can modify its content. I want to know,if there is any way, whether the user has modified its content or not before closing the application. Please help.
-Thanks in advance
You need to add a DocumentListener to the Document that backs the text area.
Then in the callback methods (insertUpdate(), removeUpdate(), changedUpdate()) of the listener, simply set a flag that something has changed and test that flag before closing the application
public class MyPanel
implements DocumentListener
{
private boolean changed;
public MyPanel()
{
JTextArea textArea = new JTextArea();
textArea.getDocument().addDocumentListener(this);
.....
}
.....
public void insertUpdate(DocumentEvent e)
{
changed = true;
}
public void removeUpdate(DocumentEvent e)
{
changed = true;
}
public void changedUpdate(DocumentEvent e)
{
changed = true;
}
}
Save the value of jtextarea and compare this value to the value of jtextarea in the moment of application closing.
Pseudocode here, doesn't remember the excact syntax of text area:
String oldText = textarea.getText();
....
// not the exact method, just to point the moment of application exit
public onClose() {
String newText = textArea.getText();
// assuming oldText is not null
if (oldText.equals(newText)) {
// no changes have been done
} else {
// the value changed
}
}

Categories

Resources