I am trying to get this JPanel to display a generated maze when a button is pressed giving it the size.
I successfully get the size, and generate a maze which I know actionPerformed() has access to. When the button is clicked, it lets me know that a maze was in fact created, but doesn't display it.
I have the paint method traversing the maze array and filling rectangles to display it. But I'm not sure when it is called or how to call it manually. I am new to GUIs so please understand.
public class View extends JFrame implements ActionListener{
private static JPanel maze_box;
private static JLabel message;
private static JButton generate_button;
private static JTextField maze_size;
private static JTextField start_stop;
private static JButton solve_button;
private String coords;
private String size;
private final ArrayList<Integer> path = new ArrayList<Integer>();
private int[][] maze = {{}};
public void paint(Graphics g){
super.paint(g);
g.translate(50,50);
int scale = maze_box.getWidth()/maze.length;
for(int row=0; row<maze.length; row ){
for(int col=0; col<maze[0].length; col ){
System.out.println("drawing");
Color color;
switch (maze[row][col]) {
case 1 : color = Color.BLACK; break;
case 9 : color = Color.RED; break;
default : color = Color.WHITE;
};
g.setColor(color);
g.fillRect(10*col, 10*row, 10, 10);
g.setColor(Color.BLACK);
g.drawRect(10*col, 10*row, 10, 10);
}
}
for(int p=0; p<path.size(); p =2){
System.out.println("drawing");
int pathX = path.get(p);
int pathY = path.get(p 1);
g.setColor(Color.GREEN);
g.fillRect(pathX*10, pathY*10, 10,10);
}
super.paint(g);
}
public static void main(String[] args){
JPanel panel = new JPanel();
JFrame frame = new JFrame();
frame.setSize(800,800);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
panel.setLayout(null);
maze_box = new JPanel();
maze_box.setBounds(100, 20, 600, 400);
maze_box.setBackground(Color.GRAY);
panel.add(maze_box);
message = new JLabel();
message.setBounds(200, 400, 200, 30);
panel.add(message);
maze_size = new JTextField("size");
maze_size.setBounds(200, 550, 100, 30);
panel.add(maze_size);
generate_button = new JButton("Generate Maze");
generate_button.setBounds(500, 550, 100, 30);
panel.add(generate_button);
generate_button.addActionListener( new View());
start_stop = new JTextField("coords");
start_stop.setBounds(200, 600, 100, 30);
panel.add(start_stop);
solve_button = new JButton("Solve!");
solve_button.setBounds(500, 600, 100, 30);
panel.add(solve_button);
solve_button.addActionListener(new View());
}
@Override
public void actionPerformed( ActionEvent aActionEvent ) {
if ( aActionEvent.getSource() == generate_button ){
this.size = maze_size.getText();
try{
int sized = Integer.parseInt(this.size);
if(sized>199){
message.setText("Please choose a smaller width");
}if(sized<=0 || this.size.equals("")){
message.setText("Please enter valid numbers");
}else{
System.out.println("generating: ");
this.maze = new Generate(sized,sized).maze;
System.out.println("done " this.maze[0][2]);
}
}catch(NumberFormatException e){
message.setText("Please enter valid numbers");
}
}
}
}
Here is a picture for an idea.
CodePudding user response:
Okay, so you have a series of issues...
First, you create a JFrame
, make it visible and then add all you components to it...
JPanel panel = new JPanel();
JFrame frame = new JFrame();
frame.setSize(800, 800);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
...
panel.add(maze_box);
...
panel.add(message);
...
panel.add(maze_size);
...
panel.add(generate_button);
...
panel.add(start_stop);
...
panel.add(solve_button);
Swing is lazy, it won't update the UI immediately after an update. You could add panel.repaint()
at the end, but a much simpler solution is simply to move the frame.setVisible(true);
call to the end of the main
method.
The over use of static
is clear indication of a design problem and you should learn to live without out it (it has it's uses, this is not one of them).
This...
solve_button.addActionListener(new View());
is a bad idea, not helped by the over use of static
. You should only create a single instance of View
(in this context) and make use of it instead.
As a general recommendation, this is a bad place to start...
public class View extends JFrame implements ActionListener{
You should avoid extending from top level containers, they are complex, compound containers and you're not adding any new functionality to the class.
Which leads on to overriding paint
of a top level container, which should be avoided.
As stated, top level containers like JFrame
are complex, compound containers, that is, they already have a number of child components added to them, for example...
When overriding paint
like this, you are interfering with the painting of the child components and worse, because child components can be painted without invoking the parent components paint
workflow, you could end up with what ever you're painting been painted over.
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works and how you should work with it (the summary is, start with a JPanel
and override paintComponent
)
But, why are you calling super.paint
twice for?
public void paint(Graphics g) {
super.paint(g);
// ...
super.paint(g);
}
Mind you, View
itself is never actually made visible on the screen, so I'm at a general lose anyway
I would also recommend taking some time to go over:
If I was doing something like this, I'd be focusing on the individual areas of the UI and trying to break them down into smaller units of work and isolating their functionality, maybe something more like...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private JLabel message;
private JTextField mazeSize;
private JButton generateButton;
private JTextField startStop;
private JButton solveButton;
private MazePane mazePane;
public MainPane() {
setLayout(new BorderLayout());
mazePane = new MazePane();
add(mazePane);
JPanel inputPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = gbc.HORIZONTAL;
gbc.insets = new Insets(4, 4, 4, 4);
message = new JLabel("Make your selections");
inputPane.add(message, gbc);
gbc.gridy ;
mazeSize = new JTextField("size");
inputPane.add(mazeSize, gbc);
gbc.gridx ;
generateButton = new JButton("Generate Maze");
inputPane.add(generateButton, gbc);
generateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
generateMaze();
}
});
gbc.gridx = 0;
gbc.gridy ;
startStop = new JTextField("coords");
inputPane.add(startStop, gbc);
gbc.gridx ;
solveButton = new JButton("Solve!");
inputPane.add(solveButton, gbc);
add(inputPane, BorderLayout.SOUTH);
}
protected void generateMaze() {
String size = mazeSize.getText();
try {
int sized = Integer.parseInt(size);
if (sized > 199) {
message.setText("Please choose a smaller width");
} else if (sized <= 0) {
message.setText("Please enter valid numbers");
} else {
//System.out.println("generating: ");
//int[][] maze = new Generate(sized, sized).maze;
//System.out.println("done " this.maze[0][2]);
// Replace with maze
mazePane.setMaze(new int[][] {{}});
}
revalidate();
repaint();
} catch (NumberFormatException e) {
message.setText("Please enter valid numbers");
}
}
}
public class MazePane extends JPanel {
private int[][] maze = {{}};
private final ArrayList<Integer> path = new ArrayList<Integer>();
public MazePane() {
setBackground(Color.GRAY);
}
public void setMaze(int[][] maze) {
this.maze = maze;
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(50, 50);
int scale = getWidth() / maze.length;
for (int row = 0; row < maze.length; row ) {
for (int col = 0; col < maze[0].length; col ) {
System.out.println("drawing");
Color color;
switch (maze[row][col]) {
case 1:
color = Color.BLACK;
break;
case 9:
color = Color.RED;
break;
default:
color = Color.WHITE;
}
g2d.setColor(color);
g2d.fillRect(10 * col, 10 * row, 10, 10);
g2d.setColor(Color.BLACK);
g2d.drawRect(10 * col, 10 * row, 10, 10);
}
}
for (int p = 0; p < path.size(); p = 2) {
System.out.println("drawing");
int pathX = path.get(p);
int pathY = path.get(p 1);
g2d.setColor(Color.GREEN);
g2d.fillRect(pathX * 10, pathY * 10, 10, 10);
}
g2d.dispose();
}
}
}