paintComponent called continuously - java

Similar problem here but didn't find an answer: Why is paintComponent() continuously and asynchronously being called without explicit repaint() call?
I have a JPanel that I am drawing onto
class DrawPanel extends JPanel {
final void paintComponent(Graphics g) {
super.paintComponent(g);
// some graphics drawing stuff
} }
and then adding this to a JScrollPane. However if I put a system.out.println() in the paintComponent method I can see its continuously being called. Any way to stop this? According to the link its possible due to the jpanel being covered

Generally paintComponent() does not paint continually. It get invoked occasionally when Swing determines it needs be painted.
If your method is being invoked continually then I can think of a couple of possible problems. You are:
manually invoking repaint()
changing a property of the component in the paintComponent() method which then automatically invokes repaint()

The paintComponent calls come from Swing's Event Dispatch Thread. It gets called everytime the component needs to be repainted.
If you resize the component or bring it back from minimized state, then it's repainted. Of course if you cover it with another component then the repainting will be called less. The other component will have a paintComponent method too though.
Nothing to worry about.

Related

Can't understand JPanel setBackground method behavior

JPanel.setBackground method does nothing (although opaque attribute is true) if super.paintComponent father method isn't being called.
I have read a lot of similar questions here about this issue, and in each one of them I've only found solutions without explanation that helped me to understand why setBackground method when written before adding the JPanel to JFrame changes the JPanel background color, while when the setBackground is written inside paintComponent nothing is changed (only when calling father's paintComponent method as already mentioned).
Is it somehow related to Graphics object?
I have tried to change JPanel's opaque attribute to true and using setBackground(COLOR.BLACK) in paintComponent() method I had overriden in a class that extends JPanel
paintComponent(Graphics g)
{
this.setOpaque(true);
this.setBackground(COLOR.BLACK);
}
I expect that the JPanel background color will be black
Instead, background color is the default one
Well, first of all if you're using paintComponent(Graphics g) method, the first line you need to have inside is: super.paintComponent(g) otherwise you're breaking the paint-chain.
This will allow the parent component to draw the default component, before any customizations you do to it. If you don't do it, well, is like having a drawing in a piece of paper, imagine a circle, then cutting that circle and then trying to paint the outside.
Here's a more in-depth answer to How does super.paintComponent(g) works
However I wouldn't write
this.setOpaque(true);
this.setBackground(COLOR.BLACK);
inside the paintComponent(...) method, as it gets called several times and you can't control when it will ever get called. I would put those lines in a constructor, unless you want to change it later in your program while it's being painted depending on the state of your program or a gradient maybe.
For this part:
why setBackground method when written before adding the JPanel to JFrame changes the JPanel background color
Honestly, I don't understand what you mean.
Why do you say that if i won't call super.paintComponent(),it will break the chain? It's still drawing all the shapes and lines i want using graphics object.
From the docs:
The JPanel has a UI delegate which performs the background painting for itself. You call it by using super.paintComponent(g) and we pass the Graphics component to prevent irrevocable changes such as Graphics.translate
Your JPanel knows how to paint its children, but requires some help to paint itself, and this help comes from its parent.
When I mentioned "break the paint chain" I didn't mean nothing would paint, but that you would get strange behaviors such as the one of the JPanel's background disappearing or not being set.
In addition,something weird happens if the argument i'm sending to setBackground method is a random color(using Random object). JPanel changing color very quickly although i'm not doing anything(not minimizing,not resizing,etc).Can you consider why?
As I said before, the paintComponent gets called several times and you don't have control over when it will be called, even moving your mouse or something else will trigger the panel to repaint.

JFrame Repaint() Individual Component

Is it possible to repaint only a specific component in a JFrame, rather than the entire thing? If this is possible, how would you do this?
Yes, you can suggest the repainting of a single component by calling repaint(); on that component only. Per the Component API:
public void repaint()
Repaints this component.
If this component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.

Relationship between paint, paintComponent, repaint, etc

The paint method:
Invoked by Swing to draw components. Applications should not invoke paint directly,
but should instead use the repaint method to schedule the component for redrawing.
This method actually delegates the work of painting to three protected methods:
paintComponent, paintBorder, and paintChildren. They're called in the order listed
to ensure that children appear on top of component itself. Generally speaking,
the component and its children should not paint in the insets area allocated to the
border. Subclasses can just override this method, as always. A subclass that just
wants to specialize the UI (look and feel) delegate's paint method should just
override paintComponent.
Parameters:
g the Graphics context in which to paint
public void paint(Graphics g)
I've read many times not to override paint(), but to override paintComponent() instead. As seen above, the documentation also suggests to override paintComponent() if you want to specialize the UI.
So, I wanted to trace through the code to see why this is so.
protected void paintComponent(Graphics g)
{
if (ui != null)
{
Graphics scratchGraphics = (g == null) ? null : g.create();
try
{
ui.update(scratchGraphics, this);
}
finally
{
scratchGraphics.dispose();
}
}
}
There are many methods to trace through, but for conciseness, here's update():
public void update(Graphics g, JComponent c)
{
if (c.isOpaque())
{
g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(),c.getHeight());
}
paint(g, c);
}
An overloaded version of paint() is called, and paint(), itself, calls paintComponent(). So, I guess I'm just trying to figure out what's going on here exactly. I'm very new to Swing; there are a lot of classes and it's pretty difficult to trace through all of them, especially with my limited knowledge of using GUIs, in general.
Are these methods constantly calling each other, thereby giving the illusion of an image on the screen? If so, why does it matter so much if you override paint() instead of paintComponent? I imagine that my logic is in some way flawed or lacking, considering that for applications, the documentation advises against invoking paint() directly, and instead suggests to invoke repaint(). So, basically, I'm just trying to get some insight into the overall relationship between paint(), paintComponent(), repaint(), etc.
Firstly take a look at...
Performing Custom Painting and
Painting in AWT and Swing
The second should be compulsory reading for all Swing developers.
paint is (within the context of this question) the top level method called (update is actually called first, which just forwards to paint) when the RepaintManager wants a component to be painted.
paint is responsible for (amongst other things) calling paintComponent, paintBorder and paintChildren. If you're not careful you could compromise your components ability to paint. So if you HAVE to override paint, make sure you are calling super.paint.
It's important to note, the if a child component is updated, the parent component may not be repainted, so it don't try and use paint to provide overlays for your component.
paintComponent is responsible for painting the "background" of the component. This basically delegates to the look and feel.
In the case of something like JPanel, it will fill the background with the background color (if set to opaque). In the case of something like JTable, it will paint the rows, columns and cell values.
It is very important to ALWAYS call super.paintComponent, especially when dealing with transparent components.
repaint will make a request to the RepaintManager which may consolidate the paint requests so as to reduce the actual number of paint events that are raised. This helps improve performance.
The important thing to note here is that you don't control the paint process, so don't try, work with it instead.
Your paint method is also expected to run quickly, so avoid time consuming operations, like loading resources, or compound loops where possible. If you can, create backing buffers and paint those instead
ps- Paint is fun ;)

How to successfully modify the way a JFrame (and all of its components) paint?

I'm trying to implement a simple window scale in java's swing library. The goal is simply to double the window height and width, and paint the window and each of its components in scale.
Here's an example of the code I'm using:
public class MyWindow extends JFrame {
...
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.scale(2,2);
super.paint(g);
}
}
The position and size for each my components in this window is set manually using setBounds with a null layout for the window.
When I actually run the program, what happens is that the first paint for the window seems successful-- everything is sized appropriately. Each subsequent repaint by the components, however, is neither twice the size, nor in the proper location. Here's what I mean:
As you can see, portions of the screen which have components that call repaint manually (the animating bits), don't seem to be using the Graphics2D scale of the JFrame. I looked in the source code, and tried overloading a few other methods (update and repaint, mostly), but all of them seemed to produce the same result. I further looked at the paint and repaint methods of the component and container classes, but they all seem to call a specified repaint of their parent. Shouldn't my Window be the "biggest" parent? If so, why haven't these repaint calls reached my Window?
My big question to you is, therefore: what repaint methods of the parent component do the child components call? Why aren't the calls properly routed to my JFrame's paint call? Is there any other (better) way that I can scale my window? Any and all help is appreciated!
As discussed in Painting in AWT and Swing: The Paint Methods, "Swing programs should override paintComponent() instead of overriding paint()." A common approach is to create a view by overriding paintComponent() in a JComponent (or subclass), as shown here. Let your view listen for changes to the game's model, as discussed here.
SwingUtilities.updateComponentTreeUI() should be used to change the Look & Feel, not update the view.
Use
javax.swing.SwingUtilities.updateComponentTreeUI(parentComponent);
when you need to make sure all of the parentComponents child component's look and feel are updated properly.

Multi Threading and graphics

My project is based on multi threading and graphics. The problem is in calling repaint() method. I am trying to call repaint method from class second which implements runnable and paint() method is in class first extending Canvas. But repaint not working.
What should I do?
Thnx
It would be much wise, that instead of using Canvas, if you override the paintComponent(...) method of a JComponent and paint on it, instead of overriding paint(...) method.
The Component.repaint() method, under Swing in particular, only marks the component as needing a repaint, it doesn't actually trigger the repaint directly.
Make sure you allow other threads to run by calling Thread.yield(), as it's the main graphics thread (which launched your other thread(s)) that actually checks the components to see what needs to be repainted.

Categories

Resources