Length of Java Swing JTextArea? [duplicate] - java

This question already has answers here:
Enforce max characters on Swing JTextArea with a few curve balls
(3 answers)
Closed 5 years ago.
I have one question, which pops up during coding:
I want to make sure, about this question, so I hope you could help me!
So, I'm thinking about that, is the JTextArea length infinite?
Or how many chars can be used max?
I tried to write it manual, but I got bored, about 5000 lines, and 100 000 chars, so what's the limit on the JTextArea?
I'm working on a chat program, and this is important for me, but I've nowhere found the answer.

So, I'm thinking about that, is the JTextArea length infinite? Or how many chars can be used max?
No, JTextArea is not infinite.
We can imply the maximum length based on the fact that JTextArea only returns a String, which has a length which returns a int. This implies that the maximum length of a JTextArea is bound to Integer.MAX_VALUE, but, because of array overheads, is slightly smaller. But in practice, you'll probably find that it's much smaller, due to the need for arrays to be laid in memory in a continuous manner, so it will depend on how much memory the JVM has available and how fragmented it is.
We can further investigate this and have a look at PlainDocument, which is the default Document used by JTextArea, which uses a char[] as it's internal data structure, just like String.
This further concretes the reasoning that the limit of a JTextArea is limited to less then Integer.MAX_VALUE
You can have a look at Do Java arrays have a maximum size?, Why I can't create an array with large size? and Why the maximum array size of ArrayList is Integer.MAX_VALUE - 8? for discussions on why an array can't be declared as Integer.MAX_VALUE
Now, before someone suggests that you could write a linked list implementation of a Document, don't forget that both Document and JTextArea rely on String, which is a key limiting factor

I'm working on a chat program, and this is important for me
The text area supports at least several bibles worth of text (i.e. 'a lot'). Far more than could ever be read by a casual reader and immensely more than should appear in a 'chat program'.
Here is a small example that shows more than 1.1 million lines of output on the names of Unicode characters:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class HowLongTextArea {
private JComponent ui = null;
HowLongTextArea() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new BorderLayout(4,4));
ui.setBorder(new EmptyBorder(4,4,4,4));
JTextArea ta = new JTextArea(15, 40);
StringBuilder sb = new StringBuilder();
String eol = System.getProperty("line.separator");
for (int ii=0; ii<Character.MAX_CODE_POINT; ii++) {
sb.append((ii+1) + "\t" + Character.getName(ii) + eol);
if (ii%10000==0) {
System.out.println("ii: " + ii);
}
}
ta.setText(sb.toString());
ui.add(new JScrollPane(ta));
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
HowLongTextArea o = new HowLongTextArea();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}

Thanks MadProgrammer for correcting me.
If you would like to set limit of JTextArea:
To implement a document filter, create a subclass of DocumentFilter and then attach it to a document using the setDocumentFilter method defined in the AbstractDocument class. Although it is possible to have documents that do not descend from AbstractDocument, by default Swing text components use AbstractDocument subclasses for their documents.
The TextComponentDemo application has a document filter, DocumentSizeFilter, that limits the number of characters that the text pane can contain. Here is the code that creates the filter and attaches it to the text pane's document:
JTextPane textPane;
AbstractDocument doc;
static final int MAX_CHARACTERS = 300;
...
textPane = new JTextPane();
...
StyledDocument styledDoc = textPane.getStyledDocument();
if (styledDoc instanceof AbstractDocument) {
doc = (AbstractDocument)styledDoc;
doc.setDocumentFilter(new DocumentSizeFilter(MAX_CHARACTERS));
}
source:http://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html#filter

Related

How to detect when a user presses a key outside of the app [duplicate]

This question already has answers here:
Java - checking if parseInt throws exception
(8 answers)
Closed 1 year ago.
So I tried to look a bit in forums and StackOverflow but nothing worked for me I need when enter is pressed to stop my code this is my code `
JFrame f;
JTextField I;
// JButton
JToggleButton b;
// label to display text
JLabel l;
f = new JFrame("AutoClicker");
i = new JTextField("100");
// create a label to display text
l = new JLabel("clicks/seconds");
// create a new buttons
b = new JToggleButton("Start");
// create a panel to add buttons
JPanel p = new JPanel();
// add buttons and textfield to panel
p.add(b);
p.add(i);
p.add(l);
// setbackground of panel
p.setBackground(Color.red);
// add panel to frame
f.add(p);
// set the size of frame
f.setSize(280, 80);
f.setVisible(true);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int jml = Integer.parseInt(i.getText());
if(jml < 50)
{
jml = 50;
}
AutoClicker(jml);
}
});
}
static void AutoClicker(int jml)
{
while(true)
{
try{
Robot r = new Robot();
int button = InputEvent.BUTTON1_DOWN_MASK;
r.mousePress(button);
Thread.sleep(jml);
r.mouseRelease(button);
Thread.sleep(jml);
}
catch(Exception e){
e.printStackTrace();
System.out.println("not good");
}
}
}
}`
I tried to add a KeyListener but it did not work.
I don't understand why it doesn't work so if you can just help me know why it doesn't work it would be much apreciated.
KeyListener isn't going to solve the problem of the fact that you are simply not handling the potential of Integer.parseInt to throw an exception - I mean, how can it convert "" or "This is not a number" to an int. In those cases it throws an exception
The JavaDocs clearly state
Throws:NumberFormatException - if the string does not contain a
parsable integer.
Go back and have a look at the original error you were getting from your previous question on this exact topic
java.lang.NumberFormatException: For input string: "Enter"
It's telling you exactly what the problem is - the text "Enter" can not be converted to an int value.
YOU have to handle this possibility. No offence, but this is honestly basic Java 101. See Catching and Handling Exceptions
Another option which "might" help is to use a formatted text field
You also don't seem to have a firm grip on the concept of what a "event driven environment" is or what the potential risk of what doing something like while (true) will do if executed within the context of the Event Dispatching Thread. This makes me think you've got yourself in over all head.
You're going to want to learn about Concurrency in Swing as AutoClicker should never be called within the context of the Event Dispatching Thread, which is going to lead you another area of complexity, concurrency and all the joys that brings.
Updated
Wow, you changed the title. Maybe a better description of the problem you're trying to solve would have a gotten a better answer. In short, you can't, not natively in Java anyway. The only way you can detect keyboard input out side of the app is using native integration, JNA/JNI. Plenty of examples about, for example

Java Swing GridBagLayout adding components inbetween other components

What i want to achieve: I want to be able to add components to a scrollpane inbetween components already added. In other words, i somehow want to move the index up and plop some new components where the old ones used to be. I created a short program to illustrate my problem, it replace the components it doesnt add them. can someone help?
Why i want to achieve it (to answer the inevitable question related to this, this is long only read if interested): Ive got a scrollpane in which i need to display lots of components, approx 150000 JTables. This takes too much memory and processing time. So what ive done is to load the scrollpane with 150000 TextFields and only displaying 100 of the tables at a time. If you scroll to textfield 200 it loads the next 100 tables, replacing the previously created text fields with the tables. If you move to textfield 300 it loads the next 100 tables, and removes the first 100, again replacing it with textfields. My thinking here is that the textfields are going to be much less resource intensive than the tables, and so far this thinking seems to be correct. So this all seems to work pretty well (on my smaller test file - about 5000 records). The problem is that to create the 150000 textfields also takes lots of time. I thought of a solution for this. To not create a textfield for every table, but to rather create 1 textfield for every 100 tables. The idea is that when you scroll to textfield 2 (instead of 200), it loads the next 100 tables, replacing textfield nr 2 with tables nr 200 - 299. So somehow i need to move textfield 3 and all those below it down in order to insert all the tables. Phew, hope this makes sense
So looking at the example below what i effectively want to achieve is to replace say textfield 20 with 5 new textfields, but not repalce textfields 21 - 25.
import javax.swing.*;
import java.awt.*;
public class Example {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ExampleScreen ex = null;
ex = new ExampleScreen();
ex.setVisible(true);
}
});
}
private static class ExampleScreen extends JFrame{
GridBagConstraints gc = new GridBagConstraints();
JPanel panel = new JPanel(new GridBagLayout());
JScrollPane scrollPane = new JScrollPane(panel);
public ExampleScreen() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.add(scrollPane, BorderLayout.CENTER);
setupFields();
createExtraFieldsInbetween(20);
this.pack();
scrollPane.getVerticalScrollBar().setUnitIncrement(16);
scrollPane.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE);
}
//after this happens i need to add components somewhere in the middle, like after textfield 20 for example
private void setupFields() {
gc.gridy = 0;
gc.gridx = 0;
for(int k = 0; k < 50; k++) {
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(1500,36));
textField.setText(new Integer(k).toString());
panel.add(textField, gc, k);
gc.gridy++;
}
}
//this is to create extra fields inbetween those already created
//this does not work, it overwrites the existing components, doesnt move them up
private void createExtraFieldsInbetween(int i) {
gc.gridy = i;
//create 5 extra
for(int k = i; k < i + 5; k++) {
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(1500,36));
textField.setText("Extra Field : " + new Integer(k).toString());
panel.add(textField, gc, k);
gc.gridy++;
}
}
}
}
Anytime I see a number like 150,000 I think the user can't be bothered to scroll through all those components so you need a better UI.
Anyway if you have a problem with a GridBagLayout, then don't use a GridBagLayout.
It looks to me like you are just displaying the components vertically so try a BoxLayout. Then you can just use the add(...) method to specify the index where you want to remove/add components.

Get a component from a JTextPane through javax.swing.text.Element?

I am using a JTextPane to display characters and symbols, where the latter are represented by custom painted JComponents. For example, the text pane might show something like this:
The text pane is user editable and it is allowed for the user to add more symbols via a button at any position and as a replacement for selected text. I do this via the JTextPane.insertComponent() method. At some point in the application I need to know what is currently being displayed in the text pane, and by that I mean not only the entered text, but also the exact components contained within.
I went through extensive troubles with Positions and DocumentListeners to manage the content of my text pane, but I kept causing more problems than I was solving. That is why I finally decided, that my troubles are probably due to a design fault on my part, so I decided to see, if I can't get to my components through the text pane.
Searching through the documentation and the source code of AbstractDocument and other related classes, I found the interface javax.swing.text.Element. I then let my application output
for(int i = 0; i < textPane.getDocument().getLength(); i++) {
System.out.println(((StyledDocument) textPane.getDocument()).getCharacterElement(i));
}
which gave me:
LeafElement(content) 0,4
LeafElement(content) 0,4
LeafElement(content) 0,4
LeafElement(content) 0,4
LeafElement(component) 4,5
LeafElement(content) 5,9
LeafElement(content) 5,9
LeafElement(content) 5,9
LeafElement(content) 5,9
LeafElement(component) 9,10
Seeing that the LeafElements that I got do seem to have some kind of information about what is displayed at which position in the Document, I figured that it must be possible to get the actual content at that position. After searching for another half hour how to get the content each of the elements represent, I gave up and decided to post my question here, hoping that some of you might know how to accomplish this!?
I have seen this question where someone tries to access the components through textPane.getComponents(), which returns an array of components with the exact number of components actually contained in the JTextPane, but they are all of the type javax.swing.text.ComponentView$Invalidator, which is obviously of no use to me. Maybe I just don't see how to properly continue from here, because a cast to the original type of my symbol doesn't work.
tl;dr
How do I get a JComponent, which is inside the text of a JTextPane, and its position from the text pane?
You can traverse the text pane's StyledDocument to find elements that represent components or icons, as shown below.
BranchElement(section) 0,7
BranchElement(paragraph) 0,7
LeafElement(content) 0,4
LeafElement(icon) 4,5
class javax.swing.plaf.IconUIResource
LeafElement(component) 5,6
class javax.swing.JLabel
LeafElement(content) 6,7
SSCCE:
/**
* #see http://stackoverflow.com/a/15669307/230513
* #see http://stackoverflow.com/questions/2883413
*/
public class DocumentParse {
private static final String ELEM = AbstractDocument.ElementNameAttribute;
private static final String ICON = StyleConstants.IconElementName;
private static final String COMP = StyleConstants.ComponentElementName;
public static void main(String args[]) throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextPane jtp = new JTextPane();
StyledDocument doc = (StyledDocument) jtp.getDocument();
SimpleAttributeSet normal = new SimpleAttributeSet();
StyleConstants.setFontFamily(normal, "Serif");
StyleConstants.setFontSize(normal, 72);
StyleConstants.setForeground(normal, Color.blue);
doc.insertString(doc.getLength(), "Test", normal);
jtp.setSelectionStart(doc.getLength());
jtp.insertIcon(UIManager.getIcon("OptionPane.warningIcon"));
jtp.setSelectionStart(doc.getLength());
jtp.insertComponent(new JLabel("Label"));
jtp.setSelectionStart(doc.getLength());
ElementIterator iterator = new ElementIterator(doc);
Element element;
while ((element = iterator.next()) != null) {
System.out.println(element);
AttributeSet as = element.getAttributes();
if (as.containsAttribute(ELEM, ICON)) {
System.out.println(StyleConstants.getIcon(as).getClass());
}
if (as.containsAttribute(ELEM, COMP)) {
System.out.println(StyleConstants.getComponent(as).getClass());
}
}
f.add(jtp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
The original component is the first (and only) child of the javax.swing.text.ComponentView$Invalidator as you can see from ComponentView.
You can get list of the invalidators and use their children to acccess inserted components.

Refreshing display of a text panel in a GUI

I'm having more "I'm hopeless at programming" problems.
I have a piece of code which uses StringBuilder to display elements of an array in a text panel of a GUI when the program starts. Here's the StringBuilder code:
// memory tab
StringBuilder mList = new StringBuilder();
memLocList = new Memory[MEM_LOCATIONS];
mem = new Memory();
for (int i = 0; i < memLocList.length; i++) {
memLocList[i] = mem;
memLocList[i].setOpCode(00);
mList.append(String.format("%10s %04x %10s %6s", "Address: ", i,
"Value: ", memLocList[i].getOpCode()));
mList.append("\n");
}
JComponent memTab = makeTextPanel(mList.toString());
tabs.addTab("Memory", new JScrollPane(memTab));
}
protected JComponent makeTextPanel(String t) {
text = t;
JPanel panel = new JPanel(false);
JTextPane filler = new JTextPane();
filler.setFont(new Font("Courier", Font.PLAIN, 14));
filler.setText(text);
filler.setAlignmentX(LEFT_ALIGNMENT);
panel.setLayout(new GridLayout(1, 1));
panel.add(filler);
return panel;
}
The GUI also has a text entry panel where a String of hex values can be entered.
On clicking a button, the user is prompted for another value, which corresponds to the position in the array where the first hex value should be inserted.
Once these values have been entered, I'd like the display to be updated / refreshed to reflect this but am unsure of how to go about it.
I found this question here, which is similar but I'm not sure if implementing Observer/Observable pattern is the right way to proceed, and even if it is, how I'd go about it:
Best Way to Constantly Update GUI Elements
My initial approach was to add an "updateDisplay()" method, which I could call after processing the button click and re-call the makeTextPanel method:
public void updateDisplay() {
makeTextPanel(text);
}
I thought this might refresh it but it has no effect of the display.
Any help appreciated.
You hold your array in a model class, and you allow other classes to "listen" to this by giving this class a SwingPropertyChangeSupport object as well as an addPropertyChangeListener(...) method. Then give the array a setXXX(...) method, and in that method fire the SwingPropertyChangeSupport object after updating the array. There are examples of just this sort of thing on this site, some written by me.
For example: here, here, here, ...
By the way, I'm not surprised that your call to makeTextPanel(text) doesn't work. It creates a JPanel, but you don't appear to do anything with the JPanel that is returned from the method. But nor should you. I don't think that creating new JPanels is the solution you want, but rather updating the Strings displayed by a component of some sort such as a JList or JTextArea using the listener framework that I've described above.
If any of this is confusing, please ask for clarification.

Highlighting Text in java

We are developing a plagiarism detection framework. In there i have to highlight the possible plagiarized phrases in the document. The document gets preprocessed with stop word removal, stemming and number removal first. So the highlighting gets difficult with the preprocessed token
As and example:
Orginal Text: "Extreme programming is one approach of agile software development which emphasizes on frequent releases in short development cycles which are called time boxes. This result in reducing the costs spend for changes, by having multiple short development cycles, rather than one long one. Extreme programming includes pair-wise programming (for code review, unit testing). Also it avoids implementing features which are not included in the current time box, so the schedule creep can be minimized. "
phrase want to highlight: Extreme programming includes pair-wise programming
preprocessed token : Extrem program pair-wise program
Is there anyway I can highlight the preprocessed token in the original document????
Thanx
You'd better use JTextPane or JEditorPane, instead of JTextArea.
A text area is a "plain" text component, which means taht although it can display text in any font, all of the text is in the same font.
So, JTextArea is not a convenient component to make any text formatting.
On the contrary, using JTextPane or JEditorPane, it's quite easy to change style (highlight) of any part of loaded text.
See How to Use Editor Panes and Text Panes for details.
Update:
The following code highlights the desired part of your text.
It's not exectly what you want. It simply finds the exact phrase in the text.
But I hope that if you apply your algorithms, you can easily
modify it to fit your needs.
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
public class LineHighlightPainter {
String revisedText = "Extreme programming is one approach "
+ "of agile software development which emphasizes on frequent"
+ " releases in short development cycles which are called "
+ "time boxes. This result in reducing the costs spend for "
+ "changes, by having multiple short development cycles, "
+ "rather than one long one. Extreme programming includes "
+ "pair-wise programming (for code review, unit testing). "
+ "Also it avoids implementing features which are not included "
+ "in the current time box, so the schedule creep can be minimized. ";
String token = "Extreme programming includes pair-wise programming";
public static void main(String args[]) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new LineHighlightPainter().createAndShowGUI();
}
});
} catch (InterruptedException ex) {
// ignore
} catch (InvocationTargetException ex) {
// ignore
}
}
public void createAndShowGUI() {
JFrame frame = new JFrame("LineHighlightPainter demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextArea area = new JTextArea(9, 45);
area.setLineWrap(true);
area.setWrapStyleWord(true);
area.setText(revisedText);
// Highlighting part of the text in the instance of JTextArea
// based on token.
highlight(area, token);
frame.getContentPane().add(new JScrollPane(area), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
// Creates highlights around all occurrences of pattern in textComp
public void highlight(JTextComponent textComp, String pattern) {
// First remove all old highlights
removeHighlights(textComp);
try {
Highlighter hilite = textComp.getHighlighter();
Document doc = textComp.getDocument();
String text = doc.getText(0, doc.getLength());
int pos = 0;
// Search for pattern
while ((pos = text.indexOf(pattern, pos)) >= 0) {
// Create highlighter using private painter and apply around pattern
hilite.addHighlight(pos, pos + pattern.length(), myHighlightPainter);
pos += pattern.length();
}
} catch (BadLocationException e) {
}
}
// Removes only our private highlights
public void removeHighlights(JTextComponent textComp) {
Highlighter hilite = textComp.getHighlighter();
Highlighter.Highlight[] hilites = hilite.getHighlights();
for (int i = 0; i < hilites.length; i++) {
if (hilites[i].getPainter() instanceof MyHighlightPainter) {
hilite.removeHighlight(hilites[i]);
}
}
}
// An instance of the private subclass of the default highlight painter
Highlighter.HighlightPainter myHighlightPainter = new MyHighlightPainter(Color.red);
// A private subclass of the default highlight painter
class MyHighlightPainter
extends DefaultHighlighter.DefaultHighlightPainter {
public MyHighlightPainter(Color color) {
super(color);
}
}
}
This example is based on Highlighting Words in a JTextComponent.
From a technical point of view: You can either choose or develop a markup language and add annotations or tags to the original document. Or you want to create a second file that records all potential plagiarisms.
With markup, your text could look like this:
[...] rather than one long one. <plag ref="1234">Extreme programming
includes pair-wise programming</plag> (for code review, unit testing). [...]
(with ref referencing to some metadata record that describes the original)
You could use java.text.AttributedString to annotate the preprocessed tokens in the original document.
Then apply TextAttributes to the relevant ones (which whould take effect in the original document.

Categories