What is the JPanel/Graphics method paintComponent? - java

So I'm trying to learn Java graphics and this bit of code has me perplexed. I don't understand a couple things here:
Why is paintComponenet used twice for the name of the method and as
we call a method from super (JPanel)?
What is Graphics g, isn't it just a reference variable for an object
of Graphics since we don't set it equal to = new Graphics();?
Why does the method name in my class have to be paintComponent to
call upon the method paintComponent from JPanel or super?
The method in my class paintComponent takes the parameter of a
Graphics object but when does paintComponent even get called and
when is the parameter of Graphics inserted?
Essentially I need someone to explain this code to me.
//note this is all in a class that extends JPanel, my JPanel is later placed in
//a JFrame which is run through main
public void paintComponent(Graphics g)
{
int width = getWidth();
int height = getHeight();
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(10, 10, 200, 200);
g.setColor(Color.BLUE);
g.drawRect(10, 10, 200, 200);
}

Why is paintComponenet used twice, for the name of the method and as we call a method from super (JPannel)
It's not "used" twice. It is overridden once, but you want to call the parent (JPanel) class's super method so that you're sure that it does its own house-keeping painting, including painting its children and clearing out any dirty bits from the screen.
What is Graphics g, isn't it just a reference variable for an object of Graphics since we don't set it equal to = new Graphics();
It's a Graphics parameter. You don't set it = new Graphics() because the JVM does this for you. It calls the method behind the scenes when needed, and provides the parameter.
Why does the method name in my class have to be paintComponent to call upon the method paintComponent from JPannel or super
It has to override the super's method so that the JVM calls the right method when it wants to draw the GUI.
The method in my class paintComponent takes the parameter of a Graphics object but when does paintComponent even get called and when is the parameter of Graphics inserted.
Again, it is called by the JVM when either your program wants to repaint the GUI, such as when you call repaint() or when the operating system wants to repaint a window such as if a window is minimized and restored.
You really really want to read the graphics tutorials:
Lesson: Performing Custom Painting: introductory tutorial to Swing graphics
Painting in AWT and Swing: advanced tutorial on Swing graphics

1) Why is paintComponenet used twice, for the name of the method and as we call a method from super (JPannel)
Here the line super.paintComponent(...), means we want the JPanel to be drawn the usual Java way first (this usually depends on the opaque property of the said JComponent, if it's true, then it becomes the responsibility on the part of the programmer to fill the content area with a fully opaque color. If it is false, then the programmer is free to leave it untouched. So in order to overcome the hassle assoicated with this contract, super.paintComponent(g) is used, since it adheres to the rules, and performs the same task, depending upon whether the opaque property is true or false).
2) What is Graphics g, isn't it just a reference variable for an
object of Graphics since we don't set it equal to = new Graphics();
and
4) The method in my class paintComponent takes the parameter of a
Graphics object but when does paintComponent even get called and when
is the parameter of Graphics inserted
paintComponent method is where all of your painting code should be placed. It is true that this method will be invoked when it is time to paint, but painting actually begins higher up the class heirarchy, with the paint method (defined by java.awt.Component.) This method will be executed by the painting subsystem whenever you component needs to be rendered. Its signature is:
public void paint(Graphics g)
javax.swing.JComponent extends this class and further factors the paint method into three separate methods, which are invoked in the following order:
protected void paintComponent(Graphics g)
protected void paintBorder(Graphics g)
protected void paintChildren(Graphics g)
The API does nothing to prevent your code from overriding paintBorder and paintChildren, but generally speaking, there is no reason for you to do so. For all practical purposes paintComponent will be the only method that you will ever need to override

Related

How do I draw something in a JPanel after I already called the paintComponent method

I'm new to making GUIs in Java. As I understand, there's a class called Graphics which is in charge of drawing shapes in a JPanel. When my application starts, I call the paintComponent method, which draws the board of the game I'm programming, and the paintComponent method takes a Graphics g as input. However, later on, I want to update the board, so how do I tell the same g that drew the board at the start of the game to draw something else when the user does something like clicking?
I believe this should have a very simple answer.
Every JComponent (Swing component) has a repaint() method, just call it to tell the DrawingManager to redraw your component.
All your drawing code should be in paintComponent method, that means that you don't draw anything anywhere else (you draw only in the flow of invocation of paintComponent, you can have drawing code structured in methods of course).
This method needs to have access to the state that indicates what and where should be drawn. It is because the OS could request repainting, and then only the painting methods from JComponent are called.
When you invoke repaint() on your JComponent, then in short time the paintComponent() method of the component on which you requested repainting will be called by the drawing thread, and you should draw only in this drawing thread.
Try repaint() or revalidate(), it should work.
I call the paintComponent method
No, you should never call the paintComponent() method directly. Swing will call the method for you when the component needs to be repainted.
I want to update the board
Then you need a "setter" method. Think of other Swing components. They have methods like "setForeground(), setBackground(), setText()" etc.
So if you want to change your component then you need to create appropriate setter method to change the properties of your class. Then in the method you save the property and simply invoke repaint() and Swing will repaint your component. So now your paintComponent() method needs to check the property you just set to do the appropriate painting.
public void setSomeProperty(Obect someProperty)
{
this.someProperty = someProperty;
repaint();
}
....
protected void paintComponent(Graphics g)
{
super.paintComponent();
// paint the board
if (someProperty != null)
// paint the property
}

how to override the paint method without stopping its functionality

So my assignment wants me to create an applet but as an extra I'm supposed to use the paint method to draw a string, for example:
public void paint(Graphics g){
g.drawString("name, name name", 400,100);
}
My problem is that this pretty much prevents the rest of my app from painting.

Is `super.paintComponent(g)` mandatory?

I was taught in my class and also seen in this book (Big Java Early Objects) to include draw instructions in a class extending JComponent as:
public class Component extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle r = new Rectangle(0,0,20,10);
g2.draw(r);
}
}
However, someone pointed out that the first line in the paintComponent method should be: super.paintComponent(g);
Based on my limited knowledge, I believe it's calling JComponent's version of the method (now overridden). Why does this need to happen? What happens if I just ignore this statement as I've been doing until now?
Why does this need to happen? What happens if I just ignore this statement as I've been doing until now?
A component is responsible for painting itself completely. The default painting may be different for each LAF, so by invoking super.paintComponent() you make sure you get the default painting which will basically just be the background.
If you don't invoke this method you have the potential for painting artifacts to occur. Then may not always occur, but you don't want to waste time debugging.
Read the API for the paintComponent() method of JComponent. Among other things it states:
Further, if you do not invoker super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts.
So at a minimum you need:
g.fillRect(0, 0, getWidth(), getHeight());
to make sure the background is cleared before you start your custom painting.

Java graphics paint method execution flow

I came across this code. I thought I alleviate this confusion before I run into any hiccups along the way in programming. I am having trouble understanding whether the paint or the actionPerformed method gets executed first in Board class. I hope my java comments are correctly stated.
The thing is, I took introductory Java in the summer and graphics was only introduced towards the end of the course. The class used ImageIcon and we never touched the drawImage method and Image abstract class. I also do not understand the paint method at all. This code is more involved than the Java graphics lecture I had. Based on the Java API, the paint method originated from the JComponent class which is JPanel's superclass.
So what is this parameter Graphics g that the paint method takes in all about and how should I think about it? How does the paint method know which object of a graphics class to paint. I looked at the Java API and it says Graphics is an abstract class. How can g be an object if its data type is abstract? I am saying g is an object because the code is calling the drawImage method on the object g.
On a side note, does repaint method mean erase the content in the JPanel and redraw the entire component like rendering?
public class Board extends JPanel implements ActionListener{
private Image apple;
private int apple_x;
private int apple_y;
// over-riding the paint method from the JComponent Class
public void paint(Graphics g){
// recursively call the paint method
super.paint(g);
g.drawImage(apple, apple_x, apple_y, this);
}
// does this method gets called first or the top one?
public void actionPerformed(ActionEvent e) {
repaint();
}
}
Drawing in Java (and basically all current windowing systems) follows the Hollywood principle:
You don't call me; I call you.
I.e. you can tell the system that a certain area will need to be redrawn (repaint()). But you'll have to wait until the system calls you to do the drawing. In Java, the system will call the paint() method and will pass you a Graphics instance to use for drawing.
So the order of event is:
actionPerformed()
paint()
Graphics is often called a graphics context. It's an object used for drawing. Depending on the system and the current requirements, the drawing might go directly on the screen or into an offscreen buffer that is later copied to the screen. The Graphics instance takes care of the details.
Someone can correct me if I am wrong.
Yes, graphics is an abstract class. But an instance of any class that inherits Graphics (such as Graphics2D) can be passed as graphics. If I recall correctly this is call upcasting. g is passed by the UI thread that called paint(), either because the object was invalidated, or has to be updated.
The graphics object is a reference to the actual bitmap that appears to the user.

Change JPanel default graphics

when I have JPanel, it has it´s default Graphics which is passed to paint(Graphics g) and similiar function. Can I somehow switch that default Graphics for my own? From outside of the JPanel class? I am looking for something like JPanel.setGraphics(Graphics g). Thank you.
No, but you may override its paintComponent method, cast the Graphics object passed as argument to Graphics2D, and draw whatever you want on it.
As far as I know, the only way to control which Graphics object is passed around is to enable the debug graphics option. This is done by calling JComponent.setDebugGraphicsOptions(int), which will replace the original Graphics object by an instance of javax.swing.DebugGraphics.
The instanciation of DebugGraphics is hardcoded in the method getGraphics of class JComponent, so I see no way to use your own implementation here (other than using the instrumentation of the JVM to rewrite the code, as mock libraries do).

Categories