使用 JPanel Java 自动调整 JFrame 的大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19180372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 14:48:25  来源:igfitidea点击:

resize JFrame automatically with JPanel Java

javaswingresizejframejpanel

提问by Ange King

I am implementing changes to a minesweeper game. One of these things is the difficulty. I have managed to do this and its working, but as the game board (in its own Jpanel) gets bigger & smaller (depending on the difficulty), I cannot get the JFrame to resize automatically. I am using:

我正在对扫雷游戏进行更改。其中之一就是困难。我已经设法做到了这一点及其工作,但是随着游戏板(在它自己的 Jpanel 中)变得越来越大(取决于难度),我无法让 JFrame 自动调整大小。我在用:

setPreferredSize(new Dimension(WIDTH, HEIGHT));

to set the initial size of the window, but this makes it REALLY tiny, as in only showing the word 'File' from the JMenuBar. I have to resize it manually.

设置窗口的初始大小,但这使得它非常小,因为只显示 JMenuBar 中的“文件”一词。我必须手动调整它的大小。

I tried setSize() and things like frame.pack() on the ActionListener event, but I cannot seem to get it to resize.

我在 ActionListener 事件上尝试了 setSize() 和 frame.pack() 之类的东西,但我似乎无法调整它的大小。

Any tips on what code/methods to use.

关于使用什么代码/方法的任何提示。

edit: code posted

编辑:发布的代码

package mines;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class SetupFrame extends JFrame {

    private final int WIDTH = 600;
    private final int HEIGHT = 500;
    public JFrame frame;
    public JMenuBar menubar;
    public JMenu file;
    public JMenu levels;
    public JMenu help;
    public JMenuItem login;
    public JMenuItem save;
    public JMenuItem resume;
    public JMenuItem exit;
    public JMenuItem easy;
    public JMenuItem medium;
    public JMenuItem hard;
    private JLabel statusbar;
    public JPanel main;
    public JPanel buttonPanel;
    public JPanel saved;
    public JPanel game;
    public Board mineGame;
    public JButton ngButton;
    public JButton undoButton;
    public JButton redoButton;
    public JTabbedPane tp;
    public String[] levelPicker;
    public JComboBox levelSelect;
    public JFileChooser chooser;
    public String filename;

    public int difficulty;

    public SetupFrame(){

      frame = new JFrame();

      String filename = JOptionPane.showInputDialog(frame, "Enter Your Name.");

      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


      setLocationRelativeTo(null);
      setTitle("Minesweeper");

      //menubar, menus, menu items
      menubar = new JMenuBar();
      setJMenuBar(menubar);

      file = new JMenu("File");
      help = new JMenu("Help");

      menubar.add(file);
      menubar.add(help);

      login = new JMenuItem("Login..");
      save = new JMenuItem("Save..");
      resume = new JMenuItem("Resume..");
      exit = new JMenuItem("Exit");

      file.add(login);
      file.add(save);
      file.add(resume);
      file.addSeparator();
      file.add(exit);

      statusbar = new JLabel("");



      chooser = new JFileChooser(); // new File Chooser for saved tab
      undoButton = new JButton(" Undo "); //undo Button for game panel 
      ngButton = new JButton(" New Game ");//new game Button for game panel
      redoButton = new JButton(" Redo");//redo Button for game panel

      main = new JPanel(new BorderLayout()); //new panel for main game
      //main.add(mineGame, BorderLayout.CENTER); //add instance mineGame to main panel

      game = new JPanel(new BorderLayout());// new panel for game tab
      main.add(game, BorderLayout.CENTER); //add the mineGames panel to game panel
      game.add(statusbar, BorderLayout.SOUTH); //add statusbar to bottom of game panel
            //game.add(button, BorderLayout.NORTH); // add buttons (eventually be redo, undo, new game)

      saved = new JPanel(); // create new panel for the saved tab
      saved.add(chooser);//add the File Chooser to the saved tab

      String[] levelPicker = {"Easy", "Medium", "Hard"};
      levelSelect = new JComboBox(levelPicker);
      levelSelect.setSelectedIndex(0);
            //levelSelect.addActionListener(this);

       buttonPanel = new JPanel();
       buttonPanel.add(undoButton);
       buttonPanel.add(ngButton);
       buttonPanel.add(redoButton);
       buttonPanel.add(levelSelect);
       main.add(buttonPanel, BorderLayout.NORTH);

       //create & add the tabs
       tp = new JTabbedPane();
       tp.addTab ("Game", main);
       tp.addTab ("Saved", saved);
       tp.addTab ("Statistics", null);
       add(tp);

       setPreferredSize(new Dimension(WIDTH, HEIGHT));
       setResizable(true);
       setVisible(true);
       frame.pack();


        class listener implements ActionListener{
            public void actionPerformed (ActionEvent e)
            {   
                if(e.getSource() == ngButton){
                    //JOptionPane.showInputDialog(frame, "Do You want To Save");
                    newMineGame();
                }
                JComboBox cb = (JComboBox)e.getSource();
                String picker = (String)cb.getSelectedItem();
                if (picker == "Easy"){
                    difficulty = 0;
                    newMineGame();
                }
                if (picker == "Medium"){
                    difficulty = 1;
                    newMineGame();
                    frame.pack();
                }
                if (picker == "Hard"){
                    difficulty = 2;
                    newMineGame();
                    frame.pack();
                }
            }


            private void newMineGame() {
                game.removeAll();
                mineGame = new Board(statusbar, difficulty);
                game.add(mineGame, BorderLayout.CENTER);
                game.add(statusbar, BorderLayout.SOUTH);
                repaint();
            }

        }

        ngButton.addActionListener(new listener());
        undoButton.addActionListener(new listener());
        redoButton.addActionListener(new listener());
        levelSelect.addActionListener(new listener());


    }

public static void main(String[] args) {
        new SetupFrame();

    }

回答by mKorbel

One of these things is the difficulty. I have managed to do this and its working, but as the game board (in its own Jpanel) gets bigger & smaller (depending on the difficulty), I cannot get the JFrame to resize automatically.

其中之一就是困难。我已经设法做到了这一点及其工作,但是随着游戏板(在它自己的 Jpanel 中)变得越来越大(取决于难度),我无法让 JFrame 自动调整大小。

and

tried setSize() and things like frame.pack() on the ActionListener event, but I cannot seem to get it to resize.

在 ActionListener 事件上尝试了 setSize() 和 frame.pack() 之类的东西,但我似乎无法调整它的大小。

  • JFrame.pack()works in case

    1. that all JComponentsrepresenting mines (there is best of ways to use JToggleButton) returns properly PreferredSizeback to its parent (JPanel)

    2. parent (JPanel) laid by GridLayout (very simple)

    3. and there are two ways how, when, where to JFrame.pack()

      • use CardLayout, the next code line after swithching Cardis JFrame.pack()

      • remove old JPanel(from JFrame) and replace with new, then you need to call JFrame.(re)validate(), JFrame.repaint()and JFrame.pack()as last code lines

  • maybe there is another issue, important is code ordering in the case that is there settings for JFrame.setResizable(false);

  • JFrame.pack()以防万一

    1. 所有JComponents代表地雷(有最好的使用方法JToggleButton)正确PreferredSize返回其父级(JPanel

    2. GridLayout 放置的 parent (JPanel)(非常简单)

    3. 有两种方式如何、何时、何地 JFrame.pack()

      • 使用CardLayout,切换后的下一行代码CardJFrame.pack()

      • 删除旧的JPanel(从JFrame)并替换为新的,然后您需要调用JFrame.(re)validate(),JFrame.repaint()JFrame.pack()作为最后的代码行

  • 也许还有另一个问题,重要的是代码排序在有设置的情况下 JFrame.setResizable(false);



after your edit

编辑后

  • use Cardlayout

  • there you miss code lines (don't to extends JFrame, create this Object as Local variable) JFrame.(re)validate(), JFrame.repaint()and JFrame.pack()as last code lines in private void newMineGame() {

  • 使用Cardlayout

  • 在那里你错过了代码行(不要扩展JFrame,将此对象创建为Local variableJFrame.(re)validate()JFrame.repaint()以及JFrame.pack()最后的代码行private void newMineGame() {



but I dont understand what you mean by: "there you miss code lines (don't to extends JFrame, create this Object as Local variable) ;

但我不明白你的意思:“你错过了代码行(不要扩展 JFrame,将此对象创建为局部变量);

code could be

代码可能是

import javax.swing.*;

public class SetupFrame {

    private JFrame frame;
    private JMenuBar menubar = new JMenuBar();
    private Board mineGame;

    public SetupFrame() {
        //there add required JComponents

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setTitle("Minesweeper");
        frame.setJMenuBar(menubar);
        frame.add(mineGame);
        //frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
        //frame.setResizable(true);//not neccessary
        frame.pack();
        frame.setVisible(true);
    }

    private void newMineGame() {
        //remove old Board
        //add a new Board
        frame.validate();
        frame.repaint();
        frame.pack();
    }

    private static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new SetupFrame();
            }
        });
    }
}

回答by dic19

Here is your mistake:

这是你的错误:

frame.pack();

frame.pack();

Why do you need frameif your SetupFrameactually extends from JFrame? Change this line by just pack()and it will work.

frame如果您SetupFrame实际上从 扩展,为什么需要JFrame?仅更改此行,pack()它将起作用。

@mKorbel already posted a complete and very useful explanation about pack()behavior (thank you).

@mKorbel 已经发布了关于pack()行为的完整且非常有用的解释(谢谢)。

Update

更新

Also in your listenerclass you'll get this exception when a JButtonis pressed:

同样在你的listener班级JButton中,按下a 时你会得到这个异常:

java.lang.ClassCastException: javax.swing.JButton cannot be cast to javax.swing.JComboBox

You need make this little change to avoid this:

你需要做这个小小的改变来避免这种情况:

class listener implements ActionListener{

    public void actionPerformed (ActionEvent e) {
        if(e.getSource() == ngButton){
            //JOptionPane.showInputDialog(frame, "Do You want To Save");
            newMineGame();
        } else if(e.getSource() instanceof JComboBox){ // add this else-if block
            JComboBox cb = (JComboBox)e.getSource();
            String picker = (String)cb.getSelectedItem();
            if (picker.equals("Easy")){ // <-- picker == "Easy" is not the proper way to compare string, use equals() method instead
                difficulty = 0;
                newMineGame();
            }
            if (picker.equals("Medium")){
                difficulty = 1;
                newMineGame();
                //frame.pack();  <--- again, just use pack();
                pack();
            }
            if (picker.equals("Hard")){
                difficulty = 2;
                newMineGame();
                //frame.pack();  <--- again, just use pack();
                pack();
            }
        }
    }

Or even better, implement an ItemListenerto listen JComboBoxselection changes instead using an ActionListener

或者甚至更好,实现一个ItemListener来监听JComboBox选择更改而不是使用ActionListener