简体   繁体   English

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

[英]JPanel not showing in JFrame, but JFrame still changes size

I don't know what I did, or what went wrong, but a change I made at some point in the last while has made my JPanel completely invisible.我不知道我做了什么,或者出了什么问题,但是我在最后一段时间所做的更改使我的 JPanel 完全不可见。 The JFrame it's nested in still changes in size to house it, and I can still toggle the content in the combobox. JFrame 它嵌套在它的大小仍然变化以容纳它,我仍然可以切换 combobox 中的内容。

In my desperation, I tried replacing the content of the SnakeSettingsPanel class with a single button, but the same thing happened - completely invisible, yet I can still interact with it.绝望中,我尝试用一个按钮替换 SnakeSettingsPanel class 的内容,但同样的事情发生了——完全不可见,但我仍然可以与之交互。 I figured it might be a computer error, so I tried restarting, but still nothing.我想这可能是一个计算机错误,所以我尝试重新启动,但仍然没有。 When I tried adding a button to the frame outside of the JPanel, it worked just fine.当我尝试在 JPanel 外部的框架中添加一个按钮时,它工作得很好。 What am I doing wrong?我究竟做错了什么?

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

Let this be a lesson on why you should avoid mixing Model (your application's data) with View (how it is displayed).让这成为您应该避免将 Model(您的应用程序的数据)与 View(如何显示)混合的教训。 Your SnakeSettingsPanel is currently both.您的SnakeSettingsPanel目前是两者。

  • As Model, it contains 3 important fields: width , height , and speed .作为 Model,它包含 3 个重要字段: widthheightspeed
  • As View, it is a full JPanel.作为 View,它是一个完整的 JPanel。 JPanels have a lot of fields which you should avoid touching directly. JPanel 有很多字段,您应该避免直接接触这些字段。 Including width and height , usually accessed via getHeight and getWidth -- which you are overwriting with a version that always returns the same built-in values of 20 and 15 (until the user changes those values through a UI that they cannot see).包括widthheight ,通常通过getHeightgetWidth访问——您将使用始终返回相同内置值 20 和 15 的版本覆盖它们(直到用户通过他们看不到的 UI 更改这些值)。

The fast fix is to rename your current getWidth() and getHeight() to avoid clashing with the built-in getWidth() and getHeight() methods of the parent JPanel class.快速解决方法是重命名您当前的getWidth()getHeight()以避免与父 JPanel class 的内置getWidth()getHeight()方法发生冲突。 Call them getMyWidth() , getMyHeight() , and suddenly everything works.打电话给他们getMyWidth()getMyHeight() ,突然一切正常。

The better fix is to remove those fields and methods entirely, and store your own model attributes in a SnakeSettings attribute.更好的解决方法是完全删除这些字段和方法,并将您自己的 model 属性存储在SnakeSettings属性中。 Update it when the user clicks on play, and return it when it is requested via getSettings() .当用户点击播放时更新它,并在通过getSettings()请求时返回它。 Less code for you, less chance of accidental name clashes with your parent JPanel class.为您减少代码,减少与您的父JPanel class 发生意外名称冲突的可能性。 This would look like:这看起来像:

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

    public int getWidth() {    // <-- clashes with superclass
        return width;
    }
    public int getHeight() {   // <-- clashes 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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM