JTextField show '...' when content is too long - java

I'm trying to make JTextField display dots when its content is longer then display area. I would like to have the same behaviour like in JTable, where when I resize column the text inside changes - when its to long only begining of it is displayed and then there are three dots (to see what I have in mind please run first example from this link and change column size - I'm not allowed to post images because I'm new here;) )
Is is possible? Only solution that I have in mind is extending JTextField with a class that will have additional field oryginalText and will behave like that (didn't test it, it's just a proposal, dimension of the JtextField will not change):
import javax.swing.JTextField;
public class MyTextField extends JTextField {
private String oryginalText;
private int length;
#Override
public void setText(String text) {
oryginalText = text;
if (oryginalText.length() > length)
super.setText(oryginalText.substring(0, length - 2) + "..");
else
super.setText(oryginalText);
}
}
any ideas?

Over your idea of extending JTextField and storing the original (non trimmed) value:
Show the textfield as disabled (or not editable) and with trimmed text. When the user clics the textfield make it enabled/editable and show the whole original text.
Then again when the user press enter or the focus exits of the textfield: disable/not editable and trimmed text.

Related

EventListener Performed by case

I would like to know the best way to approach what I am trying to achieve, I can't figure out the logical path I should take.
I have a JTextField and a JTextButton, when input is added to the JTextField and either enter or the button is pressed, it will display on the JTextArea. Now, what I want is to choose when and what the JTextArea and Button do.
For example I want default Enter & Button to display next append text in my code. Then when a case is presented I want the JTextField to only accept either int or string and then once completed, I want it to go back to default.
I don't know if what I am trying to do is logical or best practice...
The idea behind this is, I have a story text based gui game. I want it to display text to the JTextArea and when Enter or button is pressed to display the next line of text and when in the story it requires user input, the JTextArea will look for that input.
So far I have an EventListener and ActionListener which submits what I type from JTextField to JTextArea, but that is about it.
Thanks for your assistance! I have solved my issue, not sure if this is the "Best Solution". I combined your solution with a bit of tweaking.
In this instance, buttonState is an int which can be changed throughout my code by calling a constructor "setButtonState". I could have made buttonState a static to make things easier, but thought I could keep things clean.
enterButton.addActionListener(new ActionListener()
{ //This is used so when the enter screen button is pressed, it will submit text from text field to text area.
public void actionPerformed(ActionEvent e) {
String text = inputTextField.getText();
InputTextFieldEvent event = new InputTextFieldEvent(this, text);
if (buttonState == 0) //Displays all text in JTextField to JTextArea, mostly for testing purposes.
{
if (textInputListener != null) {
textInputListener.setInputListenerOccurred(event);
}
}
if (buttonState == 1) //Only accepts string for answer
{
if (inputTextField.getText().matches("[a-zA-Z]+"))
{
textInputListener.setInputListenerOccurred(event);
}
else
{
getAppendMainTextArea("You have entered an invalid input, only letters are allowed.");
}
}
if (buttonState == 2) //Only accepts int for answer
{
if (inputTextField.getText().matches("[0-9]+"))
{
textInputListener.setInputListenerOccurred(event);
}
else
{
getAppendMainTextArea("You have entered an invalid input, only numbers are allowed.");
}
}
}
});

How to make a textarea filled with text (label) every time the button pressed?

I'm trying to make a text area record that every time the button is press, it means that it has been recorded and should be showing record1, record2, record3, etc. on it.
My goal is that, every button is pressed it will add text to the text area with different text label so that no redundancy.
I tried it with my own with this:
private void btnReqstRefreshActionPerformed(java.awt.event.ActionEvent evt) {
JLabel labelthis = new JLabel("record1");
label.setSize(label.getPreferredSize());
TextArea1.add(label);
TextArea1.revalidate();
TextArea1.repaint();
}
I know it is wrong, but is it possible?
text area is like a mini text editor - you add text to it not other components. Instead of adding labels - just add the text. Something like:
TextArea1.setText(TextArea1.getText() + "record1")
This should append record1 to the existing text in the text area.
According to my experience this is possible.
`private void btnReqstRefreshActionPerformed(java.awt.event.ActionEvent evt) {
i++;//i class level variable(static) to avoid redundancy
//labelThis initialized earlier should be accessible here
String oldText = labelThis.getText().toString();
oldText += "record "+i;
labelThis.setSize(labelThis.getPreferredSize());
TextArea1.add(labelThis);
TextArea1.revalidate();
TextArea1.repaint();
}`

using LayoutClickListener to terminary replace components

I have grid layout witch some fields added like that:
private Component userDetailsTab(final User user) {
final GridLayout details = new GridLayout(2, 1);
details.setMargin(true);
details.setSpacing(true);
details.addComponent(createDetailLabel(Messages.User_Name));
final Component username = createDetailValue(user.getName());
details.addComponent(username);
...
I have also Layout click listener which replace labels on text field, it looks like that:
final TextField tf = new TextField();
details.addListener(new LayoutClickListener() {
private static final long serialVersionUID = -7374243623325736476L;
#Override
public void layoutClick(LayoutClickEvent event) {
Component com = event.getChildComponent();
if (event.getChildComponent() instanceof Label) {
Label label = (Label)event.getChildComponent();
details.replaceComponent(com, tf);
tf.setValue(label.getValue());
}
}
});
In future I want to enable click on label, edit it and write changes to database after clicking somewhere else (on different label for example).
Now when I click on 1st label and then on 2nd label, effect is: 1st has value of 2nd and 2nd is text field witch value of 2nd. Why it's going that way? What should i do to after clicking on 1st and then 2nd get 1st label witch value of 1st?
You don't need to swap between Labels and TextFields, you can just use a TextField and style it look like a Label when it's not focused.
When I tried to create click-to-edit labels, it created a ton of extra work for me. I'd discourage it (and do as Patton suggests in the comments).
However, if you're going to insist on trying to create in-place editing, you will want to do the following:
Create a new class that extends a layout (e.g. HorizontalLayout), which can swap out a label for a text field
use LayoutClickListener to removeComponent(myLabel) and addComponent(myTextField)
use BlurListener to swap back to the label
use ValueChangeListener on the text field to copy its value to the label
This is a still a bad idea because:
Users cannot see affordances as easily (they can't tell what's editable)
Users cannot use the keyboard to tab to the field they want to edit
It adds unncessary complexity (maintenance time, etc).
I would recommend, if you want in-place editing, just show the text field, and save the new value with the BlurListener.

connecting two JTextAreas in java (updating)

I have a large JTextArea where users can input a bunch of text. My program allows users to select some text and create smaller JTextAreas with the selected text for closer analysis (editing, etc).
The users can update the larger or smaller JTextAreas and when they do, I want the other to update to this new text as well.
My problem is getting the text in the large JTextArea and the smaller ones to reference each other. Is there a good way of doing this? I am having a difficult time splitting up the large text area and using document listeners at the same time. It becomes difficult when there is an overlap of text from the smaller text areas..
ex.
"large text area"
Hello. My name is Matthieu and I am getting frustrated with all these text boxes :p.
"smaller text areas"
Hello.
all these text boxes :p.
text boxes :p.
if I change "text boxes" to "apple" in 2, then box 3 and the full text should update accordingly!
This is probably not what you want to hear, but that sounds like a very bad idea... The first reason is the fact that it is very complicated to manage in the code and design. The second reason is that it makes it more complex for the user to use...
If you really want to implement it this way, I would say the best way would be to keep a list of snippets that are being edited, and add an item to that list that contains the starting index, the original text and which textbox it is being edited in.
Then whenever any changes are made in any textbox, run a method to make the changes to all the textboxes and also updates all the items in the list with updated original text and starting indexes.
I honestly can't see a simple way to do this, and the more textboxes you have, the slower it will get as well.
A much better design in my opinion would be something like a JEditorpane to just display the text (As the big textbox) showing the static text, with a single textbox that displays the selected text and allows editing. This makes the coding pretty trivial, but (Possibly even more importantly), it makes the user interface much simpler and cleaner.
Without knowing exactly why you need this, i can't be sure that the second way would be better, but I would rather use a simpler app as a user.
This could be very difficult, depending on what you want the end result to be. It looks to me like you'd need to track the selection beginning and ending along with each of the boxes. As the text is changed in #2, you could replace the original long text starting at the #2 start index and ending at the end index. That could be ok.
Where I see a problem is if you do something like insert "dumb" in the middle of #2. How would you handle that in #3? Would you shift the start index of #3 to compensate, or would you shift the text that #3 is referencing so it says "dumb test b"?
Before you code this more, I think you should logically work through what you want to happen for, at the least:
inserting characters
deleting characters
changing characters
And probably handle it on a character by character basis with your listeners. It all depends on what you want the end result to be.
All you need to do is subclass the JTextArea and use an interface. The interface can be used to let the sub text areas know that the main text area has been updated.
You will need two subclasses. One will be the main text area, the other will be for the sub panels. Have the sub panels implement an interface so when the parent is updated, they receive the data. Then they can process it how they choose.
The sub text areas are registered with the main text area
Here is a working example:
Main.java
This runs the demo
package Text;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
/**
*
* #author dvargo
*/
public class Main
{
public static void main(String [] args)
{
//build the main text area
JFrame mainFrame = new JFrame();
mainFrame.setSize(700,700);
mainFrame.setTitle("Main Frame");
mainFrame.setLayout(new GridLayout());
//build a sub text area
JFrame subFrameA = new JFrame();
subFrameA.setTitle("Sub Frame A");
subFrameA.setSize(300,300);
subFrameA.setLayout(new GridLayout());
subFrameA.setLocation(mainFrame.getX() + mainFrame.getWidth() + 25, mainFrame.getY());
//build another sub text area
JFrame subFrameB = new JFrame();
subFrameB.setTitle("Sub Frame b");
subFrameB.setSize(300,300);
subFrameB.setLayout(new GridLayout());
subFrameB.setLocation(subFrameA.getX() + subFrameA.getWidth() + 50, subFrameA.getY());
//this is the main text area. Anything typed into here will be sent to the sub text areas
TextField mainTextField = new TextField("Type here and text will appear in the sub frames!!!");
//this sub text area will just mirror the main text area
SubTextField subTextFieldA = new SubTextField();
//this sub text area will add a "-" to the begining of every line
SubTextField subTextFieldB = new SubTextField()
{
#Override
public void update(String text, char lastPressedChar)
{
super.update("- " + text.replace("\n", "\n- "),lastPressedChar);
}
};
//register the sub text areas with the main text areas
mainTextField.register(subTextFieldA);
mainTextField.register(subTextFieldB);
//add them to their frames
mainFrame.add(new JScrollPane(mainTextField));
subFrameA.add(new JScrollPane(subTextFieldA));
subFrameB.add(new JScrollPane(subTextFieldB));
//make everything visible
mainFrame.setVisible(true);
subFrameA.setVisible(true);
subFrameB.setVisible(true);
}
}
I_SubTextField.java
Interface for all sub text areas to implement
package Text;
/**
* Interface to implement to be notified when the text has changed
* #author dvargo
*/
public interface I_SubTextField
{
public void update(String text, char lastChar);
}
TextField.java
Use this as your main text area
package Text;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextArea;
/**
* Text area
* #author dvargo
*/
public class TextField extends JTextArea
{
//holds all registered sub text areas that are registered for updates
List &lt I_SubTextField &gt registeredSubTextAreas = new ArrayList &lt I_SubTextField &gt ();
/**
* Default constructor
*/
public TextField()
{
this("");
}
/**
* Constructor
* #param text Sets this text area to display this text
*/
public TextField(String text)
{
super(text);
addListener();
}
/**
* Registers a sub text area to get updates when this text area is updated
* #param subTextArea
*/
public void register(I_SubTextField subTextArea)
{
registeredSubTextAreas.add(subTextArea);
}
/**
* Unregisters a sub text area to stop receiving updates
* #param subTextField
*/
public void unRegister(I_SubTextField subTextField)
{
registeredSubTextAreas.remove(subTextField);
}
/**
* Notifies all registered classes when the data in the main window has changed
*/
private void addListener()
{
addKeyListener(new java.awt.event.KeyAdapter()
{
public void keyReleased(java.awt.event.KeyEvent evt)
{
for (I_SubTextField registeredField : registeredSubTextAreas)
{
registeredField.update(TextField.this.getText(), evt.getKeyChar());
}
}
});
}
}
SubTextField.java
Use this for all sub text areas
package Text;
/**
* Represents a sub text area. This can be registered with a TextField to be notified
* when the data has been updated
* #author dvargo
*/
public class SubTextField extends TextField implements I_SubTextField
{
/**
* Default constructor
*/
public SubTextField()
{
super();
}
/**
* Constructor
* #param text Text to display in the text area
*/
public SubTextField(String text)
{
super(text);
}
/**
* Called when the parent TextField is updated. Handle the text as you want
* #param text The text for the main parent
* #param lastPressedChar The last char the user pressed
*/
public void update(String text, char lastPressedChar)
{
setText(text);
}
}
Notice that the SubTextField is a sub class of TextField so you can register additional SubTextFields to a SubTextField.
You can set them up to register with each other and send the unprocessed text to each other. Then each SubTextField can process the text the way it wants. All y ou need to do is override the update()
I would use the same model (Document) in all the text areas. Try to override the View used in JTextArea to show only desired fragment. (See PlainView sources).

Example text in JTextField

I am looking for a way to put example text into a swing JTextField and have it grayed out. The example text should then disappear as soon as any thing is entered into that text field. Some what similar to what stackoverflow does when a user is posting a question with the title field.
I would like it if it was already a extended implementation of JTextField so that I can just drop it in as a simple replacement. Anything from swingx would work. I guess if there is not an easy way to do this my option will probably be to override the paint method of JTextField do something that way maybe.
Thanks
The Text Prompt class provides the required functionality without using a custom JTextField.
It allows you to specify a prompt that is displayed when the text field is empty. As soon as you type text the prompt is removed.
The prompt is actually a JLabel so you can customize the font, style, colour, transparency etc..:
JTextField tf7 = new JTextField(10);
TextPrompt tp7 = new TextPrompt("First Name", tf7);
tp7.setForeground( Color.RED );
Some examples of customizing the look of the prompt:
If you can use external librairies, the Swing components from Jide software have what you are looking for; it's called LabeledTextField (javadoc) and it's part of the JIDE Common Layer (Open Source Project) - which is free. It's doing what mklhmnn suggested.
How about initialize the text field with default text and give it a focus listener such that when focus is gained, if the text .equals the default text, call selectAll() on the JTextField.
Rather than overriding, put a value in the field and add a KeyListener that would remove the value when a key stroke is registered. Maybe also have it change the foreground.
You could wrap this up into your own custom JTextField class that would take the default text in a constructor.
private JLabel l;
JPromptTextField(String prompt) {
l = new JLabel(prompt, SwingConstants.CENTER);
l.setForeground(Color.GRAY);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (this.getText().length() == 0) {
// Reshape the label if needed, then paint
final Rectangle mine = this.getBounds();
final Rectangle its = l.getBounds();
boolean resized = (mine.width != its.width) || (mine.height != its.height);
boolean moved = (mine.x != its.x) || (mine.y != its.y);
if (resized || moved)
l.setBounds(mine);
l.paint(g);
}
}
You can't do that with a plain text field, but you can put a disabled JLabel on top of the JTextField and hide it if the text field gets the focus.
Do it like this:
Define the string with the initial text you like and set up your TextField:
String initialText = "Enter your initial text here";
jTextField1.setText(initialText);
Add a Focus Listener to your TextField, which selects the entire contents of the TextField if it still has the initial value. Anything you may type in will replace the entire contents, since it is selected.
jTextField1.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
if (jTextField1.getText().equals(initialText)) {
jTextField1.selectAll();
}
}
});

Categories