Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / November 2005

Tip: Looking for answers? Try searching our database.

DocumentListener is too slow

Thread view: 
William Z. - 04 Nov 2005 00:27 GMT
I'm trying to enter information into some form objects where I store my
data but this is kind of slow what I have. The problem is that when a
user types information into my Swing form, everything listed in my
changedUpdate() method (below) gets executed for each character typed.

I have a DocumentListener for each JTextField of my forms (avg. of 10
fields per form and there are 10 forms/JPanels). When the user enters
text into a field, I do the following ...

// class constructor
public TextFieldListener(JLabel label, ...) { ... }

public void changedUpdate( DocumentEvent de ) {

  Document doc = de.getDocument();

  // Since this listener is registered to a material form,
  // I get the current material definition from FormDefinitions
  // which is a static Hashtable of form types

  int matId = FormDefinitions.getInstance().getCurrentMaterial();
  Material material = (Material)
FormDefinitions.getInstance().get(MATERIAL_FORM, matId);

  // get user typed input
  String txt = doc.getText(0, doc.getLength());

  // set info to my material object
  if (label.getText().equals("weight")) {
     material.setWeight(new Integer(txt));
  }
  else if (label.getText().equals("id")) {
     material.setId(new Integer(txt));
  }

  // put the new information/material back in my storage of all form
info.
  FormDefinitions.getInstance().replace(MATERIAL_FORM, matId,
material);
}

Does anyone have any better ideas, cause I don't know how to enter this
information when a user is done with a field. User doesn't have to hit
the enter key or anything. When it's typed in, it should be stored.

Any help much appreciated.
Andrew Thompson - 04 Nov 2005 01:28 GMT
> Does anyone have any better ideas, cause I don't know how to enter this
> information when a user is done with a field.

Better yet.  Simply put it ina a modal dialog with a
'Commit Changes' and 'Cancel' button, but the CC
button disabled.

When a change is made, enable it and let the user
decide whether they want to save changes when they
exit the dialog.
William Z. - 04 Nov 2005 18:14 GMT
> Better yet.  Simply put it ina a modal dialog with a
> 'Commit Changes' and 'Cancel' button, but the CC
> button disabled.

I thought about that, in fact, the application I'm replacing does that
and it totally sux that the user has to modify the fields, and then
commit them when he's done *IMHO*.

It's a scientific app and has many fields for numerical data within
forms and the users that use this app know what they're doing and
adding in one more step just to say "yes, I really want it ..." is
something I've always hated.

> When a change is made, enable it and let the user
> decide whether they want to save changes when they
> exit the dialog.
Thomas Hawtin - 04 Nov 2005 09:23 GMT
> I'm trying to enter information into some form objects where I store my
> data but this is kind of slow what I have. The problem is that when a
[quoted text clipped - 4 lines]
> fields per form and there are 10 forms/JPanels). When the user enters
> text into a field, I do the following ...

I take it the performance problem is with each key press, not set up time.

> // class constructor
> public TextFieldListener(JLabel label, ...) { ... }
>
> public void changedUpdate( DocumentEvent de ) {

This event is called when a attribute (for instance colour) is changed.
I think it's insertUpdate and removeUpdate you really want.

>    Document doc = de.getDocument();
>
[quoted text clipped - 5 lines]
>    Material material = (Material)
> FormDefinitions.getInstance().get(MATERIAL_FORM, matId);

Ick. Singleton abuse.

>    // get user typed input
>    String txt = doc.getText(0, doc.getLength());
>
>    // set info to my material object
>    if (label.getText().equals("weight")) {

That is really nasty.

>       material.setWeight(new Integer(txt));

Don't forget about exceptions.

>    }
>    else if (label.getText().equals("id")) {
[quoted text clipped - 10 lines]
> information when a user is done with a field. User doesn't have to hit
> the enter key or anything. When it's typed in, it should be stored.

Glad to see someone is going for a half decent UI.

If you are trying to store it back to a database I would suggest you:
 o Execute the updates in another thread.
 o Group all remaining outstanding updates each transaction.
 o Have some sort of minimum period between transactions.
 o If multiuser, cache in a middle tier.

Tom Hawtin
Signature

Unemployed English Java programmer
http://jroller.com/page/tackline/

William Z. - 04 Nov 2005 18:21 GMT
> I take it the performance problem is with each key press, not set up time.

Correct, each char that get's modified does a lookup on the correct
Hashtable, to get another Hashtabel for that type, makes the change,
and put's it back in.

> > public void changedUpdate( DocumentEvent de ) {
>
> This event is called when a attribute (for instance colour) is changed.
> I think it's insertUpdate and removeUpdate you really want.

What I really have is a method that insertUpdate(), removeUpdate(), and
changedUpdate() all call a single method that does the same, so no
matter what the user does to the textfield, it updates my stored data.

> >    Document doc = de.getDocument();
> >
[quoted text clipped - 7 lines]
>
> Ick. Singleton abuse.

I know, I hated doing this too, but I didn't know how else to do it. I
didn't want to have a "god" class init everything or pass this stored
data around in every method that needed it (which was a lot), cause the
code was really looking ugly. So I figured as long as I didn't have to
many of these around, it'd be ok. Certainly works better, but if I only
had a better way ... cause I use this data all over my application.

> >    // get user typed input
> >    String txt = doc.getText(0, doc.getLength());
[quoted text clipped - 3 lines]
>
> That is really nasty.

Agreed, but how else do I know which field was updated and map it to my
storage classes?

> >       material.setWeight(new Integer(txt));
> Glad to see someone is going for a half decent UI.
[quoted text clipped - 4 lines]
>   o Have some sort of minimum period between transactions.
>   o If multiuser, cache in a middle tier.

Actually, no database, just POJO's stored in memory.
pit.grinja@gmx.de - 04 Nov 2005 09:47 GMT
Hi William,
>   // set info to my material object
>   if (label.getText().equals("weight")) {
[quoted text clipped - 3 lines]
>      material.setId(new Integer(txt));
>   }
So the user input has to match exactly one of these two predefined
values? Wouldn't a JComboBox be a better choice at this point?
>Does anyone have any better ideas, cause I don't know how to enter this
>information when a user is done with a field. User doesn't have to hit
>the enter key or anything. When it's typed in, it should be stored.
What about a FocusListener that will execute the desired commands when
the JTextField loses the focus? Problem: not very intuitive, since the
user will have to know that he has to leave the JTextField before
anything gets updated. An explicit "Commit changes" button as suggested
by Andrew might be the better choice here.
>I'm trying to enter information into some form objects where I store my
>data but this is kind of slow what I have. The problem is that when a
>user types information into my Swing form, everything listed in my
>changedUpdate() method (below) gets executed for each character typed.
Have you identified the bottleneck? What are the time-consuming steps?
Accessing the Document of your DocumentEvent or the instantiation of
your "Material" object? In the latter case, it would probably help when
you first check for valid user input by combining these two "ifs" that
you already have
>    if (label.getText().equals("weight")) {
>      material.setWeight(new Integer(txt));
>   }
>   else if (label.getText().equals("id")) {
>      material.setId(new Integer(txt));
>   }
into a single one, and when the input is valid, go ahead, do your
"Material"- instantiation, check what the actual input was ("weight" or
"id"), and update your form accordingly. Right now, you are doing a lot
of work BEFORE you actually know whether the user input is valid.
Have fun while trying out these suggestions
Piet
William Z. - 04 Nov 2005 18:26 GMT
> So the user input has to match exactly one of these two predefined
> values? Wouldn't a JComboBox be a better choice at this point?

No, that was just a short snippet, many fields, and even with a
JComboBox, I'd have the same prob, how to map only the changed valued
to my storage class.

> What about a FocusListener that will execute the desired commands when
> the JTextField loses the focus? Problem: not very intuitive, since the
> user will have to know that he has to leave the JTextField before
> anything gets updated.

Yeah, I'm really shooting for this idea now I think. Just do the update
once when the focus leaves, time to go learn how to do that. I comment
on the "commit changes" button in an earlier post.

> Have you identified the bottleneck? What are the time-consuming steps?

The bottleneck is having to do lookups into a Hashtable, get the
object, and replace it everytime a character is typed. I mean, it's not
terribly slow, but it's noticable (which I guess makes it terribly
slow).
pit.grinja@gmx.de - 05 Nov 2005 11:15 GMT
Hi Wiliam,
I guess I read your post not careful enough before I replied.
> I'm trying to enter information into some form objects where I store my
> data but this is kind of slow what I have. The problem is that when a
[quoted text clipped - 10 lines]
>
>    Document doc = de.getDocument();
Ok, there is a Label  that indicates the "type" of the text field and a
"Document" that has the content
//somed code omitted
>    // set info to my material object
>    if (label.getText().equals("weight")) {
[quoted text clipped - 3 lines]
>       material.setId(new Integer(txt));
>    }
Why don´t you use a simple String instead of a JLabel to indicate the
"type" of the JTextField. You could save two calls of
"label.getText()".
Anyways, I now realize that the suggestion in my earlier post (check
for valid input first, then do all the work) is no applicable.
My suggestion about a FocusListener has one drawback: When the user
simply rushes through the form by continuously pressing the Tab key (or
whatever key will be used for navigation) you will get a lot of
unnecessary "updates". To avoid that, I suggest you use a combination
of several approaches:
1. A DocumentListener that actually does hardly any work, but only sets
an "isUpdated" flag when its insertUpdate or removeUpdate-methods are
invoked.
2. A FocusListener that does all the Lookup and Object generation work
upon invocation of its focusLost-method, but only when the "isUpdated"
flag is set. When the work is done, the "isUpdated" flag would have to
be resetted.
Maybe you derive a new class from JTextField that has as member of type
"boolean" acting as the "isUpdated" flag and brings its own Document-
and FocusListener classes realized as internal classes so that they can
access all members of the surrounding class. That approach will also
give you the opportunity to define an extra member of type "String"
that can be used to indicate the "type" of the JTextField ("weight" or
"id", see above).
Depending on how big your form is (and I have gained the impression
that it can be quite huge) this will lead to the creation of a large
number of Listener-instances. When that is a problem, create one main
instance of a "DocumentAndFocusListener" class that implements both the
DocumentListener and FocusListener Interfaces. Register this one
listener instance as Document- and FocusListener for all your
JTextFields. The "DocumentAndFocusListener" should have one member of
the type "JTextComponent". When the "FocusGained"-method is invoked,
the source of this event should be casted to "JTextComponent" and
assigned to the "JTextComponent" member of the Listener. When one of
the methods that indicate a DocumentChange is invoked, the actual
"JTextComponent" member of the Listener should be marked as "changed",
maybe by setting a Property. When the "FocusLost"-method of the
Listener is invoked, the state of the "changed" property of the
"JTextComponent" would have to be checked, and if it is set to true,
all the Lookup-Update work would have to be done. Just a suggestion..
Good luck
Piet.


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.