Reputation: 13
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
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.
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
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