I have question how to create a performant swing component.
The component should draw some kind of bar chart. The data for the component are stored in a separte FIFO buffer class. Everytime the buffer is updated the component is informed.
At the moment the component draws a BufferedImage everytime the data changes. The paintComponent method of the bar chart component then draws the created BufferedImage.
Due to the fact that there are a lot of data changes in my application, I am thinking to improve the painting of the BufferedImage. Most of the bar chart remains the same. It is just shifted to the right and the latest data changes are added to the left of the bar chart.
At the moment the whole BufferedImage is recreated out of the data stored in the buffer. What I could think of is to shift the old BufferedImage using AffineTransformation and only add the recently added data. This would enormously decrease the amount of drawing operations on the BufferedImage.
But I do not know if this will speed up the application. How expensive is the AffineTransformation on a BufferedImage?
Any remarks are welcome. Also some other hint how to create a performant swing application.
Thanks in advance
Without some sort of baseline, it's very difficult to measure improvement. At a start, you might compare the two approaches shown here using JFreeChart. The DynamicTimeSeriesCollection loafs at 10Hz; I haven't examined the other closely, but it looks flexible.
Related
I'm making a scrolling 2D map/tile based game. Each tile (stored as tile[21][11] - 231 tiles total per map) can contain up to 21 values (stored as int[3][7]). While full-screen I see about 8 maps at once.
On average, each map takes about 0.03 seconds to draw (found with System.nanoTime). The problem is that as soon as more than 1 map is on the screen, the Swing event polling noticeably slows down.
Is there any solution to this? I can't draw the map a single time to save it as an image because it has transparency involving moving actors, so it changes too frequently. Also I don't think I can call a thread in paintComponent to draw the maps without it glitching out, but I'm not positive.
My Tiles aren't any type of JComponent, they're just data. I call their container the MapPane, which draws all of the tiles in its paintComponent.
Likewise, JTable cells are just data rendered inside a JComponent; the flyweight pattern, mentioned here, is still applicable: the goal is to omit any effort to render non-visible cells. Profile and self-time with a view toward optimizing the rendering; some approaches are examined in the KineticModel cited here.
A BufferedImage that needs no scaling is best. If you must scale, experiment with RenderingHints related to interpolation type. If composition is too expensive, construct maps in the background using SwingWorker; publish() them as they become available and process() them on the EDT, as shown here.
I have a very large complicated diagram that needs to be drawn on the fly.
I am already using a double buffered technique to paint the image (from this answer: Using threads to paint panel in java) however, the generated image that is being painted is so large that it cant be painted as a single image (and the multiple images required to paint it cant be stored in memory all at the same time). For this reason, I paint the currently visible area of the view + some margin. As I scroll, I paint the area that is going to come next, and remove from memory the area we just came from. However, if the user then decides to change direction, they need to wait for this area to be painted again. My question is this:
If a single "frame" of the screen being painted is approximately 1000*1000 pixels, in which approximately 5000 lines/circles are drawn (nodes/edges of a graph) is it likely to be more efficient to repaint this image each time, or is there a way to affectively cache the image to hard disk (to avoid java heap limitations).
Ive already optimised the paint method as much as I can think of, but there are still several seconds of delay if a user scrolls to quickly (i.e. moves out of the painted area before the next set of "frames" are painted). So my second question is this: Will moving to OpenGL offer a large improvement, and will it require major changes to the infrastructure of the code? (I tried doing this a couple of days ago, and found it was not as simple as I thought - often led to the computer crashing).
Several things come to mind:
Profile to verify your working hypotheses; self-time the animation budget on your target platform for comparison, as shown in this AnimationTest.
Compare your approach to the example cited here; it scales into the 1000's and accommodates dragging selections into the hundreds.
If your frames have a suitable geometry, consider adopting the flyweight pattern for rendering; JTable rendering is an example; the underlying mechanism using CellRendererPane is examined here.
I am writing a program that involves overriding a JPanel to do some graphics work. Basically this JPanel is displaying a field of hexagons and the user can interact with individual cells. This field is composed potentially of hundreds or thousands of hexagons, and most of the time when changes occur, only a tiny portion of the screen is affected. But at the same time, it uses multiple layers (there's a "main" layer that shows what the cells contain, and an overlay that shows which cells are selected and ready to be modified)
In order to avoid the cost of rendering each and every cell any time a repaint is needed, my app as it currently exists holds a BufferedImage for each layer. When paintComponent() is called, the app checks to see if any changes have been made that need to be drawn (for example, a user clicked on the screen so the overlay needs to show that some cell is selected), and if so, renders the modified layers to their bufferedimages. In either case, the the repaint just blits both of the BufferedImages to the screen.
It works just fine, but this is basically a home-spun version of double buffering, which Swing is supposed to support internally. However, for the life of me I can't seem to find where to get access to the component's backing buffer so that I can modify it... If I call "getGraphics()" on the JPanel, I get null pointer exceptions -- So that's a no-go.
I am looking for a more elegant elegant way to do this which hopefully takes advantage of the built-in double buffering offered by swing, in order to avoid blitting the entire screen just for one tiny change (and to avoid having to reinvent clipping).
Any ideas?
I am developing a scribble type app in java swing. It is in a rudimentary stage and is shown here.
I have implemented the undo feature which undoes the last drawn stroke upto. The undo feature can be done upto a maximum defined undo levels.
The undo feature works by copying the contents of the drawing canvas after each stroke in an Image array.
This array acts like a First-In-Last-Out Stack. When undo is clicked the stack is poped
and the obtained image is drawn on screen.
Now the problem I am facing is, the current method of implementation of undo takes up too much memory. At undo levels of 20, almost 70-80 MB of memory is used up, and at levels of 30, heap overflow occurs.
Is there a better way of implementing the undo feature ? Thanks.
EDIT : I found some useful information here which may be helpful.
You need to represent the steps in your drawing differently. In the current approach you are using, you save the Canvas each time anew as an uncompressed picture - and that is memory-greedy.
Try to refactor your code so that only the strokes being drawn on the Canvas are saved into the stack. This will put a little bit more overhead when rendering the picture (you would need to redraw the entire canvas each time a change occurs), but Java is designed to deal with that.
Having saved only shapes, the memory requirements should decrease significantly. Use the Shape class to represent the strokes on the canvas.
While I am not doing some animation or drawing a very complicated graphics.
I need (sort of) double buffering for drawing several primitives. In the application, user enters name of Shape followed by related arguments and that shape is drawn on buffer, and then on screen.
Eg of a command is RECT 100, 50, 200, 120.
For persistence, I can store all commands in list and in
public void paintComponent(Graphics g) of JPanel I draw them one by one.
But this is highly inefficient, because of iterating through list and using a hash map each time to call (or dispatch) the relevant shape-drawing-interface.
How and on what type of buffer can I draw? How can different methods draw on this buffer?
Additionally is there a convenient way to be able to undo previous draws with buffer? Or do I need to redraw on buffer each time a undo is done?
Thanks, I don't want full code, but relevant class names and small pseudocode is appreciated.
JPanel is double buffered by default, so selecting and dragging are typically quite smooth. GraphPanel is a simple object drawing program that illustrates such operations on a List<Node>. A similar approach has been successfully used with thousands of nodes.
The details of implementing an undo strategy depend significantly on the desired behavior, but remove() and repaint() are effective.
Addendum: One common optimization for rendering large numbers of objects uses the flyweight pattern. JTable, JFreeChart and JGraph are examples. This simplified example illustrates the essential mechanism.