【问题标题】:How to change size of frame, from another class如何从另一个类更改框架的大小
【发布时间】:2018-12-30 19:31:51
【问题描述】:

我正在创建一个迷宫生成器,它会根据用户想要的行数/列数随机生成一个迷宫。我只能通过每次生成迷宫而不是更改现有框架时创建一个新的JFrame 来完成这项工作。

我尝试在主目录中创建一个JFrame,然后使用它来更改大小,我尝试将其公开并在按钮内进行更改。

Frame() 类

public class Frame extends JFrame {
    private VariableDetails vDetails;
    private MazeArea mArea;

    private int width;
    private int height;

    public Frame(String title) {
        super(title);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);

        width = 500;
        height = 500;
        setSize(width,height);

        setLayout(new BorderLayout());

        mArea = new MazeArea();
        vDetails = new VariableDetails();

        Container c = getContentPane();

        c.add(mArea, BorderLayout.CENTER);
        c.add(vDetails, BorderLayout.EAST);
    }

    public void setSize2(int width, int height) {
        setSize(width,height);
    }

VariableDetails() 类

public class VariableDetails extends JPanel {
    public VariableDetails() {
        JButton genBtn = new JButton("Generate");
        genBtn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e)
        {
            setSize2(UserInputWidth,UserInputHeight);
        }
});
}

VariableDetails() 我有 2 个JTextFields 捕获用户输入的迷宫高度和宽度。

【问题讨论】:

  • 到底是什么失败了?你能分享你的IDE给你的错误吗?只是在黑暗中开枪,但您是说您在从另一个类调用“setSize”方法时遇到问题?
  • 这里没有扩展JFrameJPanel 的情况。只需使用标准(非扩展)组件并根据需要填充它们。类的扩展在很大程度上导致了按钮没有参考框架的问题。一般提示: 1) 为了尽快获得更好的帮助,edit 添加minimal reproducible exampleShort, Self Contained, Correct Example。 2) 请学习常见的 Java 命名法(命名约定 - 例如EachWordUpperCaseClassfirstWordLowerCaseMethod()firstWordLowerCaseAttribute,除非它是 UPPER_CASE_CONSTANT)并始终如一地使用它。
  • 目前它会生成一个具有所需大小的新框架,而不是仅仅将大小更改为所需的大小。
  • “目前是..” 你在回复谁?提示:添加@TerryDorsey(或重要的@)以通知此人有新评论。顺便说一句 - 我们什么时候可以看到 SSCCE / MCVE?

标签: java swing jframe


【解决方案1】:

Model-View-Controller,或更简单的级别,Passing Information to a Method or a Constructorobserver pattern 是您想要学习和理解的概念。

本质上,您的“视图”是您的“模型”的可视化表示。 “视图”“观察”“模型”以进行更改并相应地更新自身。

为了在您的上下文中实现这一点,您需要在两个视图之间共享模型,并传递对每个视图的引用。 “渲染器”视图还将“观察”模型以进行任何可能的更改

从定义模型开始...

public class MazeModel {

    private List<ChangeListener> listeners = new ArrayList<>(25);

    private int rows;
    private int cols;

    public void setSize(int cols, int rows) {
        this.cols = cols;
        this.rows = rows;

        fireStateChanged();
    }

    public int getRows() {
        return rows;
    }

    public int getCols() {
        return cols;
    }

    public void addChangeListener(ChangeListener listener) {
        listeners.add(listener);
    }

    public void removeChangeListener(ChangeListener listener) {
        listeners.remove(listener);
    }

    protected void fireStateChanged() {
        ChangeEvent evt = new ChangeEvent(this);
        for (ChangeListener listener : listeners) {
            listener.stateChanged(evt);
        }
    }
}

就个人而言,我更喜欢以interface 开头来定义合同,但为了简洁起见。该模型应包含管理迷宫所需的数据和逻辑。

接下来,更新您的类,以便可以传入 MazeModel 的实例...

public class Frame extends JFrame {

    private VariableDetails vDetails;
    private MazeArea mArea;

    private int width;
    private int height;

    private MazeModel model;

    public Frame(String title, MazeModel model) {
        super(title);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.model = model;
        this.model.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                // Update the state as required...
            }
        });

        width = 500;
        height = 500;
        // Prefer pack :/
        setSize(width, height);

        setLayout(new BorderLayout());

        // I'm guessing that model should be passed to this
        // and it should modify it's state accoridingly....
        mArea = new MazeArea();
        vDetails = new VariableDetails(model);

        Container c = getContentPane();

        c.add(mArea, BorderLayout.CENTER);
        c.add(vDetails, BorderLayout.EAST);
        setVisible(true);
    }

    public class VariableDetails extends JPanel {

        private MazeModel model;

        public VariableDetails(MazeModel model) {
            this.model = model;
            JButton genBtn = new JButton("Generate");
            genBtn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    model.setSize(cols, rows);
                }
            });
        }
    }
}

这现在允许类通过ChangeListener 建立一个独立的通信通道,从而确保它们保持解耦。

关于调整窗口大小的说明

我不会。相反,我会将模型传递给实例MazeArea,因此它可以观察模型的变化并相应地更新自身。然后我将MazeArea 包裹在JScrollPane 中,这样它就可以将大小更改为任何内容,并且框架可以保持相对静态大小。

详情请见How to Use Scroll Panes

作为一个用户,如果我自己设置窗口的大小,而你来改变它,我会很恼火

【讨论】:

    【解决方案2】:

    如果已经正确理解您想要做的是从面板更改框架的大小。为此,您需要在 Panel 类中调整大小的对象 Frame。您可以使用单例模式来实现这一点。您还可以将方法 setSize2 设为静态并像这样调用它Frame.setSize(UserInputWidth,UserInputHeight)

    我已经使用单例模式重写了您的代码。希望对您有所帮助。

    public class Frame extends JFrame {
    private VariableDetails vDetails;
    private MazeArea mArea;
    
    private int width;
    private int height;
    private static Frame instance;
    
    public static Frame getInstance() {
      if(instance==null) {
        instance=new Frame();
      }
      return instance;
    }
    
    public Frame(String title) {
        super(title);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    
        width = 500;
        height = 500;
        setSize(width,height);
    
        setLayout(new BorderLayout());
    
        mArea = new MazeArea();
        vDetails = new VariableDetails();
    
        Container c = getContentPane();
    
        c.add(mArea, BorderLayout.CENTER);
        c.add(vDetails, BorderLayout.EAST);
    }
    
    
    public class VariableDetails extends JPanel {
        public VariableDetails() {
            JButton genBtn = new JButton("Generate");
            genBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                Frame.getInstance().setSize(width,height);
            }
            });
        }
    }
    }
    

    【讨论】:

    • 好吧,除了一个糟糕的单例实现之外,在这种情况下可能有点矫枉过正,使用“模型”来表示数据/逻辑可以传递给所有类和一个用于促进跨类通信的简单“观察者模式”......只是说
    • @MadProgrammer 我同意观察者模式更好,我没有考虑过。我是一个小新手,所以你能告诉我为什么我的实现很差以及如何改进它吗?感谢您的反馈!
    • @MadProgrammer 我从未见过在序列化中应用单例的问题。对不起,我的回答很糟糕,感谢您的回复!
    • 这有同样的问题,当你改变大小时,它会创建一个新的框架而不是调整大小。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多