I am not new to Java, but somewhat inexperienced using graphics.
I am using JFreeChart to display strip charts of data that comes in very fast (every 10 ms). It works fine for a single chart, but I have multiple charts so my code cannot keep up with the server. I decided to override the paintComponent method in my JPanel and skip painting some of the frames. That did improve performance, but now there is strange behavior: I have 6 charts (each in a JPanel), and they do update as expected but 1 of the six charts flickers into the place of the other 5, then they all flicker back to themselves, then the 1 chart is in all 6, etc. This happens very fast. The chart that flickers in to all 5 is random every time I run this code, so maybe the others are also flickering in and out but I cannot see it.
#Override
public void paintComponent(Graphics g)
{
if ((count++ % UPDATESKIP) == 0)
{
super.paintComponent(g);
}
}
If UPDATESKIP = 1 then this code runs fine, but very slow.
You should not play with the painting method in that way. All the paintComponent() method of a JPanel does is paint the background of the panel. So I doubt that is where the performance problem is.
Every time the panel is repainted the child components of the panel need to be repainted, so not repainting the background will have little impact (relative to the complexity of painting 6 charts). However, if you don't paint the background every time then you can get painting artifacts on the panel.
Take a look at the Swing tutorial on A Closer Look at the Painting Mechanism
If the server data comes in too fast then maybe you need to consolidate the data before redoing the painting
I did more (better) searches and found the answer here:
Enabling/Disabling drawing of a JFreeChart.
The answer by Aleadam was perfect and did the job for me. I'd vote that answer up but I am too new to do so.
Related
My question is that i need to make a GUI that keeps updating becuse i get values that can change from a DB and i got some problems in the graphical area.
well im using Drawline and Drawstring from Graphics2D that print values that are found on the database, this strings and lines move and change value, so i need to call repaint(); with a timer to make them apper in the jpanel, the problem is that repaint(); is not removing the old painting in the background before painting, but when i resize all updates perfecly.
i know a way to clear but the background color goes away too so,
There is a way to update the jpanel removing old paintings and keep the deafult background color?
Not updated
After changing a coordenate and a label text to "AXIS Y" (repaint called automatically from a timer)
Thanks.
From the looks of your image, it looks like you're just forgetting to call super.paintComponent in the paintComponent method. What this does is repaint the background for you, so aren't left with the previous paint artifacts.
#Override
protected voud paintComponent(Graphics g) {
super.paintComponent(g);
}
Note: For future reference, though the images gave us a good picture, it always best to post a Minimal, Complete, and Verifiable example along with those images, so we don't have to make guesses (educated or not)
The program I am working on includes a class named GameForm that extends JFrame. This form is going to contain a map (just a series of rectangles), as well as certain objects on the map.
However, I would not be able to draw all of these objects with a single paintComponent(Graphics g) function, since not all objects in the game always have to be drawn at the same time. For example, the drawMap() function would only be called when the form first loads, whereas all other drawing functions would be called after each turn.
However, from what I have read (and please correct me if I am wrong), only one paintComponent function is allowed in the class, and other functions cannot make use of its Graphics2D object.
Are there any ideas as to how this can be implemented?
People who are new to Swing / GUI programming often imagine JFrames to be like a draw surface or paper. However, you will have to get used to the fact that this is not the case.
First of all, a GUI program has some kind of EDT (Event Dispatch Thread). This thread is where all the GUI action happens. Updating the GUI and responding to user input happens here. This is necessary because user interaction and programmatic changes to the GUI need to be synchronized well.
Back to the topic, a JFrame is basically just a rectangle that is registered to the System to be your "draw surface". Rather than just painting on top of it, you are asked to paint it.
That's what paintComponent(Graphics) is good for. Obviously, you don't want to paint all the time. It just works like:
user opens your window
system tells your app: "hey, you wanted this surface, please paint it"
the Graphics from paintComponent() is used to repaint your frame (quickly)
your application remains inactive until the user makes the next input
If you want to animate your frame, you have to work like this:
tell the system: "hey, I'd like to repaint my surface" (calling repaint())
system calls paintComponent() and you repaint your stuff
the next call must be delayed
start over, paint the next image
Note that the delay is important because all of this happens on the holy EDT. The EDT handles everything and needs to "breathe" so the user can do stuff while you're doing your animation.
All in all, what you've learned is:
Save all the state you need for painting in variables.
When paintComponent() is called, draw onto the surface
If you want to animate, call repaint() -> paintComponent() will be called
never block the EDT
Last thing to consider: don't use JFrame to paint directly to it.
Rather than that, add a JPanel to the frame and override its paintComponent() method.
Generally speaking, what you wish to achieve can be done in a couple of ways. It's strictly related to so-called sprites (http://en.wikipedia.org/wiki/Sprite_%28computer_graphics%29) and image buffering (http://en.wikipedia.org/wiki/Multiple_buffering). Simplest approaches would be:
a) in paintComponent() of a JPanel added to your JFrame generate the resulting image by processing all the input data/user events/machine state,
b) you can prepare & store the overlay as e.g. BufferedImage, updating it as needed, and then paint it over your JFrame during a single call - the state of JFrame will be updated only on paint events (paint(), paintComponents() etc, so you must force invalidation by hand if the map changes without direct JFrame interaction (resizing the window, covering it with other frames etc), e.g. by calling repaint() etc.
c) you can get the drawing context by calling getGraphics() (http://docs.oracle.com/javase/7/docs/api/javax/swing/JFrame.html#getGraphics%28%29), and then using the returned object (probably casted to Graphics2D) as your canvas whenever the need arises. Note that this is actually the worst solution in terms of efficiency.
They ain't the only ones possible - I, for once, use OpenGL/JOGL for most of my 2D rendering needs, since it allows insane rendering speed with all the profits of 3D graphics [interpolation, scaling, rotations, alpha-blending, perspective, geometry morphing, shading etc] with only minimal functional overhead.
Also, note it is usually advisable to draw on a dedicated canvas component (e.g. JPanel) instead of global JFrame - it's connected to so-called lightweight vs heavyweight component difference and other OOP/Swing/AWT/EDT concerns; it also allows to hide the map and reuse the JFrame for something else with one simple JPanel#setVisible(false) call.
See java what is heavier: Canvas or paintComponent()? for more information.
I am making a game in Java. Basically, I have two different "planes" of updating that I need to take care of the. The base layer is the actual game painting itself. It is simply a JPanel that covers the entire JFrame, and is drawn to using its Graphics object.
I use a fixed timestep to take care of these first graphical updates. I have overwritten the paintComponent() method to do absolutely nothing, as I have written a custom render(float interpolation) method that takes care of that, as to prevent unwanted updates.
However, this panel can take no input beyond primitive mouse clicks and keyboard input. I need the ability to create various menus, text boxes, etc, that are also on the screen. Like various abilities, or even the "Menu" button that usually appears in the upper left corner of most games.
To take care of that input, such as creating buttons, I have a second JPanel that has setOpaque(false) applied to it. Then I create various Swing components that I might need, such as a JButton.
To contain the two JPanels, I use a JLayeredPane, and set their layers appropriately, as seen below. This way the input layer should always be on top of the actual game layer.
The code below shows how I create and add the Swing components to each other. addLoginDialog() is a method that adds a Swing component for the login. It has been tested and works properly, and isn't the problem.
private void initComponents()
{
//This code is inside of the JFrame
wholePane = new JLayeredPane();
add(wholePane);
guiPanel = new GUIPanel();
guiPanel.setOpaque(false);
gamePanel = new RPGPanel();
gamePanel.setOpaque(false);
wholePane.add(gamePanel, JLayeredPane.DEFAULT_LAYER);
wholePane.add(guiPanel, JLayeredPane.POPUP_LAYER);
guiPanel.addLoginDialog();
}
So when I run the code, I get horrible flickering. This is the code that is run from my fixed timestep ~60 times per second.
public void handleRepaint()
{
//I don't use repaint() for the game drawing so I can be sure that fps is controlled.
Graphics g = gamePanel.getGraphics();
gamePanel.render(g);
g.dispose();
wholePane.repaint();
}
The problem is, I think, that the two different systems of updating the screen are clashing. The standard paintComponent() system is great for more static screens, but when I need to update consistently and keep track of the fps, I can't have updates going off randomly.
However, for the input layer, I only want to update as Swing normally does. When the mouse moves over a button, when I component is moved or is resized, etc.
Also, note the way the screen flickers: The Background image goes blank and then comes back again repeatedly. The input panel is always there, but is actually painted behind the game drawing, which shouldn't happen, because it is put in the default layer. The reason I know it isn't completely disappearing is because the game painting is partially transparent, so I can see underneath it, and the buttons I added are still there.
My main question is, how can I stop the flickering? Why is the game drawing being drawn on top of the input components when the game drawing is being done on the Panel that is in a lower layer in the JLayeredPane? And I supposed most importantly, what is causing the flickering? Thank you for any help.
Why is the game drawing being drawn on top of the input components
when the game drawing is being done on the Panel that is in a lower
layer in the JLayeredPane?
Mostly because you've circumvented how Swing works.
Let's start with the fact that the Graphics context is a shared resource (typically there is a single Graphics context per native peer), that is, every component gets the same context, this means, when you use your own painting routine, you are basically painting over every thing else.
The RepaintManager is responsible for making decisions about what and when something should be painted. So what you now have is two artist fighting over the same canvas, wanting to paint on it simultaneously, which is just making a mess.
Add into the fray that Swing's painting process is not thread safe and you end up with a complete mess.
If you absolutely must have control, then you need to remove Swing's painting engine from the equation.
Start by taking a look at Passive vs. Active Rendering
ps- There is also hard ware acceleration benefits to using a BufferStrategy
I'm not quite sure how to phrase this, so bear with me.
I have two JPanels in a container JPanel with an OverlayLayout. Both JPanels in the container override paint(Graphics).
The bottom JPanel is opaque and draws some fairly complicated graphics, so it takes a "long" time (10s or 100s of milliseconds) to render.
The top JPanel is transparent and just draws a rectangle or line or simple shape based on mouse input, so it's really quick.
Is there a way to set things up so when I change the simple shape in the upper panel, it doesn't redraw the bottom panel? (e.g. it somehow caches the bottom panel)
I'm vaguely familiar w/ concepts like bitblt, double-buffering, and XOR-drawing but not really sure what to apply here.
You'd be best off using a single JComponent and creating a BufferedImage to store the bottom image. When the paintComponent operation happens on the JComponent, you just blit the bottom image and use the Graphics object to do any further drawing on top of that (from a stored state). Should be fairly efficient.
You'll want to do the complex drawing operations for the bottom BufferedImage in another thread, as the other poster mentions (omitted this by accident, sorry :)). However, you don't want to cause contention on this image, so you must store an additional BufferedImage for this, and blit it synchronously to the other image at the very moment the drawing operations are complete on it.
Focusing on the complicated panel, the key is factoring everything out of paintComponent() except drawImage(). Put everything else in another thread that continually updates an offscreen buffer. Periodically update the screen at some rate that keeps the simple panel responsive. The only hard part is synchronizing, but SwingWorker is a good choice. There's more here.
What's sure is that if the upper panel is target for a full repaint(), then the lower one will be also.
Maybe you can try to optimize the region to repaint on the upper panel in order to avoid repainting all the lower one. But if the painted rectangle in the upper panel covers the whole area, then you end up with full repaint() once again.
Normally, Swing tries to optimize the regions that need a repaint, but it also aggregates these regions when several repaint are performed in a short time, and if I remember well, the aggregated region is just a rectangle that is the union of all repaint rectangles, which is not always optimized but allows for fast computation of repaint events creation.
Now, I think you should follow the advices given in previous replies; indeed, you should really avoid having a paint() method that can perform computations that can be that long (a few 10s of ms should be the real maximum). Painting should be as fast as possible if you don't want to have a GUI that looks unresponsive to the end user. Hence, favour performing the computation only once (and outside the EDT if possible) store the result in a BufferedImage that you just simply draw later on in the paint() method.
EDIT: added other sources of reflection
If you want to optimize the update of the list of points but still keep it in the paint() method, then you can use the clipping region of the passed Graphics to limit the calls to drawing methods, something like:
Rectangle clip = g.getClipBounds();
for (Point p: allPoints) {
if (clip.contains(p)) {
// draw p with g graphics
}
}
You can even try to optimize the list of points to draw by using a QuadTree instead of a simple List, but you'll have to code it yourself (or find some free implementations, there are probably a few of them out there). With a quadtree, you can optimize the time to find the list of all points that have to be redrawn (based on the Graphics clipping rectangle) and only redraw those points.
Addenda for answer by trashgod and jfpoilpret
1/ OverlayLayout is strange way how to layout JPanels, are you same output with once JPanel (without OverlayLayout and Translucentcy)
2/ (10s or 100s of milliseconds) is maybe small value because there is Native OS Latency (45-75ms for today OS and PC)
3/ synchronizations would be managed by using SwingWorker on BackGround Task and with order, directions and synchronizations for painting processes to the JPanel, maybe your paints are too fast/quickly
4/ you didn't describe more about how, where and which about paint()/paintComponent()
if (SwingUtilities.isEventDispatchThread()) {
paintImmediately(int x, int y, int w, int h) // or Rectangle r
} else {
Runnable doRun = new Runnable() {
#Override
public void run() {
repaint(long tm, int x, int y, int width, int height) // or Rectangle r
}
};
SwingUtilities.invokeLater(doRun);
}
I have a component on which I'm drawing a BufferedImage on all the surface.
I would like to draw something more over it, following the mouse when it passes over the area.
To do it, I'm adding a MouseMotionListener on the component and implement mouseMove method. Inside mouseMoved method I'm calling repaint() at the end of the drawing of the drawing of the cursor image. I would like to know if there is a better way to do it, cause the image following the cursor is really small, and I'm repainting every thing each time.
Add a JLabel containing an Icon to the panel with the buffered image.
Then when you move the mouse you just change the location of the label. Swing will repaint the last location so the buffered image shows through, then it will repaint the label at the new location. So let Swing manage the repaint.
Since you know the coordinate of your mouse and the small image you gonna paint over your background, you can optimize like this [pseudo-code]:
void mouseMoved(event) {
lastCoordinates = currentCoordinates;
currentCoordinates = event.coordinates;
image.repaint(lastCoordinates.x, lastCoordinates.y, smallImage.width, smallImage.height);
image.repaint(currentCoordinates.x, currentCoordinates.y, smallImage.width, smallImage.height);
}
that way you only repaint the two regions you actually care about instead of the whole background.
Also, reading the javadoc it seems the code above my actually trigger 2 separate calls to painting stuff, which would be inefficient. You may want to try to pass in a 10 milliseconds value or so to make sure the 2 paints execute together.
Check out javadoc for repaint() that takes 4 and 5 arguments:
4-argument version
5-argument version