Resize components on frame resize Java

27,700
  1. JFrame.setVisible(true) should be the last line you call.
  2. GridBagLayout can adapt the size of your components according to the frame size, as long as you use weightx/weighty and fill

UPDATE:

  1. Forget about setting preferred size, this is just going down the path to GUI-problems
  2. If you use LayoutManager's (and it is a very good idea), forget about calling setSize()/setBounds()/setLocation(), the LayoutManager's will override them anyway
  3. You need to take care of the resizing of the image in order to maintain the original image ratio
  4. If you use weightx/weighty, you should also use anchor and/or fill
  5. Use frame.pack() to size properly your frame
  6. Use setExtendedState() to maximize a frame

Btw, an SSCCE means that you make a runnable example for others, this includes changing local path to images to online URL's (see the example below).

With the following snippet, everything seems to work ok:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.TextField;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.StyledDocument;

public class DraftGUI implements MouseListener {

    private static final String IMAGE_URL = "http://images.paramountbusinessjets.com/space/spaceshuttle.jpg";
    private JPanel jpPack;
    private JPanel jpCards;
    private JPanel jpInfo;
    private JPanel jpChat;
    private TextField tf;
    private StyledDocument doc;
    private JTextPane tp;
    private JScrollPane sp;

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    public DraftGUI() throws MalformedURLException {

        final JFrame frame = new JFrame("Draft");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // set the content pane, we'll add everything to it and then add it to the frame
        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridBagLayout());

        // creates some panels with some default values for now
        JPanel jpCards = new JPanel(new BorderLayout());
        jpCards.setBackground(Color.BLUE);

        JPanel jpInfo = new JPanel();
        jpInfo.setBackground(Color.GREEN);

        JPanel jpPack = new JPanel(new GridBagLayout());
        jpPack.setBackground(Color.RED);

        // grab some info to make the JTextPane and make it scroll
        tf = new TextField();
        doc = new DefaultStyledDocument();
        tp = new JTextPane(doc);
        tp.setEditable(false);
        sp = new JScrollPane(tp);

        // adding the quantities to the chat panel
        JPanel jpChat = new JPanel();
        jpChat.setLayout(new BorderLayout());
        jpChat.add("North", tf);
        jpChat.add("Center", sp);

        // a new GridBagConstraints used to set the properties/location of the panels
        GridBagConstraints c = new GridBagConstraints();

        // adding some panels to the content pane
        // set it to start from the top left of the quadrant if it's too small
        c.anchor = GridBagConstraints.FIRST_LINE_START;
        c.fill = GridBagConstraints.BOTH; // set it to fill both vertically and horizontally
        c.gridx = 0; // set it to quadrant x=0 and
        c.gridy = 0; // set it to quadrant y=0
        c.weightx = 0.7;
        c.weighty = 0.3;
        contentPane.add(jpCards, c);

        c.gridx = 1;
        c.gridy = 0;
        c.weightx = 0.3;
        c.weighty = 0.3;
        contentPane.add(jpInfo, c);

        c.gridx = 0;
        c.gridy = 1;
        c.weightx = 0.7;
        c.weighty = 0.7;
        contentPane.add(jpPack, c);

        c.gridx = 1;
        c.gridy = 1;
        c.weightx = 0.3;
        c.weighty = 0.7;
        contentPane.add(jpChat, c);

        // set some necessary values
        frame.setContentPane(contentPane);
        frame.setLocationByPlatform(true);

        // This code works for adding an Image
        // need to learn how to specify a path not dependent on the specific users's machine
        // this is not a high priority for now though
        GridBagConstraints d = new GridBagConstraints();
        d.weightx = 1.0;
        d.weighty = 1.0;
        d.fill = GridBagConstraints.BOTH;
        d.gridx = 0;
        d.gridy = 0;
        ImageLabel imageLabel1 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
        jpPack.add(imageLabel1, d);
        ImageLabel imageLabel2 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
        d.gridx++;
        jpPack.add(imageLabel2, d);

        ImageLabel imageLabel3 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
        d.gridy++;
        jpPack.add(imageLabel3, d);

        imageLabel1.addMouseListener(this);
        imageLabel2.addMouseListener(this);
        imageLabel3.addMouseListener(this);
        frame.pack();
        // 223, 310 are the aspect values for a card image, width, height
        // these need to be maintained as the GUI size changes
            frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new DraftGUI();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public static class ImageLabel extends JPanel {
        private static int counter = 1;
        private ImageIcon icon;
        private int id = counter++;

        public ImageLabel(ImageIcon icon) {
            super();
            setOpaque(false);
            this.icon = icon;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(icon.getIconWidth(), icon.getIconHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            double zoom = Math.min((double) getWidth() / icon.getIconWidth(), (double) getHeight() / icon.getIconHeight());
            int width = (int) (zoom * icon.getIconWidth());
            int height = (int) (zoom * icon.getIconHeight());
            g.drawImage(icon.getImage(), (getWidth() - width) / 2, (getHeight() - height) / 2, width, height, this);
            g.setFont(g.getFont().deriveFont(36.0f));
            g.drawString(String.valueOf(id), getWidth() / 2, getHeight() / 2);
        }
    }
}
Share:
27,700
Michael Yousef
Author by

Michael Yousef

Updated on October 25, 2020

Comments

  • Michael Yousef
    Michael Yousef over 3 years

    I'm having some trouble trying to resize the components in my GUI when I resize the GUI. Right now, when I resize the GUI, the size of the components don't change, they keep to the static size I set them to. When I resize the GUI passed the minimum size needed to display them, they are no longer displayed. I want them to resize and maintain an aspect ratio when the GUI is resized.

    Here's the code I have for the GUI:

    import java.applet.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.awt.image.ImageObserver;
    import java.io.*;
    import java.net.*;
    
    import javax.imageio.ImageIO;
    import javax.swing.*;
    import javax.swing.border.Border;
    import javax.swing.text.*;
    import javax.swing.text.html.*;
    
    public class DraftGUI implements MouseListener {
    
    private JPanel jpPack;
    private JPanel jpCards;
    private JPanel jpInfo;
    private JPanel jpChat;
    private TextField tf;
    private StyledDocument doc;
    private JTextPane tp;
    private JScrollPane sp;
    
    public void mousePressed(MouseEvent e) {
    }
    
    public void mouseReleased(MouseEvent e) {
    }
    
    public void mouseEntered(MouseEvent e) {
        }
    
        public void mouseExited(MouseEvent e) {
        }
    
    public void mouseClicked(MouseEvent e) {
        e.getComponent().setVisible(false);
    }
    
    private Client client;
    
    
    public GUI(Client client) throws IOException {
    
        JFrame frame = new JFrame("Draft");
    
        //set the size to fullscreen to start
        frame.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
    
        //set the content pane, we'll add everything to it and then add it to the frame
        JPanel contentPane = new JPanel();
        contentPane.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
        contentPane.setLayout(new GridBagLayout());
    
        //creates some panels with some default values for now
        JPanel jpCards = new JPanel(new BorderLayout());
        jpCards.setOpaque(true); //ensures it paints every pixel
        jpCards.setBackground(Color.BLUE);
    
        JPanel jpInfo = new JPanel();
        jpInfo.setOpaque(true);
        jpInfo.setBackground(Color.GREEN);
    
        JPanel jpPack = new JPanel(new GridBagLayout());
        jpPack.setOpaque(true);
        jpPack.setBackground(Color.RED);
    
        //grab some info to make the JTextPane and make it scroll
        this.client = client;
        tf = new TextField();
        doc = new DefaultStyledDocument();
        tp = new JTextPane(doc);
        tp.setEditable(false);
        tf.addActionListener(this.client);
        sp = new JScrollPane(tp);
    
        //adding the quantities to the chat panel
        JPanel jpChat = new JPanel();
        jpChat.setLayout(new BorderLayout());
        jpChat.add("North", tf);
        jpChat.add("Center", sp);
    
        //a new GridBagConstraints used to set the properties/location of the panels
        GridBagConstraints c = new GridBagConstraints(); 
    
        //adding some panels to the content pane
        //set it to start from the top left of the quadrant if it's too small
        c.anchor = GridBagConstraints.FIRST_LINE_START; 
        c.fill = GridBagConstraints.BOTH; //set it to fill both vertically and horizontally
        c.gridx = 0; //set it to quadrant x=0 and
        c.gridy = 0; //set it to quadrant y=0
        c.weightx = 0.7;
        c.weighty = 0.3;
        contentPane.add(jpCards, c);
    
        c.gridx = 1;
        c.gridy = 0;
        c.weightx = 0.3;
        c.weighty = 0.3;
        contentPane.add(jpInfo, c);
    
        c.gridx = 0;
        c.gridy = 1;
        c.weightx = 0.7;
        c.weighty = 0.7;
        contentPane.add(jpPack, c);
    
        c.gridx = 1;
        c.gridy = 1;
        c.weightx = 0.3;
        c.weighty = 0.7;
        contentPane.add(jpChat, c);
    
        //set some necessary values 
        frame.setContentPane(contentPane);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    
        //This code works for adding an Image
        //need to learn how to specify a path not dependent on the specific users's machine
        //this is not a high priority for now though
        GridBagConstraints d = new GridBagConstraints();
        d.gridx = 0;
        d.gridy = 0;
    
        ImageLabel imageLabel1 = new ImageLabel("path-to-file");
    
        imageLabel1.setPreferredSize(new Dimension(223, 310));
        jpPack.add(imageLabel1, d);
    
        ImageLabel imageLabel2 = new ImageLabel("path-to-file");
        imageLabel2.setPreferredSize(new Dimension(223, 310));
        ImageLabel imageLabel3 = new ImageLabel("path-to-file");
        imageLabel3.setPreferredSize(new Dimension(223, 310));
        d.gridx = 1;
        jpPack.add(imageLabel2, d);
        d.gridy = 1;
        jpPack.add(imageLabel3, d);
    
        imageLabel1.addMouseListener(this);
        imageLabel2.addMouseListener(this);
        imageLabel3.addMouseListener(this);
    
        //223, 310 are the aspect values for a card image, width, height
        //these need to be maintained as the GUI size changes
    
        }
    
    }
    
    
    class ImageLabel extends JLabel {
       Image image;
       ImageObserver imageObserver; 
    
       // constructor with filename     
       ImageLabel(String filename) {
          ImageIcon icon = new ImageIcon(filename);
          image = icon.getImage();
          imageObserver = icon.getImageObserver();
       }
    
       // constructor with icon
       ImageLabel(ImageIcon icon) {
          image = icon.getImage();
          imageObserver = icon.getImageObserver();
       }
    
       // overload setIcon method
       void setIcon(ImageIcon icon) {
          image = icon.getImage();
          imageObserver = icon.getImageObserver();
       }
    
       // overload paint()
       public void paint( Graphics g ) {
           super.paint( g );
           g.drawImage(image,  0 , 0 , getWidth() , getHeight() , imageObserver);
    
       }
    
    }
    

    For some reason, there's no default resizing property for the frame's components, so when the frame resizes, the components don't do anything. I'm not sure what I'm doing wrong or missed, but clearly I left something out.

    Also, if anyone knows, the ImageLabels are taking up extra space around them. The padding is set to 0 by default, so I'm not sure why it's creating like a border around them.

    Thanks.

    EDIT for Guillaume:

    I know a main is necessary if I want to run it as a standalone, it's currently part of another application and gets called separately from within it. It was probably not the best decision to post it without a main for completeness, but whatever, it can't be that big of a problem.

    Your code took out the portion where the picture was actually displayed. "path-to-file" was supposed to be replaced by an actual image file path, so you would display the image. It's hard to actually see the issue at hand when it's simply text in there.

    When you have the image displayed correctly, and you try to resize the entire GUI, you will notice that the image doesn't shrink. It keeps to its preferred size and has issues when it becomes smaller than it. In my code, it stops displaying the picture completely when it can't display at least the preferred size. In your code, it cuts off part of the picture when it shrinks.

    What I want is for it to actually resize the JLabel containing the picture, so that as the GUI resizes, so will the image. It's necessary that the image shrinks accordingly for my program. The user will eventually have functionality based on clicking the images, so displaying only some images or portions of them simply won't do.

    Please try your code/my code again and reproduce the issue I'm having, testing with pictures, so that we can find a correct solution. Thanks.