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

setText() is not always updating Jtextfield and Jlabel items

1,843 views
Skip to first unread message

Kevin Nathan

unread,
Feb 26, 2015, 3:23:22 PM2/26/15
to

I could use some direction about where to look for this. I am still
pretty new to Java. I have a user input screen with multiple
JTextFields for user input and matching JLabels for informational
output for users.

This is for a livestock auction system. While the animals are moving
around on the scale, the scale instrument (a serial port device)
returns an indication of "motion" that we want to show to the user.
When the motion goes away, the actual weight gets written to the Weight
JTextField. However, during the motion (which can be anywhere from
non-existent to many seconds) we want to write "Motion" in the
textfield and the actual, changing, weights in the label field. This is
what is not happening. After the motion stops, the true weight does get
written correctly, using setText().

The serial port routine returns an error code of -2 if there is motion
(and several other error codes that are handled correctly) and that is
what I am using. Here are some code snippets to show what is being
attempted, I hope it's enough to make sense:


MainScreen class:
-----------------

// Trying new "Motion" routine:
while (clerkFuncs.scaleErr == -2) {
weight = clerkFuncs.readScale(tr);
showMotion(weight);
}


private void showMotion(long wt) {

noteField[1][weightRow].setText(Long.toString(wt));
// noteField[1][weightRow].setText("<html><font
color='red'>Motion</font></html>");

editField[1][weightRow].setText("Motion");
}


ClerkFuncs class:
-----------------

// weight and weightStr are global in ClerkFuncs. I don't like it
// but that's how it was written.

public long readScale(TransClass tr) {
clearScaleReturns(); // clears weight string and error var

if (!scale.scalePortErr) {
getAutoWeight();
checkForWeightErrors();
} else { // manual weight entry
getManualWeight();
}
return (weight);
}


private void getAutoWeight() {
scale.startScale();

do {
weightStr = scale.getWeight();
} while (scale.getStatus() && weightStr.equals(""));

scale.stopScale();
}


private void checkForWeightErrors() {
scaleErr = scale.scaleErr;
try {
String trimmed = weightStr.trim();
if (!trimmed.isEmpty()) {
weight = Long.parseLong(trimmed);
} else {
weight = 0L;
}
} catch (NumberFormatException ex) {
System.out.println("checkForWeightErrors Exception: " + ex);
System.out.println("weightStr: [" + weightStr + "]");
scaleErr = -3; // bad scale return
weight = 0L;
}
}

I am completely puzzled why "setText" does not work in this instance,
but works everywhere else I am using it. Thanks for any help, or
pointers to pages that may help me to understand this


--
Kevin Nathan (Arizona, USA)
Linux is not a destination, it's a journey -- enjoy the trip!

Linux 3.7.10-1.45-desktop
12:49pm up 7 days 3:18, 18 users, load average: 0.38, 0.46, 0.74

Jeff Higgins

unread,
Feb 26, 2015, 7:48:21 PM2/26/15
to
On 02/26/2015 03:23 PM, Kevin Nathan wrote:
>
> I could use some direction about where to look for this. I am still
> pretty new to Java. I have a user input screen with multiple
> JTextFields for user input and matching JLabels for informational
> output for users.
>
> This is for a livestock auction system. While the animals are moving
> around on the scale, the scale instrument (a serial port device)
> returns an indication of "motion" that we want to show to the user.
> When the motion goes away, the actual weight gets written to the Weight
> JTextField. However, during the motion (which can be anywhere from
> non-existent to many seconds) we want to write "Motion" in the
> textfield and the actual, changing, weights in the label field. This is
> what is not happening. After the motion stops, the true weight does get
> written correctly, using setText().
>
> The serial port routine returns an error code of -2 if there is motion
> (and several other error codes that are handled correctly) and that is
> what I am using. Here are some code snippets to show what is being
> attempted, I hope it's enough to make sense:
>

Often in Swing, when the complaint involves
"does not work in this instance, but works everywhere else"
you've run into a thread concurrency issue.

You might have a look at "Concurrency in Swing"
<http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html>
if you haven't already.

The section "Bound Properties and Status Methods"
refers to another section in the Java Tutorials
"Lesson: Writing Event Listeners"
<http://docs.oracle.com/javase/tutorial/uiswing/events/index.html>
which may be helpful as there was no indication in the snippets
you provided that you are using the Swing event model.

Knute Johnson

unread,
Feb 26, 2015, 11:05:32 PM2/26/15
to
Two suggestions, first a call to JTextField.setText() must be on the
Event Dispatch Thread. I don't see you wrapping your calls on the EDT.

Second, if the GUI isn't updating it is probably because the updates are
not on the EDT or the EDT is blocked for some reason. Without more
coherent code it is difficult to tell what is going on.

But that is where I would look.

--

Knute Johnson

Kevin Nathan

unread,
Feb 27, 2015, 10:21:54 AM2/27/15
to
On Thu, 26 Feb 2015 19:43:05 -0500
Jeff Higgins <je...@invalid.invalid> wrote:

>Often in Swing, when the complaint involves
>"does not work in this instance, but works everywhere else"
>you've run into a thread concurrency issue.
>
>You might have a look at "Concurrency in Swing"
><http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html>
>if you haven't already.
>

Thanks, Jeff! I will start there and investigate Knute's answer, as
well.


--
Kevin Nathan (Arizona, USA)
Linux is not a destination, it's a journey -- enjoy the trip!

Linux 3.7.10-1.45-desktop
08:20am up 7 days 22:50, 18 users, load average: 0.39, 0.45, 0.44

Kevin Nathan

unread,
Feb 27, 2015, 10:24:59 AM2/27/15
to
On Thu, 26 Feb 2015 20:05:35 -0800
Knute Johnson <nos...@rabbitbrush.frazmtn.com> wrote:

>Two suggestions, first a call to JTextField.setText() must be on the
>Event Dispatch Thread. I don't see you wrapping your calls on the EDT.
>
>Second, if the GUI isn't updating it is probably because the updates
>are not on the EDT or the EDT is blocked for some reason. Without
>more coherent code it is difficult to tell what is going on.
>
>But that is where I would look.

Thanks, Knute! I don't know anything about wrapping calls on the EDT,
so that looks like the path I need to research and learn.

Even though I've been on this project for months, I still feel like I
know next to nothing about Java; but it is slowly starting to come
together! And I hate having to work on someone else's code with no
comments, but that's just me... :-)


--
Kevin Nathan (Arizona, USA)
Linux is not a destination, it's a journey -- enjoy the trip!

Linux 3.7.10-1.45-desktop
08:22am up 7 days 22:51, 18 users, load average: 0.39, 0.43, 0.43

Nigel Wade

unread,
Feb 27, 2015, 10:45:28 AM2/27/15
to
On 26/02/15 20:23, Kevin Nathan wrote:
> // Trying new "Motion" routine:
> while (clerkFuncs.scaleErr == -2) {
> weight = clerkFuncs.readScale(tr);
> showMotion(weight);
> }
>
>
> private void showMotion(long wt) {
>
> noteField[1][weightRow].setText(Long.toString(wt));
> // noteField[1][weightRow].setText("<html><font
> color='red'>Motion</font></html>");
>
> editField[1][weightRow].setText("Motion");
> }

This is the problem.

For setText() to work it needs to be invoked by the Event Dispatch Thread
(http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html)

However, there is also the issue of allowing the EDT to do its work. If you block the thread in a loop then the EDT
never gets a chance to do its work.

Your code above is wrong because it either
1) is not invoked on the EDT
2) is invoked on the EDT and therefore blocks the thread in the while() loop.

The normal way that Swing is used is either by event action, or by explicitly invoking a method on the EDT.
If your code is an action handler invoked on the EDT then it must perform an action and return to allow the EDT to get
on with everything else it has to do. If your code is running on thread other than the EDT it should invoke the
setText() method on the EDT by using SwingUtilities.invokeAndWait() or SwingUtilities.invokeLater(). setText() is one of
those methods which "mostly" works if you use on a non-EDT thread, which may explain why your code appears to work for
other uses of setText(). However, "mostly" is not always, and it's incorrect code because setText() is not thread safe,
and it will likely cause you intermittent and non-reproducable problems when you least expect, or want, them in
production use.

With the code you have, the while loop should not be running on the EDT. The showMotion() method should be. I don't know
how you get to the path of the while loop, but it's probably going to have to be changed. To get the while loop to run
the setText() method on the EDT you use something along the lines of:

final long weight=wt;
SwingUtilties.invokeAndWait(new Runnable() { public void run() {showMotion(weight); }} );


The other, and arguably more elegant solution, is to use a SwingWorker.
Your while loop would go in the doInBackground() method, and publish() the weights. The SwingWorker.process() method
would essentially be your showMotion() method which processes the published weights.

The above link to the Java Swing tutorial should hopefully provide some insight.

Just remember the fundamental issue, Swing is event driven on the EDT.




Kevin Nathan

unread,
Mar 2, 2015, 11:33:27 AM3/2/15
to
On Fri, 27 Feb 2015 15:45:24 +0000
Nigel Wade <n...@ion.le.ac.uk> wrote:

>On 26/02/15 20:23, Kevin Nathan wrote:
>> // Trying new "Motion" routine:
>> while (clerkFuncs.scaleErr == -2) {
>> weight = clerkFuncs.readScale(tr);
>> showMotion(weight);
>> }
>>
>>
>> private void showMotion(long wt) {
>>
>> noteField[1][weightRow].setText(Long.toString(wt));
>> // noteField[1][weightRow].setText("<html><font
>> color='red'>Motion</font></html>");
>>
>> editField[1][weightRow].setText("Motion");
>> }
>
>This is the problem.
>
>For setText() to work it needs to be invoked by the Event Dispatch
>Thread
>(http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html)
>
>However, there is also the issue of allowing the EDT to do its work.
>If you block the thread in a loop then the EDT never gets a chance to
>do its work.
>

Thanks, Nigel, for that informative answer! I was busy all weekend with
a local outdoor event. I will be looking at this later this week. That
sure cleared up a lot of questions in my mind!


--
Kevin Nathan (Arizona, USA)
Linux is not a destination, it's a journey -- enjoy the trip!

Linux 3.7.10-1.45-desktop
09:30am up 10 days 23:59, 18 users, load average: 1.35, 0.73, 0.52

0 new messages