Using Draw again vs Repaint - java

I'm trying to figure out if the repaint method does something that we can't do ourselves.
I mean,how are these two versions different?
public class Component extends JComponent {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle r = new Rectangle(0,0,20,10);
g2.draw(r);
r.translate(5,5);
g2.draw(r);
}
}
and
public class Component extends JComponent {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle r = new Rectangle(0,0,20,10);
g2.draw(r);
r.translate(5,5);
repaint();
}
}

The 2nd version can result in a very risky and poor animation since it can result in repaints being called repeatedly, and is something that should never be done. If you need simple animation in a Swing GUI, use a Swing Timer to drive the animation.
i.e.,
public class MyComponent extends JComponent {
private Rectangle r = new Rectangle(0,0,20,10);
public MyComponent() {
int timerDelay = 100;
new Timer(timerDelay, new ActionListener(){
public void actionPerformed(ActionEvent e) {
r.translate(5, 5);
repaint();
}
}).start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.draw(r);
}
}
The use of repaint() is to suggest to the JVM that the component needs to be painted, but it should never be called in a semi-recursive fashion within the paint or paintComponent method. An example of its use can be seen above. Note that you don't want to call the painting methods -- paint or paintComponent directly yourselves except under very unusual circumstances.
Also avoid calling a class Componenet since that name clashes with a key core Java class.

Related

Java Swing or AWT repaint frequency

I tried to make a simple game in Java and ended up with this code
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
ball.paint(g2d);
}
...
while (true) {
repaint();
Thread.sleep(10);
}
It redraws not frequently enough. But if I move my mouse on top of the window it starts to repaint much more frequently. Pressing buttons on keyboard speeds up too.
I'm using Arch with i3wm.
Don't trust guides on the internet. Think yourself sometimes.
It was the guide with mistake. The problem is that the algorithm is wrong. We just have to draw more frequently than update our world.
Here is a stupid implementation of this. It should may be really wrong in terms of concurrency.
Timer timer1 = new Timer(1, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
game.repaint();
}
});
timer1.start();
Timer timer2 = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
game.move();
}
});
timer2.start();
I had exactly the same problem. Two timers didn't work for me. I managed to move an object smoothly by adding rendering hints and drawing an empty rectangle before my main object:
public void paintComponent(Graphics g) {
g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE)
g2d.fillRect(0, 0, getWidth, getHeight)
// paint your object here
}

Overriding paintComponent twice

This is more of a conceptual question, so it's hard to post a small workable code sample. But, I have a class that overrides paintComponent here:
public abstract class BasePanel extends JPanel {
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
this.standardDraw(drawObjects,g2);
}
}
Basically, I'd like this to be the "standard way" this base panel draws if paintComponent is not overridden in a derived class. So, I have a derived class called AspectRatioPanel which I'd like to re-specify how it draws things:
public class AspectRatioPanel extends BasePanel {
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
// Get ViewPort Bounding Box to clip
BoundingBox viewPortBoundingBox = this.getViewPortBoundingBox();
// Clip to viewport
g2.setClip((int)viewPortBoundingBox.topLeft.getX(),(int)viewPortBoundingBox.topLeft.getY(),(int)viewPortBoundingBox.getWidth(),(int)viewPortBoundingBox.getHeight());
this.standardDraw(drawObjectsBuf,g2);
}
}
The problem I'm having is the call super.paintComponent(g) in the derived class. I intend for it to be calling paintComponent in JComponent, but it is going through BasePanel first. Is there a better way to approach this problem? I could delete the paintComponent method in BasePanel, but having a standard way of drawing things is useful for me. I also can't seem to call JComponent.paintComponent directly since it's protected. Is there a solution for this? Also, am I doing something conceptually wrong?
Probably I misunderstood your problem, but I would separate standard and custom painting
public abstract class BasePanel extends JPanel {
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
provideCustomPainting(g);
}
protected void provideCustomPainting(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
this.standardDraw(drawObjects,g2);
}
}
public class AspectRatioPanel extends BasePanel {
protected void provideCustomPainting(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
// Get ViewPort Bounding Box to clip
BoundingBox viewPortBoundingBox = this.getViewPortBoundingBox();
// Clip to viewport
g2.setClip((int)viewPortBoundingBox.topLeft.getX(),(int)viewPortBoundingBox.topLeft.getY(),(int)viewPortBoundingBox.getWidth(),(int)viewPortBoundingBox.getHeight());
this.standardDraw(drawObjectsBuf,g2);
}
}
You could simply not call super.paintComponent(Graphics); by overwriting paintComponent() you have 3 options:
a.) Call super at the beginning of the method; you paint code paints on top of what has been painted by the super class.
b.) Don't call super at all - your paintComponent needs to ensure it paints everything that is needed; if the components is opaque that means you need to paint the entire area the component occupies.
c.) Call super at your convinience; whatever is painted in super appears to be "layered" in sequence where you call it. Makes only sense if the super method doesn't paint the entire area.
If you insist to use paintComponent from a specific class of your inheritance hierarchy as super.paintComponent, regardless of inheritance hierarchy in between, thats also possible:
BasePanel extends JPanel {
protected final defaultPaintComponent(Graphics g) {
super.paintComponent(g);
}
}
Child classes can call "defaultPaintComponent" instead of super.paintComponent, thus bypassing any implementation classes in between in the hierarchy defined (I suggest declaring it final to prevent accidental overwrites).

Java setBackground() confusion

I'm new to the Java swing library and I'm currently having some trouble setting the background of my JFrame.
I have read jframe-setbackground-not-working-why and the link inside it, but it doesn't seem to fit here.
Here is my codes:
public class Board extends JPanel{
public enum pointType{
EMPTY,
CARRIER,
BALL;
}
private class Point{
int x;
int y;
pointType type;
public void paint (Graphics2D g2){
// color changes depends on pointType
g2.setColor(Color.WHITE);
g2.fillOval(x,y,25,25);
}
}
Point[][] myBoard;
public Board(){
//constructor, myBoard = 2d List of points
}
//.. other methods and class variables
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
for(int k =HEIGHT; k>=0; k--){
for(int i=WIDTH; i>=0; i--){
// call paint method for each points on board
myBoard[i][k].print(g2);
}
}
}
public static void main(String[] args){
Board board = new Board();
JFrame myFrame = new Jframe("Game");
myFrame.add(board);
board.setBackground(Color.YELLOW);
myFrame.setVisible(true);
mtFrane.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
My code successfully prints all the points according to their pointType, but the board color is not set correctly (still default background).
So here are the questions:
1) How should I set the background correctly?
2) I feel that my code is not using JPanels/JFrames/Graphics together correctly, if that's the case, any suggestions on how I improve my code structures?
Use paintComponent() instead of paint()
public class Board extends JPanel{
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
...
}
}
For more info have a look at below posts:
Difference between paint() and paintcomponent()?
paint() vs. paintComponent(): A Resolution
The default paintComponent() method in JPanel uses the background color stored in the JPanel's instance variable; however, your overridden paintComponent() method doesn't make use of the instance variable and so changing it with setBackground() won't do anything.
If you want to stick with overriding the paintComponent() method, you should draw a box filling the entire area of the JPanel with the color which you want inside the paintComponent() method.
The new paintComponent() method for Board would look like this:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.YELLOW);
g2.fillRect(0, 0, getWidth(), getHeight()); // Fill in background
// Do everything else
for(int k =HEIGHT; k>=0; k--){
for(int i=WIDTH; i>=0; i--){
// call paint method for each points on board
myBoard[i][k].print(g2);
}
}
}

Does invoking the drawRect method on a Graphics2D trigger the paintComponent method?

I'm trying to figure out the behavior of my program, and that is my best theory as to why its doing what its doing. I was hoping this would use the rand variable to decide which shape to paint, but instead it seems the paintComponent method is being invoked many times in-between timer firings, causing many shapes to be painted and I'm trying to understand why.
This is the code:
public class TestPane extends JPanel {
private int yPos0;
private int yPos1;
private int boundary0=750;
private ActionEvent ae = null;
private Graphics g0 = null;
private int count=1;
public TestPane(Color foreground){
setForeground(foreground);
this.setBackground(Color.BLUE);
Timer timer = new Timer(3000,new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
ae = e;
yPos0 =yPos0+50;
repaint();
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g){
g0 = g;
super.paintComponent(g);
createShape(yPos0);
repaint();
}
public void createShape(int ypos0){
//generate random number between 1 and 3 and assign to rand
int rand = (int)((Math.random()*3)+1);
System.out.println(rand);
if(rand==1){
Graphics2D g2d = (Graphics2D) g0.create();
g2d.setColor(Color.RED);
g2d.drawRect(0, ypos0, 200, 50);
}
if(rand==2){
Graphics2D g2d = (Graphics2D) g0.create();
g2d.setColor(Color.GREEN);
g2d.drawRect(0, ypos0, 150, 50);
g2d.drawRect(50, ypos0+50,50,50);
}
}
}
The reason that paintComponent is being called so many times is that you are calling repaint within that method which causes itself to be called ad infinitum. This is not needed as you're already calling repaint from your Timer.

how to use method of one class in another class

here is first class
// extending class from JPanel
public class MyPanel extends JPanel {
// variables used to draw oval at different locations
int mX = 200;
int mY = 0;
// overriding paintComponent method
public void paintComponent(Graphics g) {
// erasing behaviour – this will clear all the
// previous painting
super.paintComponent(g);
// Down casting Graphics object to Graphics2D
Graphics2D g2 = (Graphics2D) g;
// changing the color to blue
g2.setColor(Color.blue);
// drawing filled oval with blue color
// using instance variables
g2.fillOval(mX, mY, 40, 40);
now i want to use the method g2.setColot(Colot.blue) in the following where the question marks are.
// event handler method
public void actionPerformed(ActionEvent ae) {
// if ball reached to maximum width of frame minus 40 since diameter of ball is 40 then change the X-direction of ball
if (f.getWidth() - 40 == p.mX) {
x = -5;
????? set the color as red ????????
}
Add a Color member to your class. When you want to change the color, change to value of the member and call repaint():
public class MyPanel extends JPanel {
int mX = 200;
int mY = 0;
Color myColor = Color.blue; //Default color is blue,
//but make it whatever you want
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(myColor);
g2.fillOval(mX, mY, 40, 40);
}
public void actionPerformed(ActionEvent ae) {
if (f.getWidth() - 40 == p.mX) {
x = -5;
myColor = Color.red;
repaint();
}
}
If I understand what you need is to make Graphics2D g2 a class attribute. This way all the methods in your class can access that "global" variable:
public class MyPanel extends JPanel {
Graphics2D g2;
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2 = (Graphics2D) g;
...
}
public void actionPerformed(ActionEvent ae) {
g2.setColor(...);
}
}

Categories

Resources