0

My goal is to have the custom JComponent paint a rectangle at it's location and also paint an image if it has one. Right now, when I run the code it paints only the image at sprites/0.png, and also paints two black lines around the upper left hand corner. It doesn't paint any other rectangles or images. Below is my my custom JComponent class:

 public class GameSpace extends JComponent {
        private static final long serialVersionUID = 1L;
        private Image imageAtSpace = null;
        public static final int DEFAULT_WIDTH = 100;
        public static final int DEFAULT_HEIGHT = 100;
        public GameSpace() {
            setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        }
        public GameSpace(int x, int y) {
            this();
            setLocation(x, y);
            setVisible(true);

        }
        /*
      Other constructors removed for brevity
      */
        public void setImage(Image image) {
            this.imageAtSpace = image;
        }
        public void removeImage() {
            this.imageAtSpace = null;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLACK);
            g.drawRect(getX(), getY(), getWidth(), getHeight());
            if (!isEmpty())
                g.drawImage(imageAtSpace, getX(), getY(), this);
        }
        public boolean isEmpty() {
            return imageAtSpace == null;
        }
    }

And here is the class that creates the panel and JFrame:

public class GameView {
    JPanel mainGamePanel;
    private static final int DEFAULT_NUM_SPOTS = 16;
    private static final int SPOTS_PER_ROW = 4;
    private static final int SPOTS_PER_COLUMN = 4;
    private static final int DEFAULT_WIDTH = GameSpace.DEFAULT_WIDTH;
    private static final int DEFAULT_HEIGHT = GameSpace.DEFAULT_HEIGHT;
    Map<Integer, GameSpace> gameSpaces = new HashMap<Integer, GameSpace>();
    public GameView() {
        mainGamePanel = defaultLoad();
    }

    private JPanel defaultLoad() {
        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setFocusable(true);
        panel.setSize(400, 400);
        int startX =0;
        int startY = 0; 
        for (int i = 0; i < DEFAULT_NUM_SPOTS; i++) {
            int xLocation = startX + (i % SPOTS_PER_ROW)*DEFAULT_WIDTH;
            int yLocation = startY + (i / SPOTS_PER_COLUMN)*DEFAULT_HEIGHT;
            GameSpace gs = new GameSpace(xLocation, yLocation);
            gs.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
            gs.setImage(new ImageIcon(this.getClass().getResource("/sprites/" + i + ".png")).getImage());
            gameSpaces.put(i, gs);
            panel.add(gs);
            panel.revalidate();
            panel.repaint();
        }
        panel.setVisible(true);
        return panel;
    }
    public static void main(String...args) {
        JFrame frame = new JFrame("test");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new GameView().mainGamePanel);
        frame.setSize(400, 400);
        frame.revalidate();
        frame.repaint();
        frame.setVisible(true);


    }

}

I'm still a bit unsure of when I need to revalidate/repaint, so I kind of just threw it everywhere in an attempt to solve the problem, apologies if there's any redundancy. Any help for why it's not painting a grid of rectangles with images inside of them would be appreciated. Even if I comment out adding the image, it won't paint rectangles.

asdf
  • 35
  • 3
  • 1) Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). In this case, the custom painted panel should override `getPreferredSize`. 2) One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson Dec 21 '17 at 00:10
  • 2
    Using `getX()` and `getY()` in your `paintComponent` is going to offset the rectangle by `getX() * 2` and `getY() * 2` as the these values return the location of the component within the parent's coordinate space. A component's `Graphics` context is automatically translated so that `0x0` is the top left corner of the component. You could have look at [this question/answer](https://stackoverflow.com/questions/47914227/some-issues-with-paintcomponent/47915385#47915385) which is similar issue – MadProgrammer Dec 21 '17 at 00:12
  • 1
    Generally speaking, this is a poor use case for extending `JComponent`. Instead, you should have a single component which acts as the "surface" onto which other elements are painted, this saves you a lot of hassle with messing with `null` layouts and attempting to convert between different coordinate spaces – MadProgrammer Dec 21 '17 at 00:13

0 Answers0