Java Swing GridLayout 更改网格大小

Java Swing GridLayout Change Grid Sizes

我正在尝试创建一个以 Netflix 风格列出电影的程序,以学习前端编码。

我希望它最终看起来如何:

我的猜测是每部电影都是一个带有图像、名称标签和发行年份标签的按钮组件。

我正在努力重现这种外观。这是我尝试时的样子:

我图像中的导航栏位于边框布局的页面开始处。在导航栏下方,电影容器位于边框布局的中心。

我的想法是创建一个 GridLayout,然后为每部电影创建一个按钮并将其添加到 GridLayout。

您可以使用以下代码重新创建:

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;
}
}

我注意到 GridLayout 总是试图将所有内容都放入 window。

只需要在 GridLayout 中正确配置 JButton

例如

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;
}

这是上述内容的完整来源,其中对年份进行了调整以换行。它在 JButton 中使用 HTML 将按钮文本分成两行。

输入焦点在第一个按钮上,而鼠标悬停在“2009”电影上:

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);
    }
}

来自 Andrew Thompson 回答的相同想法,但有一些小的文本对齐更改和悬停效果

final class Testing 
{
 public static void main(String[] args)
 {
  JFrame frame=new JFrame("NEFLIX");
  
  frame.setContentPane(new GridDisplay()); 
  frame.pack();
  frame.setResizable(false);
  
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setVisible(true);
 }
 
 private static final class GridDisplay extends JPanel implements ActionListener
 {
  private GridDisplay()
  {
   super(new GridLayout(0,5,20,20));
   
   setBackground(new Color(0,0,0,255));
   
   BufferedImage image=new BufferedImage(150,200,BufferedImage.TYPE_INT_RGB); 
   Graphics2D g2d=(Graphics2D)image.getGraphics();  
   g2d.setColor(Color.BLUE);  
   g2d.fillRect(0,0,image.getWidth(),image.getHeight());
   
   HoverPainter painter=new HoverPainter();  
   for(int i=0;i<10;i++)
   {
    TVShowCard card=new TVShowCard(image,"Show "+i,"199"+i);   
    card.addMouseListener(painter);   
    add(card);
   }
  }

  //highlight only on hover
  private final class HoverPainter extends MouseAdapter
  {
   @Override
   public void mouseExited(MouseEvent e) {
    ((TVShowCard)e.getSource()).setBorderPainted(false);
   }

   @Override
   public void mouseEntered(MouseEvent e) {
    ((TVShowCard)e.getSource()).setBorderPainted(true);
   }  
  } 
  
  private final class TVShowCard extends JButton
  {
   private TVShowCard(BufferedImage preview,String name,String year)
   {
    super();
       
    setContentAreaFilled(false);
    setBackground(new Color(0,0,0,0));
    setFocusPainted(false);  
    setBorderPainted(false);

    //I didn't use image icon & text horizontal alignment because the text always horizontally centered aligned but from the expected output it was left  so created 2 labels for the job            

    setLayout(new GridBagLayout());
    addIcon(preview);  
    addLabel(name,year);
      
    addActionListener(GridDisplay.this);
   }
   
   private void addIcon(BufferedImage preview)
   {
    JLabel icon=new JLabel();   
    icon.setIcon(new ImageIcon(preview));  
    add(icon,new GridBagConstraints(0,0,1,1,1.0f,0.0f,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
   }
   
   private void addLabel(String name,String year)
   {
    JLabel label=new JLabel("<html><body>"+name+"<br>"+year+"</body></html>");   
    label.setForeground(Color.white);  
    label.setBackground(new Color(0,0,0,0));
    add(label,new GridBagConstraints(0,1,1,1,1.0f,1.0f,GridBagConstraints.SOUTHWEST,GridBagConstraints.NONE,new Insets(5,0,0,0),0,0));
   }
  } 
  
  @Override
  public void actionPerformed(ActionEvent e)
  {
   TVShowCard card=(TVShowCard)e.getSource();
   
   //do stuff with it
  }
 } 
}