Repainting in a multithreaded environment - java

i am working on an applet with around ten different datasources(e.g. statistics/error-log/...). Each datasource is updated by a single network connection and reports updates via the observer mechanism. The applet has different views which display parts of the data. Every view is only interested in some parts of the data and registers itself as an Observer at the necessary Observables.
The views(extended JPanels) mostly consist of standard swing components (e.g. JLabels, JButton, ...). Some attributes of the components in the views depend on information from the underlying data model.
Example:
StatisticPanel::paintComponent(Graphics g) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
super.paintComponent(g);
}
This logic is implemented in the paintComponent() method of the StatisticPanel and the update() methods just calls repaint(), because I didn't want the manipulate the components outside of the EDT.
Is this the intended way of updating swing components in a multi-threaded environment? Is it better to use a Runnable with SwingUtitlies.invokeLater()? Are there better approaches for this problem?

I second camickr's recommendations, but regarding this code snippet:
StatisticPanel::paintComponent(Graphics g) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
super.paintComponent(g);
}
You have non-painting methods in your paintComponent method (the first two methods), and that shouldn't be as 1) you want this method to be as lean and fast as possible and thus have only painting-related code, and 2) you do not have aboslute control of when this method is called or even if it is called, and so non-painting related code and program logic does not belong in there. For these reasons, I strongly urge you to get them out of there, but instead should be called separate from paintComponent, but as with most Swing code, on the EDT.
EDIT 1
I'm not a professional, but how about if you gave your StaticPanel a method similar to this:
public void doMyUpdate() {
if (SwingUtilities.isEventDispatchThread()) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
}
});
}
repaint(); // if the paintComponent method has more than just a super call.
}
EDIT 2
Also, please have a look at this thread: check-if-thread-is-edt-is-necessary

repaint() is used to invoke the Swing RepaintManger which in turn will schedule the repainting of the component, so yes it is ok to just invoke repaint directly. The RepaintManager will make sure all repainting is done on the EDT.

Related

paintComponent() is being invoked 200 times

I am having an odd issue when using paintComponent() and repaint().
As you see below, I have a paintComponent() class as an inner class as the main JPanel of my GUI.
// add another panel to centerInner
tableBottom = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!paintImages.isEmpty()) {
for (PaintImages temp : paintImages) {
g.drawImage(temp.getImage(), temp.getX(), temp.getY(), this);
}
}
if (!extraCards.isEmpty()) {
for (PaintImages temp1 : extraCards) {
g.drawImage(temp1.getImage(), temp1.getX(), temp1.getY(), this);
}
}
}
};
This is a black jack game with 4 players a dealer.
repaint() is called by 4 functions:
The constructor for the initial draw.
An update method that creates an ArrayList of objects to print for the initial deal.
An another update method that creates an ArrayList for each card drawn.
And the reset which clears all ArrayLists and repaints the new initial deal.
I won't go into the backend, but every one of those four methods only run the desired number of times. just once for every time its called.
My problem is that when paintComponent is invoked by repaint(), paintComponent() runs almost 200 times, not including the for loops that run around 10 times a piece on average per game.
My question is:
1) Is this common behavior for a paintComponent method? Does paintComponent call itself repeatedly over and over again until all painting necessary has been completed?
OR
2) Does this have to do with the JPanel tableBottom? at this point nothing is actually being added to the JPanel because it is top most JPanel. But maybe paintComponent is ran repeatedly for every JPanel, JFrame, ContentPane, Label, etc.,
OR
3) Did I do something wrong in my code below? Again through testing using increments and print statements I found the update methods are called the appropriate amount of times and doing their jobs correctly.
Thanks for any help.
being a inner class I call repaint like tableBottom.paintComponent()
Never invoke the paintComponent() method directly. To repaint the panel you do:
tableBottom.repaint();
The request will be passed to the RepaintManager which will then combine repaint() requests for all components and then paint the components as necessary. This will make painting more efficient.
g.drawImage(temp1.getImage(), temp1.getX(), temp1.getY(), this);
The "this" means that images can be repainted as they are being read. That is sometimes the painting method is invoked before the image I/O has completed. So in this case when the I/O is finished another paint request will be made so the image is painted completely. If you are reading the images at the start of you class and storing them in some data structure then you can probably just use "null" instead of "this".
Did I do something wrong in my code below?
The code provide looks reasonable, but we can't see the context of how/when you invoke the painting code. I already mentioned one problem.
Post a proper SSCCE that demonstrates the problem.

Is calling repaint from paintComponent a good practice

For some UI components in our application, we override paintComponent, which under some conditions "recursively" calls itself by invoking repaint. We use this approach to achieve high refresh rate of animations in the component.
For instance, a progress bar we use looks something like:
public class SimpleProgressBar extends JPanel {
private boolean inProgress;
....
#Override
protected void paintComponent(Graphics g) {
if (inProgress) {
paintBar(g);
repaint();
} else {
doSomeOtherThings();
}
}
}
Is this a good practice (especially in terms of performance / efficiency / CPU usage)?
Is it better to use a Timer or a background thread to repaint our components?
Is this a good practice (especially in terms of performance / efficiency / CPU usage)?
No, it is not good practice. Calling repaint from within paintComponent is bad practice because:
A high frame rate like this is virtually never required
The frame rate is not guaranteed (repaint does not directly call the painting method, but causes a call to this component's paint method as soon as possible' (which may not be immediately))
Places priority on painting of a single component, and can result in poor performance not only in painting of that one component, but also painting of other Components as well as response to other EDT specific tasks (eg events)
Is it better to use a Timer or a background thread to repaint our components?
Yes, using a Timer or Thread gives you much better control over the frame rate, without bogging down the EDT while doing so. Depending upon the context, a Timer runs on the EDT (as opposed to a Thread) so no dispatching to the EDT is required.
There are very few situations where overriding paintComponent is a good thing. Your situation seems to be one of them; however, it is important to remember that it is not your job to call paintComponent. What I mean by this, is that it is an office of the System to decide when to repaint certain components. This is especially evident when you drag the screen around, or when you put another screen over yours. That being said, it is very difficult to say how many times your method will be called; therein, making it difficult to say when it would be worth using that implementation.On a side note, a background thread, as you put it, would more than likely not make it better, and Swing is notoriously not thread-safe.I hope this helps, and best of luck to you!

How do I successfully use the Thread.sleep() method in Graphics?

This is my code so far:
// Imported Classes
public class Timer extends Applet
{
public void paint (Graphics page) throws InterruptedException
{
Thread.sleep(1000);
}
}
I just want to know how I can get this to work. I've used the Thread.sleep() method in other code before, but never with Graphics. I don't have much experience with Exceptions either, I usually try my best to avoid or correct them.
You should never call methods such as Thread.sleep on the event dispatch thread (i.e. in paint methods). This will render the whole GUI unresponsive.
You should instead use timers such as SwingTimer to perform animations etc. See the following related questions:
how to use a swing timer to start/stop animation
Java Applet Thread Animation
How to make applet animation?
Drawing images continuously in Java Applet

JButton ActionListener - GUI updates only after JButton is clicked

I'm having a problem with my JButton ActionListener. I have a doTheCleaning() method defined in another class which when called makes series of changes to my GUI.
public void doTheCleaning(){
//change image icon
//had thread.sleep here
//insert to text area
//had thread.sleep here
//etc
}
Then in another class, I instantiated the class containing my doTheCleaning() method and had my ActionListener written with my actionperformed() method for my jbutton written like this:
public void actionPerformed(ActionEvent e){
//some code
//newClass.doTheCleaning();
}
I know how to do the rest like addActionListener() and stuff so no need to question about that. My concern is that all the changes in my GUI that is performed when doTheCleaning() method is called applies only after the button is clicked. When this happens, the succession between the changes that happened in my labels and textarea were not shown. The code works fine if i called it directly in my tester class but calling it inside the actionperformed method shows only the final state of my GUI. I need to show which element changed first, then what's next, and so on.
How could I achieve it when I need these changes to occur only when I click the JButton?
**I'm not so good with doing GUI in java yet. iIhope you guys understood my point without me giving my code. but I could if necessary. Thanks.
Do not perform any intensive operations within EDT, otherwise the GUI will be unresponsive and you might not see the GUI updates. Best choice you can use is SwingWorker:
Override doInBackground(), and put any long operations inside this method so that it will be run on a separate thread rather than the EDT.
For any GUI creation or changing states of GUI components within doInBackground(), use publish(V... chunks) to send data to process(List<V> chunks). You need to override process(List<V> chunks). Also note that process(List<V> chunks) is executed on EDT.
After doInBackground() returns, done() executes on EDT and you can override it to use it for any GUI updates. You can also retrieve the value returned from doInBackground() by using get().
Note that SwingWorker<T,V> is generic, and you need to specify the types. T is the type of object returned from doInBackground() and get(), while V is the type of elements you passed to process(List<V> chunks) via publish(V... chunks).
execute() method starts the swing worker by invoking doInBackground() first.
For more on this, please read Concurrency in Swing.

Java -- For an animation, how should a logic class notify a loosely coupled view to repaint

For an application that repaints frequently, how should the 'model' notify the 'views' that they need to repeatedly repaint one of their components. This:
class AppLogic extends Observable {
void runAnimation() {
while (isAnimationRunning) {
modifyDataStructures();
setChanged();
notifyObservers();
Thread.sleep(25);
}
}
}
class View extends JComponent implements Observer {
void update(Observable o) {
o.getData();
innerPanel.repaint();
}
}
seems like a terrible way to go about animating a panel, especially if the animation is being repainted most of the time that the program is running. Any suggestions? Thanks.
*Ignore the obvious errors in threading and such
Assuming that you are building a kind of "Dashboard" application that updates the information periodically, do what this answer says. If you want something more advanced (like animations for a game) you need more work. Check this article for some interesting tidbits about game programming and animation in Java.
Rather than "running" the business logic, you could use a Swing Timer in the View component and just ask the business model to paint itself, e.g passing the current time as a parameter.

Categories