3

I have a panel which extends JPanel and overrides method paintComponent(Graphics g) which draw some squares.

public class Painter extends JPanel{

    private static final Color orange = new Color(225, 95, 0);

    private Block[][] blocks;
    private int sizeBlock;

    public Painter() {
        this.setBackground(Color.WHITE);
    }

    public void setBlocks(Block[][] blocks) {   
        this.blocks = blocks;   
    }

    public void setSizeBlock(int size) {    
        this.sizeBlock = size;  
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);

        for(Block[] cols : blocks) {
            for(Block block : cols) {

                switch(block.getType()) {

                    case Block.wall: {

                        paintBlockLineBorder(g, block.getX()*(sizeBlock-1),
                                                block.getY()*(sizeBlock-1), orange);
                        break;

                    }

                    default: {break;}
                }           
            }       
        }       
    }

    private void paintBlockLineBorder(Graphics g, int x, int y, Color color) {

        //background
        g.setColor(color);
        g.fillRect(x, y, sizeBlock, sizeBlock);

        //border
        g.setColor(Color.BLACK);
        g.drawRect(x, y, sizeBlock-1, sizeBlock-1);

    }
}

I add this JPanel (Painter) into other JPanel (painterPanel) which is added to a JFrame with layout GridBagLayout.

The result is not how I want:

This is what I want:

Here is a little use-case which reproduces the problem:

public static void main(String[] args) {

    JFrame mainFrame = new JFrame();
    mainFrame.setLayout(new GridBagLayout());
    mainFrame.setBounds(100, 100, 500, 400);
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    GridBagConstraints gbc = new GridBagConstraints();
    gbc.anchor = GridBagConstraints.NORTHWEST;
    gbc.fill = GridBagConstraints.NONE;
    gbc.gridx = 0; gbc.gridy = 0;
    gbc.weighty = 1; gbc.weightx = 1;

    JPanel painterPanel = new JPanel();
    painterPanel.setBorder(BorderFactory.createLineBorder(Color.black));

    mainFrame.add(painterPanel, gbc);

    Painter apainter = new Painter();

    painterPanel.add(apainter);

    Block[][] ablock = new Block[2][2];
    ablock[0][0] = new Block(0, 0, Block.wall);
    ablock[0][1] = new Block(0, 1, Block.wall);
    ablock[1][0] = new Block(1, 0, Block.wall);
    ablock[1][1] = new Block(1, 1, Block.wall);

    apainter.setBlocks(ablock);
    apainter.setSizeBlock(25);

    apainter.repaint();

    mainFrame.setVisible(true);     
}

and here is Block class:

public class Block {

    public static final String wall = "wall";

    private int x;
    private int y;
    private String type;

    public Block(int x, int y, String type) {

        this.x = x;
        this.y = y;
        this.type = type;
    }

    //getters & setters
}

Why is my Painter not completely visible?

Abra
  • 19,142
  • 7
  • 29
  • 41
KunLun
  • 3,109
  • 3
  • 18
  • 65
  • @CarlosHeuberger while there are other things in that code that should be tweaked, yes, that is the crux of the problem. – Andrew Thompson Jan 01 '19 at 12:28
  • @CarlosHeuberger I overrided `getPreferredSize`, `getMinimumSize` and `getMaximumSize` and now it works. Can you create an short answer, to choose answer? @AndrewThompson what should be optimized? – KunLun Jan 01 '19 at 12:32
  • 1
    Too much to go into. Start with: A loop for making the array of all blocks, `pack()` to size the frame, the `repaint()` before `setVisible(..)` is redundant and will be ignored, .. OK that might be the main parts of it. ;) – Andrew Thompson Jan 01 '19 at 13:23
  • @AndrewThompson Please, let's talk about here: https://chat.stackoverflow.com/rooms/186009/room-for-kunlun-and-andrew-thompson – KunLun Jan 01 '19 at 13:43
  • *"let's talk about here:"* Thanks, no. I don't 'chat' on SO. – Andrew Thompson Jan 01 '19 at 13:48
  • @AndrewThompson In my project I call `repaint()` after `setVisible()`. The idea was to show that I call `repaint()` after I add `painterPanel` and `setBlocks` and `setSizeBlock`. Also in my project I call `pack()`. How I could get all elements from an array with two indexes with just a single loop, but still keep a clear code? It will be more efficient than two loops? – KunLun Jan 01 '19 at 14:12
  • 1) `repaint()` is ignored unless the component is visible. 2) A pity the example code did not. 3) Yes, I meant two loops. One for each dimension of the array. – Andrew Thompson Jan 01 '19 at 14:17
  • @AndrewThompson Oh...you are talking about building blocks. You was taking too serious my _"little usecase which reproduce the problem"_ . The idea was to reproduce my problem. – KunLun Jan 01 '19 at 14:25
  • Agree with Andrew Thompson, where are all the "essential" codes for your main frame? Make sure the size of the panel is set, add the panel to the frame, pack() the frame, set visibility to true.. make sure all these are done and in the right order. Then try to paint 1 block first. Only if that shows, try to paint other blocks with your loops. It is not necessary to call repaint in the main method. pack() on the frame will resize the frame which implicitly repaints all content within it. – user3437460 Jan 02 '19 at 06:41

2 Answers2

0

Try the following :

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main{

    public static void main(String[] args) throws InterruptedException{

            JFrame mainFrame = new JFrame();

            Block[][] ablock = new Block[2][2];
            ablock[0][0] = new Block(0, 0, Block.wall);
            ablock[0][1] = new Block(0, 1, Block.wall);
            ablock[1][0] = new Block(1, 0, Block.wall);
            ablock[1][1] = new Block(1, 1, Block.wall);

            Painter apainter = new Painter();
            mainFrame.add(apainter);
            apainter.setBlocks(ablock);
            apainter.setSizeBlock(25);

            mainFrame.pack();
            mainFrame.setVisible(true);
    }
}

class Painter extends JPanel{

    private static final Color orange = new Color(225, 95, 0);

    private Block[][] blocks;
    private int sizeBlock;

    public Painter() {

       setBackground(Color.WHITE);
       setBorder(BorderFactory.createLineBorder(Color.black));
       setPreferredSize(new Dimension(400, 300));
    }

    public void setBlocks(Block[][] blocks) {

        this.blocks = blocks;
    }

    public void setSizeBlock(int size) {
        sizeBlock = size;
        //you may want to update Preferred Size
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);

        for(Block[] cols : blocks) {
            for(Block block : cols) {

                switch(block.getType()) {

                    case Block.wall: {

                        paintBlockLineBorder(g, block.getX()*(sizeBlock-1),
                                                block.getY()*(sizeBlock-1), orange);
                        break;
                    }

                    default: {break;}

                }
            }
        }
    }

    private void paintBlockLineBorder(Graphics g, int x, int y, Color color) {

        //background
        g.setColor(color);
        g.fillRect(x, y, sizeBlock, sizeBlock);

        //border
        g.setColor(Color.BLACK);
        g.drawRect(x, y, sizeBlock-1, sizeBlock-1);

    }
}

class Block {

    public static final String wall = "wall";

    private final int x;
    private final int y;
    private final String type;

    public Block(int x, int y, String type) {

        this.x = x;
        this.y = y;
        this.type = type;
    }

    int getX() {return x;   }
    int getY() {return y;   }
    String getType() {  return type;}
}

Don't hesitate to ask for clarifications as needed.
Also consider making a grid using GridLayout : 1 2

c0der
  • 18,467
  • 6
  • 33
  • 65
0

At advice of @CarlosHeuberger I overrided getPreferredSize, getMinimumSize and getMaximumSize which return a Dimension with values based on lengths of blocks and value of sizeBlock

KunLun
  • 3,109
  • 3
  • 18
  • 65