odeng
odeng

Reputation: 49

PaintComponent is not being called-Java

My code is supposed to draw a random sized image three times in random locations. For some reason, when I run this code using BlueJ, all that shows up is a gray screen. I think it is because PaintComponent isn't being called, but I am not quite sure. What went wrong with my code and how can I fix it?

class PanelHolder extends JPanel{//class PanelHolder extends JPanel
//variables
public boolean threesharks;
public int xcoord;
public int ycoord;
public int ratio;
public Image i;
public int w;
public int h;
public boolean background=true;
Color water = new Color(136, 180, 231);


public PanelHolder(){//constructor

    i = Toolkit.getDefaultToolkit().getImage("$harkz.png");

}
public void randomxy(){
    for(int x=0;x<3;x++){
        threesharks=true;
        ycoord=(int)(Math.random()*300+200);//use math.random to figure out coordinates and sizing
        xcoord=(int)(Math.random()*1000+0);//make a loop
        ratio=(int)(Math.random()*5+1);
        w=ratio*523;
        h=ratio*195;
        repaint();
        System.out.println("I'm in randomxy");

        //call repaint() each time
        //after three times, make threesharks=false
    }
    threesharks=false;
}
public void paintComponent(Graphics g){
    if(threesharks){
        setBackground(water);
        System.out.print("hi!");
        if(background){
            super.paintComponent(g);//set backgroun
            background=false;
        }
        g.drawImage(i, xcoord, ycoord, w, h, this);
    }
    }

}

Upvotes: 1

Views: 233

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347204

You seem to have a misunderstanding with how painting works in Swing. Swing will call your paintComponent when ever it thinks your component needs to be repainted, this might occur for many different reasons, many of which you don't have control over.

Painting in Swing is destructive, that is, each time your paintComponent method is called, you are expected to repaint the entire state of the component from scratch, painting is not accumalitive.

This means that you need to store the state of things you want to paint in some meaningful manner and re-use these values are needed.

Have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing

Random Ponies

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new PanelHolder());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    class PanelHolder extends JPanel {//class PanelHolder extends JPanel
//variables

        public boolean threesharks;
        public BufferedImage i;
        public boolean background = true;
        Color water = new Color(136, 180, 231);

        private Point[] points;
        private Image[] images;

        public PanelHolder() {
            //constructor

            try {
                i = ImageIO.read(...);
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            randomxy();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(800, 800);
        }

        public void randomxy() {
            points = new Point[3];
            images = new Image[3];
            for (int x = 0; x < 3; x++) {
                points[x] = new Point();

                double ratio = (Math.random() * 6d) + 0.1d;
                int width = (int) (ratio * i.getWidth());
                int height = (int) (ratio * i.getHeight());
                points[x].y = Math.max(0, (int) (Math.random() * 800) - height);//use math.random to figure out coordinates and sizing
                points[x].x = Math.max(0, (int) (Math.random() * 800) - width);//make a loop

                images[x] = i.getScaledInstance(width, height, Image.SCALE_SMOOTH);

            }
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);//set backgroun
            g.setColor(water);
            g.fillRect(0, 0, getWidth(), getHeight());
            if (points != null && images != null) {
                for (int index = 0; index < points.length; index++) {
                    g.drawImage(images[index], points[index].x, points[index].y, this);
                }
            }
        }
    }

}

This is a rough example, which uses Image#getScaledInstance which is not generally recommended, but works for the example.

Have a look at The Perils of Image.getScaledInstance() for more details

Have a look at Quality of Image after resize very low -- Java and Java: maintaining aspect ratio of JPanel background image for possible (scaling) alternatives

I'd also have a look at Reading/Loading an Image for a better mechanism for loading images

Upvotes: 1

Related Questions