Regarding Sizing of JFrames and JPanels

Note that this explanation assumes that we are using one JPanel inside a JFrame. (We're not using a ContentPane either since don't see the point of them.)

So our graphics look like this:

And in order to draw on a JPanel, we actually make a subclass of JPanel, commonly called DrawingPanel, DrawPanel or GraphicsPanel.

Using a DrawingPanel class then permits us to write our own paintComponent(Graphics g) {} method that does all the drawing and allows us access to the very useful drawing methods of the Graphics and Graphics2D objects (commonly named g and g2).


JFrame size

There are three ways of doing this Choose one:

  1. The size of the JFrame is set using window.setSize(900, 700); (where window is the name of the JFrame object).
  2. To make the JFrame take up the whole screen do the following:
    Dimension fullScreen = Toolkit.getDefaultToolkit().getScreenSize();
    window.setSize(fullScreen);
    ** This way is better: window.setExtendedState(JFrame.MAXIMIZED_BOTH);
    If you then wanted to determine the size of the window, you could just do int scrW = window.getWidth(); and int scrH = window.getHeight();
  3. If your JPanel has a lot of components on it (buttons, textfields, etc), then use window.pack(); to arrange them in the smallest space available. If you use pack(), then setSize() is ignored.

Sample code JFrame window = new JFrame(); window.setTitle("Title of JFrame"); window.add(panel); window.setSize(900,800); // or window.pack(); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setLocationRelativeTo(null); window.setVisible(true);

JPanel size

If you are drawing on the JPanel, you cannot base your measurements on the size of the JFrame. The JFrame includes the borders and the area at the top which has the title, close button, etc.

If you want to draw a horizontal line across the middle or the screen, you cannot do window.getHeight()/2

In this image, the circle is drawing in the exact centre of the JPanel or JFrame. You can see that these are two different locations. Using the JFrame coordinates for drawing will not give you the results that you desire.

This means that we need to be able to specify the JPanel size.


Setting an exact JPanel size

  1. First you have to make sure that you do not set the size of the JFrame.
  2. Then use JPanel method "setPreferredSize()". NOTE: setSize() does not work for JPanels.
    Example:
    JPanel panel = new DrawingPanel(); panel.setPreferredSize(new Dimension(800,700)); Yes, this requires a Dimension object, not two ints.
  3. If you have multiple JPanels, they will probably be placed on the JFrame in BorderLayout. In this case, you'll probably want to just use windown.pack() instead of trying to set the individual sizes. Remember that all of the outer ones (N,S,E,W) are as small as possible and the center one takes up all the remaining space.
  4. window.setResizable(false); (optional)
  5. Finally, you will have to add window.pack();
    What this does is to pack all of the components in the JFrame and any sub panels as closely as possible, then adjust the JFrame to its size. The only component we have is a JPanel so the JFrame gets the preferred size from it and then sets it's own size accordingly. (It still works if you have more components.)

 

If you've followed these steps, then your JPanel is exactly the number of pixels that you want it to be.

More Sample code (Since I'm extending JPanel, I'll put the code in the constructor) class DrawPanel extends JPanel{ int panW = 600; int panH = 400; DrawPanel() { this.setBackground(Color.WHITE); this.setPreferredSize(new Dimension(panW, panH)); } @Override public void paintComponent(Graphics g) { g.drawLine(0, panH/2, panW, panH/2); ... }

Resizeable Graphics

If you look at the TicTacToe program, you'll see how we adjust the graphics to scale as the JFrame is resized

Explanation of how it works

Problem If you have a lot of squares, then there is a rounding error that accumulates and you see large borders at the bottom and right sides.

JPanels that can be resized, but have other constraints on them.

Example: JPanel must always be square

This is actually a common situation. You make something that only works properly in a square JPanel, but you want to be able to drag it bigger or smaller. See the following code for how to implement it:

import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; /********************************************************************** * Adding the componentListener and square resizing to the JFrame * * crashes the program. So do it in the JPanel. * **********************************************************************/ public class SquareResizeOnly extends JFrame { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new SquareResizeOnly(); } }); } SquareResizeOnly(){ this.add(new DrawPanel()); this.setTitle("This always resizes to a square when dragged"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.pack(); this.setVisible(true); } class DrawPanel extends JPanel implements ComponentListener { int panSize=400; DrawPanel() { this.setBackground(Color.WHITE); this.setPreferredSize(new Dimension(panSize, panSize)); this.addComponentListener(this); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); //clear screen and repaint using background colour Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int r = 20; //circle radius g.setColor(Color.GREEN.darker()); g.drawLine(0, panSize/2, panSize/2, panSize/2); g.drawLine(panSize/2, panSize/2, panSize/2, panSize); g.setColor(Color.BLUE); g.drawOval(panSize/2-r/2, panSize/2-r/2, r, r); } /* Resizing the screen triggers a Component Event. Listen for it */ @Override public void componentResized(ComponentEvent e) { //find size of JPanel int w = this.getWidth(); int h = this.getHeight(); panSize = (w>h)? h:w; //take the smallest number //resize the JPanel to the newly determined size this.setPreferredSize(new Dimension(panSize, panSize)); //run the pack() method in the outer class. SquareResizeOnly.this.pack(); this.repaint(); } public void componentHidden(ComponentEvent e) {} public void componentMoved (ComponentEvent e) {} public void componentShown (ComponentEvent e) {} } }

 

Same program without inner class for JPanel (compare with above)

import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class SquareResizeOnly extends JPanel implements ComponentListener { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new SquareResizeOnly(); } }); } //global variables JFrame window; int panSize=400; //constructor SquareResizeOnly(){ //setup JPanel this.setBackground(Color.WHITE); this.setPreferredSize(new Dimension(panSize, panSize)); this.addComponentListener(this); //setup JFrame window = new JFrame(); window.add(this); window.setTitle("This always resizes to a square when dragged"); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.pack(); window.setVisible(true); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int r = 20; //circle radius g.setColor(Color.GREEN.darker()); g.drawLine(0, panSize/2, panSize/2, panSize/2); g.drawLine(panSize/2, panSize/2, panSize/2, panSize); g.setColor(Color.BLUE); g.drawOval(panSize/2-r/2, panSize/2-r/2, r, r); } /* Resizing the screen triggers a Component Event. Listen for it */ @Override public void componentResized(ComponentEvent e) { //find size of JPanel int w = this.getWidth(); int h = this.getHeight(); panSize = (w>h)? h:w; //take the smallest number this.setPreferredSize(new Dimension(panSize, panSize)); window.pack(); this.repaint(); } public void componentHidden(ComponentEvent e) {} public void componentMoved (ComponentEvent e) {} public void componentShown (ComponentEvent e) {} }