Search code examples
javaswinglayout-managergrid-layout

Java Swing GridLayout Change Grid Sizes


I'm trying to create a program that lists movies in a Netflix style to learn Front-End coding.

How I want it to look in the end:

Example Image How it should look

My guess is that every movie is a button component with an image a name label and a release year label.

I'm struggling to recreate this look. This is how it looks when I try it:

How it looks when I try it

The navigationbar in my image is at the page start of a border layout. Below the navigationbar the movie container is in the center of the border layout.

My idea was creating a GridLayout and then create a button for each movie and adding it to the GridLayout.

You can recreate this with this code:

public class Main {
private static JFrame frame;

public static void main(String[] args) throws HeadlessException {
    frame = new JFrame();
    frame.setLayout(new BorderLayout());
    frame.setBackground(new Color(32, 32, 32));
    
    JPanel navigationPanel = createNavigationBar();
    frame.add(navigationPanel, BorderLayout.PAGE_START);
    
    JPanel moviePanel = createMoviePanel();
    frame.add(moviePanel, BorderLayout.CENTER);
    
    frame.setPreferredSize(new Dimension(1920, 1080));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("Example App");
    frame.pack();
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    frame.setVisible(true);
}

public static JPanel createMoviePanel() {
    JPanel moviePanel = new JPanel();
    
    GridLayout layout = new GridLayout(0, 10);
    layout.setHgap(3);
    layout.setVgap(3);
    moviePanel.setLayout(layout);
    moviePanel.setBackground(new Color(32, 32, 32));
    
    ArrayList<String> exampleList = new ArrayList<>();
    
    // Add stuff to the example list
    for(int i = 0; i < 120; i++) {
        exampleList.add(Integer.toString(i));
    }
    
    final File root = new File("");
    
    for(final String movie : exampleList) {
        JLabel picLabel = new JLabel();
        
        try {
            File imageFile = new File(root.getAbsolutePath() + "\\src\\images\\" + "imageName.jpg"); // Try to find the cover image
            
            if(imageFile.exists()) {
                BufferedImage movieCover = ImageIO.read(imageFile);
                picLabel = new JLabel(new ImageIcon(movieCover));
            } else {
                BufferedImage movieCover = ImageIO.read(new File(root.getAbsolutePath() + "\\src\\images\\temp.jpg")); // Get a temp image
                picLabel = new JLabel(new ImageIcon(movieCover));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        JLabel movieName = new JLabel("New Movie");
        movieName.setForeground(Color.WHITE);;
        
        JButton movieButton = new JButton();
        movieButton.setLayout(new GridLayout(0, 1));
        //movieButton.setContentAreaFilled(false);
        //movieButton.setBorderPainted(false);
        //movieButton.setFocusPainted(false);
        
        movieButton.add(picLabel);
        movieButton.add(movieName);
        
        moviePanel.add(movieButton);
    }
    
    return moviePanel;
}

public static JPanel createNavigationBar() {
    JPanel navBar = new JPanel();
    navBar.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 20));
    navBar.setBackground(new Color(25, 25, 25));
    
    JButton homeButton = new JButton("Home");
    homeButton.setContentAreaFilled(false);
    homeButton.setBorderPainted(false);
    homeButton.setFocusPainted(false);
    
    JButton movieButton = new JButton("Movies");
    movieButton.setContentAreaFilled(false);
    movieButton.setBorderPainted(false);
    movieButton.setFocusPainted(false);
    
    // Add all the buttons to the navbar
    navBar.add(homeButton);
    navBar.add(movieButton);
    
    return navBar;
}
}

I noticed that the GridLayout always tries to fit everything onto the window.


Solution

  • All that's needed is a properly configured JButton in a GridLayout.

    E.G.

    enter image description here

    public static JPanel createMoviePanel() {
        JPanel movieLibraryPanel = new JPanel(new GridLayout(0, 10, 3, 3));
        movieLibraryPanel.setBackground(new Color(132, 132, 132));
    
        int m = 5;
        BufferedImage image = new BufferedImage(9 * m, 16 * m, BufferedImage.TYPE_INT_RGB);
        for (int ii = 1; ii < 21; ii++) {
            JButton picButton = new JButton("Mov " + ii, new ImageIcon(image));
            picButton.setMargin(new Insets(0,0,0,0));
            picButton.setForeground(Color.WHITE);
            picButton.setContentAreaFilled(false);
            picButton.setHorizontalTextPosition(JButton.CENTER);
            picButton.setVerticalTextPosition(JButton.BOTTOM);
            movieLibraryPanel.add(picButton);
        }
    
        return movieLibraryPanel;
    }
    

    Here is a complete source for the above with a tweak to put the year on a new line. It uses HTML in the JButton to break the button text into two lines.

    The input focus is on the first button, whereas the mouse hovers over the '2009' movie:

    enter image description here

    import java.awt.*;
    import java.awt.image.*;
    import javax.swing.*;
    
    class MovieGrid {
    
        MovieGrid() {
            JFrame f = new JFrame("Movie Grid");
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);
            f.add(createMoviePanel());
            f.pack();
            f.setVisible(true);
        }
    
        public static JPanel createMoviePanel() {
            JPanel movieLibraryPanel = new JPanel(new GridLayout(0, 10, 3, 3));
            movieLibraryPanel.setBackground(new Color(132, 132, 132));
    
            int m = 5;
            BufferedImage image = new BufferedImage(
                    9 * m, 16 * m, BufferedImage.TYPE_INT_RGB);
            for (int ii = 2001; ii < 2021; ii++) {
                JButton picButton = new JButton(
                        "<html>Movie<br>" + ii, new ImageIcon(image));
                picButton.setMargin(new Insets(0,0,0,0));
                picButton.setForeground(Color.WHITE);
                picButton.setContentAreaFilled(false);
                picButton.setHorizontalTextPosition(JButton.CENTER);
                picButton.setVerticalTextPosition(JButton.BOTTOM);
                movieLibraryPanel.add(picButton);
            }
    
            return movieLibraryPanel;
        }
    
        public static void main(String[] args) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    new MovieGrid();
                }
            };
            SwingUtilities.invokeLater(r);
        }
    }