Reputation: 109
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!
Upvotes: 2
Views: 619
Reputation: 57381
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).
Upvotes: 1
Reputation: 28294
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 < I_SubTextField > registeredSubTextAreas = new ArrayList < I_SubTextField > ();
/**
* 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()
Upvotes: 1
Reputation: 3684
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:
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.
Upvotes: 1
Reputation: 1953
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.
Upvotes: 1