Design question about Swing GUI updates via PropertyChangeSupport - java

In the past I have used PCS to update Swing elements that displayed certain fields and everything worked as expected. However, I am now facing a relatively complex (in other words, terribly designed) UI that displays a lot of fields. Data updates come in bunches (a network packet containing new values for about 1,000 fields), and I was wondering what the proper way to handle something like this is.
My main concern is that whenever a data packet comes, 1,000 PropertyChangeEvents are triggered, causing 1,000 .repaint()'s (or .revalidate()'s or whatever). The more prudent way seemed to do something like "gui.stopRepainting(); fireAllThePropertyEvents(); gui.restartPainting();". Is there a way to do that, or is there maybe a better way to handle this ?

A repaint request is passed to the RepaintManager which in turn combines multiple requests into a single repaint.
I find it strange that you have 1000, fields of a single form. Assuming this in fact true then I doubt all 1000 will be visible at the same time. I believe the RepaintManager will only paint those that are visible so the overhead may not be as bad as you think.
I don't know of any way to stop the repaint, but maybe you could make the pane invisble, do the updates and then make it visible again.
Or maybe you can create a custom RepaintManager the does nothing. You instal it, do your updates and then reinstal the default manager.

Related

Showing a state of another thread in GUI

I have a GUI and the GUI is starting another thread (Java). This thread is starting a class which is crawling many websites. Now I want to show in the GUI how many websites are crawled and how many are left.
I wonder what's the best solution for that.
First idea was to start a timer in the GUI and periodically ask the crawler how many is left. But I guess this is quite dirty...
Then one could pass the GUI to the crawler and it is calling a GUI method every time the count of ready websites changes. But I don't think that's much better?
What is the best way to do something like that?
It depends.
Ask the crawler how much work it is done isn't a bad idea. The benefit is you can actually control when an update occurs and can balance out the load.
The downside is that the information may go stale very quickly and you may never get accurate results, as by the time you've read the values, the crawler may have already changed them.
You could have the crawler provide a call back interface, which the GUI registers to and when the crawler updates it's states, calls back to the GUI.
The problem here is the UI may become swamped with results, causing to lag as it tries to keep up. Equally, while the crawler is firing these notifications, it isn't doing it's work...
(Assuming Swing)
In either case, you need to make sure that any ideas you make to the UI are made from within the Event Dispatching Thread. This means if you use the callback method, the updates coming back will come from the crawlers thread context. You will need to resync these with the EDT.
In this case you could simply use a SwingWorker which provides mechanisms for syncing updates back to the EDT for you.
Check out Concurrency in Swing for more details
register a callback function to your thread. when your data is dirty, invoke this callback function to notify GUI thread to update. don't forget to use synchronization.

multithreading for java graphics

I have a java application that streams raw data and draws real time plots accordingly. this is handled by calling methods from a class i wrote that uses the Graphics object. i implemented algorithms in an overridden paintComponent method to generate all the plots from the most recent data. i have other methods in my class to update variables used in the paintComponent method to draw the graphs.
in my main class, i update my graphs periodically in a timer event handler. in the event handler i call methods from my graphs class that update certain variables, do a few calculations, and then call repaint() (which apparently is the correct way to call the paintComponent method).
my problem is, the algorithms i use in the paintComponent method can take a (relatively) long time to complete depending on the amount and resolution of my plots. (i haven't exactly run into this problem yet, but i'm trying to address it now). of course i wouldn't want all this graphing to hog all the processing time of my application, so i was wondering if it's possible to have "paintComponent" execute in a separate thread.
what would happen if i created a subclass in my main to run in a separate thread and simply called the graph methods i described? would that automatically make all of those methods (including paintComponent) execute in the new thread? or would i have to modify my graph class itself for this to work? ideally i would like to avoid modifying my graphs class because i have already designed it to work within the NetBeans GUI builder as a JPanel, and i'd like to avoid breaking that functionality.
There's a couple options.
One method is to use two BufferedImages, where you draw on one in separate thread, and paint from the other one, and switch as drawing completes (for what I assume is a snapshot every so often.)
A much better solution is to have a model of directly renderable data (as in the data it holds can be drawn without performing any further algorithmic work on it).
This means you will perform your alogirthms on a separate thread, calculate the values that will be used to paint, call SwingUtilities.invokeLater to update the model. The model will then only get updated on the Swing thread, and when you repaint, you have access to exactly the data you need to draw (and no extraneous data).
If this data is still so much that painting takes a long time (ie: if you're drawing charts with tons of data points), you'll send to calculate which parts of your window need repainting and fire repaint() on just that. This piece should be a lat resort however. 99% of your performance will come from moving the algorithms into a separate thread, and giving the painter access to directly renderable data.
If you look at best practices on updating a TableModel with external data, what you have is the work that gets the data occurring in a background thread (typically SwingWorker) and then posted to the actual model via invokeLater() (This is so the data doesn't get modified while your paint() is trying to read it.) and then firing appropriate events from within the model update that tell the table what cells changed. The table then knows what part of its viewport needs repainting and fires the appropriate repaint() method. During this time the background thread can continue retrieving data and adding new updates to the event queue via invokeLater.
you have to redirect paint methods to the SwingWorker or Runnable#Thread (all output to the GUI must be wrapped into invokeLater), example here or here
Well, if you want to improve the responsiveness of the GUI you could do the lengthy work in a SwingWorker, although I don't know that doing so will speed up your application any more.
I have a java application that streams raw data and draws real time
plots accordingly. this is handled by calling methods from a class i
wrote that uses the Graphics object.
To complete other's answer:
you should really consider to use JFreeChart. It's a good library for drawing charts and you can modify dynamically the displayed dataset (and do a lot of more things).

Best practice when using threads in SWING / Java in general

I have a SWING UI that contains a button that creates a new SwingWorker thread. That thread then queries the SQLite database for results to put them in a JTable. In my StringWorker constructor, the parameters are various fields taken from other SWING components such as a JSpinner, JComboBoxes, etc.
Since I'm new to all of this thread thing, I'd like some advice from more knowledgeable programmers on how I should go about doing what I want to do.
I'd like to know if threads automatically end when I close the program with System.exit(0); so I don't end up with memory leaks
What is the best way to make sure I don't have two threads accessing my database at the same time (let's say the user clicks multiple times on the button or, other case, an administrator is updating the database with some files as input (within my program), then while the first thread is parsing the files and updating the database, he wants to query the database using the button, etc.).
Is it slower to use threads? At first I did all my calculations right in the EDT and of course the UI locked every time after pressing the button, but it only locked for about 5 seconds if I recall correctly. Now, when I press the button, it doesn't lock up but it seems like the result take about a little bit less than twice as long to show up in the JTable. Is it because I made a mistake in my code or is this normal?
I though about using a static field in the class the queries are in and setting it to true if it's in use. Is that the correct way of doing it? That way, not matter which thread is using the database, the second thread won't launch.
If it's not absolutely necessary (it shouldn't be), don't use System#exit in your code. Here are some explanations why and what is better.
Your database is capable of handling two concurrent requests, so it's not a bad thing in itself. If you use JDBC and its pooled connections via DataSource, then you should probably restrict the usage of one such a connection to one thread at a time. To cure the problem of having redundant database queries, e.g. when "clicking twice", there is probably more than one solution. I assume here that you mean the scenario where you have a Swing UI that is distributed to several people, and each of these instances talks to the same database -> simply disable your button as long as the execution of the database query takes.
It's slightly slower if you do not run your code directly in the Event Dispatch Thread due to scheduling of execution of your workers, but this should not be noticable. To see what goes wrong I would have to see the relevant code.
I'd like to know if threads automatically end when I close the program with System.exit(0);
Yes. Entire process will end and threads that are part of this process. However, if you don't call System.exit(), all non daemon threads must finish before process is gone.
What is the best way to make sure I don't have two threads accessing my database at the same time
Since it's a Swing application, I assume that both you and administrator can't access the application at the same time. However, to guarantee that even in single application you can't start more than one operation affecting database, you have to block UI. Either disable buttons or put glass pane on top of UI. Modal progress dialog is also helpful.
Is it slower to use threads?
No, it is not slower if done right. Slow operation will take as long as it takes. You can't fix it with threads, but you can, either keep speed (perceived) the same while providing nice, non blocking UI or you can do more than one slow operation at a time and therefore increase that perceived speed.

Prevent Swing GUI from becoming unresponsive when invoking a method which is both accessing Swing components and is time-consuming

The following line:
SwingUtilities.updateComponentTreeUI(aComponent);
is making my GUI unresponsive.
When invoking this method to update the laf on a large portion of a GUI, it takes a lot of time, and so makes the GUI unresponsive during this operation.
Since this operation is manipulating the GUI, one can't use a SwingWorker for this either.
From the SwingWorker documentation:
Time-consuming tasks should not be run on the Event Dispatch Thread.
Otherwise the application becomes
unresponsive.
Swing components should be accessed on the Event Dispatch Thread
only.
The problem here though, is that the operation is accessing Swing components and is time-consuming.
Is there a good way to prevent this unresponsiveness?
Since what you do is changing the L&F, and that might severely impact the appearance and usability of the GUI, ask yourself whether you really want the application to be responsive during that time. It may be better to display a message ("Please wait..." or something) using the glass pane, and freeze the GUI while the L&F is updated.
Now, as others have suggested, you may want to investigate why updating the component tree is so slow.
I was going to suggest looking through your GUI to identify any custom or third-party components that contained a lot of sub-components or that had any unusual or inefficient method to revalidate itself. It looks like that was the case, as you mentioned the date picker was a serious bottleneck.
You suggested splitting the calls to updateComponentTree into several sub-tasks that allow events to occur in between, which might be a 'hack' but isn't too bad, unless the change of font changes the sizes of elements and may cause the user to miss a button etc.
If possible, I would suggest looking at the code in the date picker component and see if you can rewrite it so that instead of hiding the components in the pop-up, it actually removes/disposes them, and recreates them when necessary. This should have no noticeable effect on the responsiveness of the date picker when it's being used, but will certainly speed up component tree updates when the pop-up is not visible.

Is update from EDT in swing an absolute rule or are there exceptions?

In Swing, the GUI is supposed to be updated by the EDT only, since the GUI components are not thread safe.
My question is, if I have a single thread, other than the EDT, that is dedicated to update a specific component, and this component is not accessed by any other thread in my program, only this dedicated thread, is it ok? In my case I have a JTable and a thread receives information from the network and updates the table (without using EventQueue.invokeLater). All the other components are updated from the EDT. I have not seen a problem so far, and I was wondering if a bug will surface eventually.
UPDATE
My purpose was to update the table in real-time. The data come constantly from the network and for this I dedicated 1 thread just for the table, to update it constanlty as they come. If I use the SwingUtilities.invokeLater, this means that the table will be updated when the EDT is available. Is not swing supposed to be used for real-time update requirements?
Instead of trying to reason about whether it will or won't work, I would just stick to the well-known 'rule' which is that you should only interact with GUI components using the event dispatching thread. When you receive data from the network, just update the table using SwingUtilities.invokeLater (or invokeAndWait).
You might not see problems straight away, but it's quite possible you might do in the future.
There are a few methods documented as thread-safe. I believe a few less in JDK7, because it turns out some of them are unimplementable as thread-safe. For the most part Swing is thread-hostile - it has to be used from the AWT EDT thread. This is largely because it uses EventQueue.invokeLater internally at "random". Also there is hidden shared state (you can change the PL&F without having to tell each component for instance). Some classes you may be able to treat as thread-agnostic, but they are not documented as such.
So the answer is, always use the EDT for Swing. As with most threading bugs, you might seem to get away with it and then suddenly fail in production. The bug is likely to be difficult to diagnose and reproduce (particularly if it only happens in production on certain systems). Fixing a code base that is severely broken may not be fun. Keep it clean from the start.
You must update GUI components on the EDT. Period. (There are a couple of legacy exceptions to this rule - but they were all silently putting things over to the EDT anyway). The EDT operates as a message pump (as most windowing systems do) - you have to live within that constraint if you want to update GUI components.
If you want your table to update quickly, keep the EDT clean - don't put any huge load onto it.
If you are working with updating live tables, I strongly recommend that you take a look at GlazedLists - they have a very, very good SwingThreadProxyList implementation that takes care of efficiently posting updates to the EDT. You have to agree to drink the GlazedLists koolaid to go this route, but it is mighty tasty koolaid (I love GL).
Is not Swing supposed to be used for real-time update requirements?
No. You may be able to update your data model at a sufficient rate, but the GUI is typically subordinate. You may be able to take advantage of any network latency in your environment. Alternatively, you may need to consider something like Oracle's Sun Java Real-Time System.
You can improve the "liveness" of the EDT by keeping updates brief and using the minimal, correct synchronization. Several alternatives are discussed here.
It is an absolute rule, unless you want race conditions. The event dispatch thread is fast enough for our CCTV app's display not to need hacks.

Categories