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?
Related
The number of models that my swing application needs to display is currently 2000 to 10000 images. After multiple zooming or using for a period of time, the memory continues to increase and will not decrease,How can I optimize it?
It is hard to recommend anything without knowing more about the environment, but I'll list some general tips:
You resize images every time you zoom in/out. This creates new images rapidly, especially if you zoom in using the mouse wheel or some other tool that fires events rapidly. Consider creating the image after the resizing has finished.
Don't hold references to unused images. This means you shouldn't store all the resized images, only the used ones.
Probably you don't need every image in every state of the
application - consider creating a loading screen which is shown while your application loads and resizes the used images, and discards the previous ones. (It does not have to be an actual loading screen or animation)
I've never seen a small or medium-scale project which needed 10k unrelated images. You might be storing animations per-frame, which is way less efficient than using video formats.
If you have many similar images, consider not loading them from file but instead paint them dynamically (you have a base image and paint over it using the component's Graphics).
Call the garbage collector. This should free up any unused space in the memory.
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'm working on an Android application that requires 2D graphical view with a large set of objects. Here's what I basically need to display:
In my case, there could be hundreds of spatially distributed objects. This view is going to behave like a map, so the user is able to scroll in horizontally and vertically, zoom in and zoom out. It also requires click event handling, so the user is able to click any triangle and I then should display some extended information related with that particular triangle.
I'm mostly concerned about 3 things:
In case I re-draw all the objects per in my onDraw() handler, that would be really slow. Also, there I cases when I don't even need to draw all these objects since some of them are invisible depending on zoom level and scroll position. These requires using quad trees which I don't want to implement manually.
All these objects are defined as (x,y,rotation,type), so in case customer decides that we need a "show all" button, I'll have to implement a functionality to calculate bounding boxes.
I need to be able to handle click events and (probably) dragging for all these shapes.
Is there any library that can help me with these tasks? Just don't want to spend 3 days on stuff that I believe must already have been implemented.
All the methods in the Canvas class of the android.graphics package should suffice. The Canvas does clipping (meaning drawing commands get discarded if it's not visible) so if the image is static you could render it into a Picture and draw that on onDraw().
I think the drawing methods have methods to calculate bounds and return them. See Path's computeBounds(RectF bounds, boolean exact).
I have a large component (say width=4000px, height=200px) and would like to be able to see it entirely even on a small screen.
I don't see any easy way to do a wrapping component, my idea is the following :
given a factor (for example 4), the component would be of size 1000x800, by wrapping the child to 4 lines. The size requests would be translated in reverse to reshape the child, and so on. On painting, the component would call the paint(Graphics) of the child 4 times with a correct Graphics argument that would map the wrapped space to the child's space.
However, I can't see how to handle all the events : should I set eventlisteners for every children-generated event (PropertyChange) and for every parent-generated event (Mouse, Key, Resize, ....) ? This seems quite a lot of mapping, and I'd be happy to ear of an easier way of doing that...
I haven't looked too much at the JViewport implementation, but maybe this could help me don't you think?
thanks for your suggestions!
Frederic.
Edited to answer some of the comments that suggest to redesign the component :
Allow me to disagree here : making a component is one job, showing it is another. If I want to show it with scroll bars, I use a Scroll-Pane, whereas if I want to show it split in 4 lines, I want to use a similar solution.
I am the designer of the component in question (and had sharp words with myself, as suggested, but it lead me nowhere :-) ). I actually added "line-wrapping code" in it but it appears (really quickly!) that adding point space conversion, painting management in the codes of the component itself makes it really really messy, which is the reason why I imagine that a specialized component is a really a better solution.
Furthermore, making a custom component lets me reuse it far more easily as a "wrapper" for any other component.
Imagine if you had to recreate a JScollPane-like functionality every-time you use a JScollPane, dealing with scroll position, buffered painting and everything inside your own components : hopefully you don't have to!
You're approaching this the wrong way. It's the contents of the component, not the component itself you should be thinking about. If you want it to be 1000x800, make it that size. If the component has content - e.g. text or other components - calculate their positions appropriately. (You probably won't be able to use the standard layouts, and may end up writing your own). You'll probablky need to recalculate the layout if the component's width changes.
Don't call paint 4 times. If you've calculated the layout of the component, it's children or text, correctly then paint should just work.
In response to the comment: wrapping a histogram, in the sense of inserting arbitrary line breaks, is not likely to be useful. With graphical components the 'breaker' won't know exactly where to insert the breaks; you will also lose any information attached to the Y axis. Much better solutions would be to simply shrink the histogram in the horizontal direction until it fits the screen width, or to draw four histograms one under the other, duplicating the Y axis information for each. Alternatively allow horizontal scrolling over the whole histogram; or change the axes so the histogram is drawn horizontally. If none of the above work, perhaps because you have many hundreds of histogram bars, maybe a more interactive approach where you amalgamate some of your histogram bars together to give an overview, and allow the user to 'drill down' into the plot to get at the more detailed information.
If the issue is that you can't modify the original component, and it draws a fixed size image, then your best bet may be to call 'paint(Graphics)' on it four times with appropriate transforms and clipRects on the Graphics to draw the four parts 'stacked'. But frankly you may be as well off throwing away the original component. Histograms are not that hard to draw, and there are plenty of free plotting packages to help you. And be very rude to the designer of the original component if you meet them.
You don't mention scrolling. Put it on it's own pane and then put that pane into a scrolling panel.
I have a custom UI drawn for my java application. Right now I draw the entire UI from scratch. I know for a fact some parts of the UI are static. I know I could save these static parts to an image, but will this yield a improvement in performance (Since even an image must be drawn every frame)?
Is it plausible to save a reference to the Graphics2D object after the UI has been drawn and assign that to the new graphics object every frame (starting from a point where all the static components are drawn)?
Thanks in advance,
Alan
You don't need to redraw everything in every frame. So if you have static parts of your UI (or even dynamic parts that you know haven't changed since last frame) then you simply don't need to repaint them.
In my code (Swing games and simulations mostly) I usually try to follow the following rules:
Pre-prepare static images (e.g. BufferedImage textures for UI elements)
Override the paintComponent() method for each UI element individually to do the painting
Only call the repaint() method of any given UI element if I know that something has changed
Call repaint() in a timer-based loop for animation, but only call it on the portion of the UI that is being animated (e.g. a nested JPanel)
This approach seems to work and perform pretty well (though I'd welcome comments if there are ways to improve it!!)
There are two main optimizations you can do here. The first is to make sure that when you cause your UI to be repainted, usually done by calling repaint, make sure you call the version of repaint where you specify a rectangle that has changed. Only make the rectangle big enough to encompass the parts that actually have changed, not the static parts. For this to be effective you also have to pay attention to the clipRect in the Graphics2D object you are passed in paint(). That is used by the system to tell you exactly what needs to be repainted, in the above case usually the rectangle that you passed to repaint. Don't paint anything that lies entirely outside that rectangle.
You can also get significant performance improvements by caching the static parts of your interface in an image. Writing an image is by far the fastest way of getting things onto a screen. My measurements indicate that small images are faster than even a few simple drawing primitives. However you need to make sure the image characteristics match the screen, by using createCompatibleImage().
Of course you may be using a lot of memory to get this speedup. I would recommend testing to see if you need to do image caching before implementing it.
if some parts of the screen is completely static, then never redraw that part. Don't do a full-screen/window clear, just clear the part of the screen/window that changes all the time.
This way, you don't unnecessarily redraw the static image.