Sebmins
Sebmins

Reputation: 13

How to change size of frame, from another class

I am creating a maze generator, that randomly generates a maze given how many rows/columns the user wants. I can only get this working by creating a new JFrame every time I generate a maze rather than changing the existing frame.

I've tried creating a JFrame in the main then using that to change the size, I've tried making it public and changing it from within the button.

Frame() class

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() class

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

In VariableDetails() I have 2 JTextFields that captures the input of the user for the height and width of the maze.

Upvotes: 0

Views: 387

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347214

Model-View-Controller, or a more simple level, Passing Information to a Method or a Constructor and a observer pattern are the concepts you want to learn and understand.

Essentially, your "view" is a visual representation of your "model". The "view" "observers" the "model" for changes and updates itself accordingly.

In order to achieve this in your context, you need to share the model between both views, passing a reference to each. The "renderer" view will also "observer" the model for any possible changes

Start by defining the model...

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

Personally, I'd prefer to start with a interface to define the contract, but for brevity. The model should contain the data and logic required to manage the maze.

Next, update your classes so that the instance of the MazeModel can be passed in...

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

This now allows the classes an independent communication channel, via the ChangeListener, which ensures that they remain de-coupled.

A note about resizing the window

I wouldn't. Instead, I would pass the model to the instance MazeArea, so it could observer the changes to the model and update itself accordingly. I'd then wrap the MazeArea in a JScrollPane, which would allow it to change size to anything and the frame could remain at a relative static size.

See How to Use Scroll Panes for more details

As a user, it would annoy me to no end if I'd set the size of the window myself and you came along and changed it

Upvotes: 1

Alex
Alex

Reputation: 33

If have understood correctly what you want to do is change the size of the Frame from the panel. In order to do that you need the object Frame you want to resize in your Panel class. You can achieve this with a singleton pattern. You could also make the method setSize2 static and call it like this Frame.setSize(UserInputWidth,UserInputHeight)

I have rewritten your code using the singleton pattern. Hope it helps.

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

Upvotes: 0

Related Questions