Reputation: 49
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
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
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