JPanel 未显示在 JFrame 中,但 JFrame 仍会更改大小

Posted

技术标签:

【中文标题】JPanel 未显示在 JFrame 中,但 JFrame 仍会更改大小【英文标题】:JPanel not showing in JFrame, but JFrame still changes size 【发布时间】:2022-01-17 13:48:24 【问题描述】:

我不知道我做了什么,或者出了什么问题,但是我在最近一段时间所做的更改使我的 JPanel 完全不可见。它嵌套的 JFrame 的大小仍然会发生变化以容纳它,我仍然可以切换组合框中的内容。

无奈之下,我尝试用一​​个按钮替换 SnakeSettingsPanel 类的内容,但同样的事情发生了——完全不可见,但我仍然可以与之交互。我想这可能是一个计算机错误,所以我尝试重新启动,但仍然没有。当我尝试在 JPanel 外部的框架中添加一个按钮时,它工作得很好。我做错了什么?

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class SnakeSettingsPanel extends JPanel 
    public boolean quit = false;
    public boolean play = false;
    public int width = 20;
    public int height = 15;
    public Speed speed = Speed.SLOW;

    public JTextField wField;
    public JTextField hField;
    public JComboBox<Speed> sField;

    public static void main(String[] args) 
        JFrame jf = new JFrame();
        jf.setTitle("Snake");
        SnakeSettingsPanel settings = new SnakeSettingsPanel();
        jf.add(settings);
        jf.pack();
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    

    public SnakeSettingsPanel() 
        setLayout(new GridBagLayout());

        // @author Create our labels.
        JLabel wLabel = new JLabel("Width:");
        JLabel hLabel = new JLabel("Height:");
        JLabel sLabel = new JLabel("Speed:");
        
        GridBagConstraints p = new GridBagConstraints();
            p.gridx = 0;
            p.gridy = 0;
            p.insets = new Insets(10, 10, 10, 10);

        // @author Create the buttons, and add listeners
        JButton y = new JButton("Play");
        JButton n = new JButton("Quit");
        y.addActionListener(new PlayListener());
        n.addActionListener(new QuitListener());

        // @author Create text fields for height/width
        wField = new JTextField(15);
        wField.setText("20");
        hField = new JTextField(15);
        hField.setText("15");

        // @author Creates a combobox for selecting speed.
        Speed[] speeds = Speed.SLOW, Speed.MEDIUM, Speed.FAST;
        sField = new JComboBox<Speed>(speeds);

        // @author Stitch everything into the panel.
        add(wLabel, p);
        p.gridx = 1;
        add(wField, p);
        p.gridx = 0;
        p.gridy = 1;
        add(hLabel, p);
        p.gridx = 1;
        add(hField, p);
        p.gridx = 0;
        p.gridy = 2;
        add(sLabel, p);
        p.gridx = 1;
        add(sField, p);
        p.gridx = 0;
        p.gridy = 3;
        add(y, p);
        p.gridx = 1;
        add(n, p);

        setVisible(true);
    

    public boolean getPlay() 
        return play;
    

    public boolean getQuit() 
        return quit;
    

    // @author Returns all settings as a SnakeSettings object
    public SnakeSettings getSettings() 
        return new SnakeSettings(width, height, speed);
    

    public int getWidth() 
        return width;
    

    public int getHeight() 
        return height;
    

    public Speed getSpeed() 
        return speed;
    

    // @author Sends out the word to start a new game.
    public class PlayListener implements ActionListener 
        public void actionPerformed(ActionEvent e) 
            quit = false;
            play = true;
            width = Integer.parseInt(wField.getText());
            height = Integer.parseInt(hField.getText());
            speed = (Speed) sField.getSelectedItem();
        
    

    // @author Sends out the word to shut down the program.
    public class QuitListener implements ActionListener 
        public void actionPerformed(ActionEvent e) 
            quit = true;
            play = false;
               
    

【问题讨论】:

【参考方案1】:

让这成为您为什么应该避免将模型(您的应用程序的数据)与视图(它的显示方式)混合在一起的一课。您的SnakeSettingsPanel 目前两者兼有。

作为模型,它包含 3 个重要字段:widthheightspeed。 作为 View,它是一个完整的 JPanel。 JPanel 有很多字段,您应该避免直接接触这些字段。包括widthheight,通常通过getHeightgetWidth 访问——您将使用始终返回相同内置值20 和15 的版本覆盖它们(直到用户通过他们看不到的 UI)。

快速 修复方法是重命名您当前的 getWidth()getHeight() 以避免与父 JPanel 类的内置 getWidth()getHeight() 方法发生冲突。打电话给他们getMyWidth()getMyHeight(),突然间一切正常。

更好的修复方法是完全删除这些字段和方法,并将您自己的模型属性存储在SnakeSettings 属性中。当用户点击播放时更新它,并在通过getSettings() 请求时返回它。为您减少代码,减少与您的父级 JPanel 类发生意外名称冲突的可能性。这看起来像:

    // SnakeSettingsPanel, before
    public int width = 20;
    public int height = 15;
    public Speed speed = Speed.SLOW;

    public int getWidth()     // <-- ***es with superclass
        return width;
    
    public int getHeight()    // <-- ***es with superclass
        return height;
    
    public Speed getSpeed() 
        return speed;
    
    public SnakeSettings getSettings() 
        return new SnakeSettings(width, height, speed);
    

    // SnakeSettingsPanel, after
    SnakeSettings settings = new SnakeSettings();

    public SnakeSettings getSettings() 
        return settings;
    

【讨论】:

谢谢,成功了。我什至没有考虑过与 JPanel 分开的某些类会以这种方式搞砸它。你知道具体的命名约定是如何导致一个不可见的面板的吗? 面板可见的——但它太小了,什么都没有显示(20x15,10px 插图,留给任何文本显示的空间很小)。这两个属性,宽度和高度,控制可见组件的大小。调用pack() 会使面板的布局管理器尝试为所有内容找到合适的尺寸;但是,在为您的面板找到理想的宽度和高度后,JFrame 会询问面板它想要的尺寸......面板总是回复它想要 20x15 像素的尺寸。这就是它被授予的大小。

以上是关于JPanel 未显示在 JFrame 中,但 JFrame 仍会更改大小的主要内容,如果未能解决你的问题,请参考以下文章

JPanel 更改未在 Jframe 上显示

Jpanel 和 Jframe 在运行时分别显示

JMenuBar显示在JFrame和JPanel中

JFrame 中的所有组件均未显示

在 JFrame 上更改 JPanel 组件时无法显示它

java中jframe 和jpanel的区别