Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Newbie] JTextArea.append() in loop - nothing happens ...

336 views
Skip to first unread message

Robert Ludewig

unread,
Feb 20, 2003, 7:05:02 AM2/20/03
to
Hello,

In the following code the content of a file is written into a JTextArea.
Unfortunatedly when the file is very large I have to wait for a long time
until something can be seen in the Textarea. Why is that so? In the loop I
wrote .append() - shouldn't the 10-byte-piece that was read (and appended)
be shown right away? And after that read the next piece and so on? So the
textarea gets filled step by step? Why is it not working this way and what
do I have to do to achieve this kind of "streaming"?
public class StreamTest2 extends JPanel
{
JScrollPane s;
JLabel l;
JPanel p;
JFrame f;
JTextArea t;
JButton b;
JFileChooser fc;
FileInputStream fi;
byte[] buff = new byte[10];
public StreamTest2()
{
l = new JLabel("Status");
f = new JFrame("StringTest2");
p = new JPanel();
t = new JTextArea();
b = new JButton("get File");
fc = new JFileChooser(new File("C:\\temp"));
s=new JScrollPane (t);
b.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (fc.showOpenDialog(f) == JFileChooser.APPROVE_OPTION)
{
try
{
fi = new FileInputStream(fc.getSelectedFile());
}
catch (FileNotFoundException ex)
{
l.setText("Konnte Datei " + fc.getSelectedFile()
+"nicht öffnen !");
}
l.setText("Datei \"" + fc.getSelectedFile() + "\"");
int read = 0;
do
{
try
{
read=fi.read(buff);
}
catch (IOException ex1)
{
l.setText(ex1.toString());
}
t.append(new String(buff,0,read));
}while (read>=10);
}
}
});
p.setLayout(new BorderLayout());
p.add(s, BorderLayout.CENTER);
p.add(b, BorderLayout.NORTH);
p.add(l, BorderLayout.SOUTH);
f.setSize(300, 500);
f.getContentPane().add(p);
f.show();
}
}


Mark Hansen

unread,
Feb 20, 2003, 9:25:08 AM2/20/03
to
Robert Ludewig wrote:
> Hello,
>
> In the following code the content of a file is written into a JTextArea.
> Unfortunatedly when the file is very large I have to wait for a long time
> until something can be seen in the Textarea. Why is that so? In the loop I
> wrote .append() - shouldn't the 10-byte-piece that was read (and appended)
> be shown right away? And after that read the next piece and so on? So the
> textarea gets filled step by step? Why is it not working this way and what
> do I have to do to achieve this kind of "streaming"?

Remember that there are two main parts to getting something displayed.
First, is the change to the Data of the component, which you are doing
by calling "t.append(...)". Second is the the redrawing of the GUI
components, which is managed by the Event Dispatch Thread (EDT).

Because your loop never allows the EDT to do any of it's work, nothing
is displayed until the loop if finished, and control returns to the
EDT.

This is a prime example of when to use a "worker" thread. The correct
logic would look something like this:

... from the actionPerformed method
- set up the application to indicate that work is progressing, perhaps
by putting up a wait cursor, disabling the button, etc.
- launch a thread that will do the actual work
- from the new thread, you can update the GUI components using the
SwingUtilities.invokeLater() method
- when the worker thread is finished, it can re-enable the application
by resetting the cursor, re-enabling the button, etc. - again, using
the SwingUtilities.invokeLater() method.

It is important to realize that you must not (in most cases) modify
the GUI components from any thread other than the Event Dispatch Thread,
as these methods are not thread safe.

There are good examples of doing this on the Sun Java web site. For
one example, see:

<http://developer.java.sun.com/developer/technicalArticles/Threads/swing/>

Thomas Weidenfeller

unread,
Feb 20, 2003, 10:04:55 AM2/20/03
to
"Robert Ludewig" <schwertfis...@gmx.de> writes:
> In the following code the content of a file is written into a JTextArea.
> Unfortunatedly when the file is very large I have to wait for a long time
> until something can be seen in the Textarea. Why is that so?

This is an FAQ. You might want to search an archive of this group for
detailed explanations. In short, you are blocking the EDT. Use a
separate thread (implement a Runnable) and in that thread use yet
another Runnable with invokeLater() to update the display while loading
the file.

But there are more problems in your code:

> l = new JLabel("Status");
> f = new JFrame("StringTest2");
> p = new JPanel();
> t = new JTextArea();
> b = new JButton("get File");
> fc = new JFileChooser(new File("C:\\temp"));
> s=new JScrollPane (t);

You might want to work on your coding style and use meaningful variable
names instead of single letter names.

> fi = new FileInputStream(fc.getSelectedFile());

(a) Since you are reading text files, use a FileReader instead.
FileInputStream, like all xxxStream classes, is for binary data.

(b) At least wrap the FileInputStream in a BufferedInputStream. If you
follow the advice of using a FileReader, wrap the FileReader in a
BufferedReader. Not doing so makes the file reading extremely
slow. We are talking about some 100 or some 1000 times slower,
depending on your platform, OS, hard disk, etc.

> do
> {
> try
> {
> read=fi.read(buff);
> }
> catch (IOException ex1)
> {
> l.setText(ex1.toString());
> }
> t.append(new String(buff,0,read));
> }while (read>=10);
>

> }while (read>=10);

The whole loop logic is wrong.

(a) A read() might return less characters than the size of the
buffer you provide, while still not being at EOF at all. A read is
even allowed to return with 0 bytes read. The only valid test in
your case is to test agains EOF and not 10, which is indicated by
-1.

(b) In case of read() returning -1 for EOF you are trying to create a
String of length -1 in the call to append().

The classic idiom for such a loop looks something like:

while((read = fi.read(buff)) != -1) {
// do something with the data
}

> f.show();

No pack()?

/Thomas

Andrew Thompson

unread,
Feb 20, 2003, 10:15:57 AM2/20/03
to
"Robert Ludewig" <schwertfis...@gmx.de> wrote in message
news:b32gjr$1fveao$1...@ID-140548.news.dfncis.de...

> Hello,
>
> In the following code the content of a file is written into a JTextArea.
> Unfortunatedly when the file is very large I have to wait for a long time
> until something can be seen in the Textarea. Why is that so? In the loop I
> wrote .append() - shouldn't the 10-byte-piece that was read (and
appended)
> be shown right away? And after that read the next piece and so on? So the
> textarea gets filled step by step? Why is it not working this way and what
> do I have to do to achieve this kind of "streaming"?

There are people who post here that are far mar
experienced with either IO or FUI components,
but I will make a few suggestions based upon my
limited knowlege..

> public class StreamTest2 extends JPanel
> {
> JScrollPane s;
> JLabel l;
> JPanel p;
> JFrame f;
> JTextArea t;
> JButton b;
> JFileChooser fc;
> FileInputStream fi;
> byte[] buff = new byte[10];

these are very small chunks of data to be reading, see below

> public StreamTest2()
> {
> l = new JLabel("Status");
> f = new JFrame("StringTest2");
> p = new JPanel();
> t = new JTextArea();
> b = new JButton("get File");
> fc = new JFileChooser(new File("C:\\temp"));
> s=new JScrollPane (t);
> b.addActionListener(new ActionListener()
> {
> public void actionPerformed(ActionEvent e)
> {
> if (fc.showOpenDialog(f) == JFileChooser.APPROVE_OPTION)
> {
> try
> {
> fi = new FileInputStream(fc.getSelectedFile());
> }
> catch (FileNotFoundException ex)
> {
> l.setText("Konnte Datei " + fc.getSelectedFile()
> +"nicht öffnen !");
> }

OK. If your call to fi = new FileInputStream(fc.getSelectedFile());
fails it throws an exception which has already been 'catch'ed above..

Your references to 'fi' below will be attempting to
work with a 'null' object. AFAIK, all that code
needs to be inside the same brackets as your 'try'
to work as it's usually used..

> l.setText("Datei \"" + fc.getSelectedFile() + "\"");
> int read = 0;
> do
> {
> try
> {
> read=fi.read(buff);

I had an eraly program that read large files and
I wanted to implement a 'progress bar' type
user update, so I read the input file 1 byte at a
time to gauge where I was.

Bad mistake, reading byte-by-byte took 65000ms.
I finally tried reading the entire file in one sweep.
That took around 800ms!

It was hardly worth implmenting a 'progress bar'
any longer..

> }
> catch (IOException ex1)
> {
> l.setText(ex1.toString());
> }
> t.append(new String(buff,0,read));

And 'append'ing text to a textarea is also very slow.
I would recommend reading it all into a string and
using t.setText( string ); instead..

> }while (read>=10);
> }
> }
> });
> p.setLayout(new BorderLayout());
> p.add(s, BorderLayout.CENTER);
> p.add(b, BorderLayout.NORTH);
> p.add(l, BorderLayout.SOUTH);
> f.setSize(300, 500);
> f.getContentPane().add(p);
> f.show();
> }
> }

HTH

--
Andrew Thompson
http://physci.org/ Home of the Java Physical Sciences Project
& host of 1.1C - Superluminal! (Science and technology site)


0 new messages