2

There is constructor of class extending JFrame:

import java.awt.*;
import javax.swing.*;

public class ChessFrame extends JFrame {
    public ChessFrame () {
        setSize(520, 520);
        setResizable(false);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 1));

        // Add components
        getContentPane().add(new Board());
        pack();
        setVisible(true);
    }
}

And class extending JPanel:

import javax.swing.*;

public class Board extends JPanel {
    public Board() {
        setSize(new Dimension(520, 520));
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.fillRect(0, 0, 520, 520);
    }

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

As a result rectangle smaller then 520x520. enter image description here

Size of black rectangle is about 496x510. There is more:

  1. getWidth() and getHegiht() written inside the Board class, returns 0 and 0 (so size of this JPanel into JFrame is 0x0)
  2. If I remove pack(), size of frame becomes 496x510 (black rectangle size)

It's actually copypaste of official java tutorial: https://docs.oracle.com/javase/tutorial/uiswing/painting/step2.html.

Do I do something wrong or it's something related with java? If it's second, why does this happen? Any help would be appreciated.

Yonshoku
  • 115
  • 1
  • 7
  • 1
    The size of the panel and the frame will NEVER be the same. The frame size includes the titlebar and borders. Don't attempt to set the size of the frame (or the JPanel). All you need is to override `getPreferredSize()` as you have done. In you painting method don't hardcode the values when painting the rectangle. Instead you can use getWidth() and getHeight(). – camickr Feb 10 '21 at 23:51
  • @camickr, There is overrided getPreferredSize(), invocked pack() and frame setVisible() after that. – Yonshoku Feb 10 '21 at 23:54
  • 1
    Note a component doesn't have a size until the frame is packed or made visbible, so yes in the constructor of your class you will see sizes of 0. The values will be correct in the paintComponent() method. Post a proper [mre] demonstrating the problem if the above explanations don't make sense. You may have other logic causing a problem. Also, there is no need to do custom painting. You can just use the setBackground(...) method to fill the background color of the panel. – camickr Feb 10 '21 at 23:56
  • @camickr I understood now why did it return 0 and 0, thank you very much. I made it reproducible(except JFrame constructor calls from another class with help of SwingUtilities.invokeLater()). Thank you! – Yonshoku Feb 11 '21 at 00:02
  • I stated earlier you don't need the setSize() for the panel. There is also no need to extend JFrame. Your main() method that starts the application just needs to create an instance of a JFrame and add the Board component to the frame. You stated you copied code from the Swing tutorial, yet the structure of your code does not follow the example from the tutorial. A proper [mre] will contain all the code necessary to demonstrate the problem. – camickr Feb 11 '21 at 00:28
  • Your code is not a copy / paste of the Oracle tutorial [Creating the Demo Application (Step 2)](https://docs.oracle.com/javase/tutorial/uiswing/painting/step2.html). The code on that page packs the JFrame and does not extend the JFrame. – Gilbert Le Blanc Feb 11 '21 at 10:00

1 Answers1

2

enter image description here

This example only tries to establish the panel size once the frame (and panel) are visible on-screen. It returns the exact size (300 pixels) set in the code.

import java.awt.*;
import javax.swing.*;

public class ChessBoard extends JPanel {
    
    int size = 300;
    JLabel sizeLabel = new JLabel();

    ChessBoard() {
        setBackground(Color.CYAN);
        setLayout(new GridBagLayout());
        add(sizeLabel);
    }
    
    public void showSize() {
        sizeLabel.setText(String.format("%1sx%1s", getWidth(), getHeight()));
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(size,size);
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            ChessBoard cb = new ChessBoard();
            
            JFrame f = new JFrame(cb.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);
            
            f.setContentPane(cb);
            f.pack();
            f.setMinimumSize(f.getSize());
            
            f.setVisible(true);
            // delay showing size until app. is on-screen
            Runnable r1 = cb::showSize;
            SwingUtilities.invokeLater(r1);
        };
        SwingUtilities.invokeLater(r);
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    Thank you very much, it works and it's great start point to figure all out! – Yonshoku Feb 11 '21 at 10:44
  • 1
    You're welcome. Given the name 'chess' I just recalled something else that might be of interest.. See also [Making a robust, resizable Swing Chess GUI](http://stackoverflow.com/q/21142686/418556). – Andrew Thompson Feb 11 '21 at 12:24
  • Thank you again, you are right, I'm trying to solve this problem right now =) @Andrew Thompson – Yonshoku Feb 11 '21 at 12:55
  • 1
    Well I guess you're in luck then, given the 215 lines of code in [my answer](https://stackoverflow.com/a/21142687/418556) produced the screen shots seen in the question. ;) Have fun! :) – Andrew Thompson Feb 11 '21 at 13:26