I feel as though the solution to this is very simple and I'm just overlooking something stupid, but I can't seem to make the repaint() method of one of my JPanels work. The JPanel in question is a member object of another class which handles all the logic behind what is drawn to the JPanel, however, whenever I call repaint() in my thread, I do not see anything drawn, nor do I see my System.out.println() call, which I put in there for debugging purposes. I have put the files on Github for convenience. Here are the three files I think MIGHT have something to do with it. You can always look at the others if you need to.
SageLife.java
LifeFramework.java
Grid.java
I've created plenty of JPanels before and have rarely encountered this problem, so I'm just not sure what's causing it.
You are overriding paintComponents rather than paintComponent in your Grid JPanel. This does not follow Swing's paint chain mechanism.
#Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
Note: always go for Swing Timer over Thread for handling UI updates in Swing.
Related
I am doing a project with double buffering. When I paint, it simply paints on top of the old layers, but I need to erase them. Repaint() didn't work, but I'm guessing something equally as simple is the answer.
Any ideas?
Added code, and now it disappears, but it erases the background color.
public void paint(Graphics g)
{
super.paint(buffer);
for(Projectile p: projectiles)
drawRectImage(buffer, p.image, p.getRectangle());
}
Suggestions:
If this is a Swing GUI, then don't override the paint method, but instead override the paintComponent method. This won't help your current problem, but will help prevent future problems including problems with painting of borders and child components.
If Swing (again you don't say), then make sure that your painting component extends JPanel, not JComponent, since JPanel is opaque and fills its background rectangle in its super method.
If it's not Swing, then you should strongly consider changing from AWT to Swing.
If you're still stuck, then yep, you'll want to create and post a minimal example program. Please check out the link.
I'm learning Java as part of my degree but its very brief but what ever I do I like to make sure I atleast have some understanding.
Until now anything that I want displayed on the screen is put into the paintcomponent method of the JPanel.
However, I have drawn out some parts of my layout which never change, and only a certain thing in the middle rotates.
I have a timer which calls repaint().
If I correct in thinking that everything including the components that never change are being removed and then redrawn and the whole paintcomponent method is being run every time.
To me I feel like I should (or there must be) a way where the static stuff is moved out / is only drawn once, and only the parts that I specifically want to be redrawing should stay in the paintcomponent method?
Is this correct or am I not fully understanding something?
I am assuming that you are not adding GUI components in the paintComponent method, right?
Components are not "removed" during a repaint
Better to put the stable part of any image into a single background BufferedImage and draw the BufferedImage in the paintComponent method. This can make for more efficient painting.
Consider calling an overload of repaint(...) that sets a bounding rectangle for the region to be painted.
I have tried tutorials on this but I still don't quite understand it. Basically my question is which method is better and why? Should I use paint or paintComponent?
Please try to keep the answer simple, thanks.
Quoting from documentation of paint() method
This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren.
...
A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.
It looks like the paint() method actually draws the component, including the border and children. If you only want to customize the component's appearance excluding the border and children, you use paintComponent().
http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#paint(java.awt.Graphics)
Generally speaking, when painting in Swing, it is recommended to override paintComponent.
There are a number of reasons why, one is paintComponent is painted at the bottom layer, meaning you won't accidentally wiping out any components that were rendered during the paint process - this happens a lot to people who post here.
There are a, very, few times you might need to override paint, but I would always encourage you to try making it work with paintComponent first.
Check out
Performing custom painting
Painting in AWT and Swing (+1 to trashgod)
I have looked all round, and no one seems to have an answer for me. I have a JPanel where I add/remove labels from it while it;s running. The problem is that every time I add a new label to it I have to revalidate() it so the new label shows up. Every time I revalidate(), it I get a very annoying flicker, and all my labels ghost up to the top of my window for a millisecond then return to what they were doing. The only time I call revalidate() is after I add a label; I do not change the paint method or anything only did
public void paintComponent(Graphics page)
{
super.paintComponent(page);
}
so that my page would not look bad. I could really use some help on this. I've made a asteroids game using JFrame, Jlabel and Jpanel game; it work great, but this flickering and component "ghosting quickly ghosting to top of panel" is just unbearable, and I know for a fact this is the revalidate() method.
Using labels (or generally GUI components) to represent quickly animating, dynamically created/moved objects is not practical. Its like using a car to drive from the living room to the kitchen.
The Swing components come with a lot of nice features, e.g. they can determine the space they require and a layout manager can use that to automatically place them nicely. Unfortunately for a game, you neither need all the nice stuff, nor do you want to pay the processing overhead involved with it. Matters are further complicated by swings multi-platform capabilities which mandate that each component has a peer component (the peer deals with rendering the component to the active look).
To solve this, you do not represent individual game objects as swing components. Instead you use a single swing component (usually JPanel) as a canvas to paint your game objects on to. You simply call repaint() for that JPanel periodically (e.g. 30 or 60 times a second). Of course you will override paintComponent() on the JPanel to do paint all the game objects using your own code.
Edit: To outline how you do your own rendering
You need to decide how to organize your game related objects. A very simple skeleton could look like this (getters/setters omitted):
public class GameObject {
public int x;
public int y;
public Image image;
}
In practice this class will have additional members (like a behavior that controls how the object moves, and maybe some states/counters for animation). It may also be abstract with a concrete subclass for each possible behavior (like ship, asteroid and bullet). All instances of GameObject are managed in some kind of collection, I assume you use a List.
When implementing the paintComponent it comes down to just loop through the list and render each objects's image:
public void paintComponent(Graphics g) {
List<GameObject> list = ... // however you obtain it in your game
for (GameObject gobject : list) {
g.drawImage(gobject.image, gobject.x, gobject.y, (ImageObserver) null);
}
}
More elaborate games may order the gameobjects to get control of how game objects overlap each other. But in principle its incredibly simple.
When I was having problems with filckering Swing components it turned out to be concurrency issues. Since you are doing a game, which means you are doing animation it may be the case here.
Take care to modify Swing components only from AWT-EVENT thread. Either use SwingUtilities.invokeLater or do your animation using javax.swing.Timer.
As a concrete example, Asteroids doesn't flicker at all. Here are a few reasons:
It runs on the event dispatch thread.
It uses JPanel, which is double buffered by default.
It paces the animation using javax.swing.Timer, updating the game's model in actionPerformed().
It overrides paintComponent(), but can safely omit super.paintComponent() because the action listener repaints the entire panel.
The listener calls paintImmediately() to avoid any potential delay; substitute repaint() to see if there's any difference on your platform.
Addendum: As shown in this counter-example, revalidate() does not cause flickering. Instead of replacing labels, update the label's icon, as shown here.
Have you considered reusing them - i.e. using setVisible(false) when they're not needed?
Not sure if adding and removing labels is the best way of achieving what you want for a game.
I'd personally be tempted to manage the drawing myself.
I have been working on Java Swing for a while. I paint something(draw some basic shapes like circle,rectangle etc) on a JDesktopPane and once I resize the frame window that contains jDesktopPane or drag some other window over this frame, then the drawn shapes disappear. I use an object of the BufferedImage class so as to save the image. So Is there any way of preventing the shapes getting disappeared or repaint it when they disappear?
You need to make sure you are saving what you paint and repainting it each time in the paintComponent() method. This method is called automatically whenever a repaint is needed (for example: because of a resize).
I can only provide a guess since you've decided not to post the necessary code, but my suggestions are:
Don't get your Graphics object by calling getGraphics on a component. Instead,
Be sure to do your drawing in a class that subclasses a JComponent or one of its children (such as a JPanel).
draw your BufferedImage in the JComponent's paintComponent method immediately after calling super.paintComponent() in the same method. Use the Graphics object that is provided by the JVM and passed into the method's parameter.
To be sure that your paintComponent method's signature is correct, place an #Override annotation immediately before it. Otherwise if it is not correct, the JVM will probably not call it when you expect it to.
But also, please when asking a question here, try to give us enough information so we don't have to guess. Since your problem is graphics related, it would make sense to post your graphics-related code, right?