Search code examples
javaswingmodel-view-controllerobserver-pattern

Black frame after action event and many notifyObservers


i am trying to implement the MVC and Observer patterns into my java application. I have an application that creates a maze and also solves it.

Basically i have found out that the notifyObserver() calls are working as expected. The maze is getting printed after the button click "create". But at the end of the actionEvent the whole frame is getting black and i don't know why.

see the interesting parts of the panel object:

 public class MazePanel extends JPanel implements Observer {

 .....some instance vars ect.....

    public void buildFrame(){

    // create the frame
    JFrame frame = new JFrame("Labyrinth Solver");   

    // create the JPanel
    canvas = new JPanel();
    canvas.setBorder(BorderFactory.createEmptyBorder(1000, 1000, 1000, 1000));
    canvas.setPreferredSize(new Dimension(getDimension()*zoom, getDimension()*zoom));

    // add the canvas to the frame and make it visible
    frame.add(canvas);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true); 
    frame.setResizable(false);
    frame.setBackground(Color.black);
}

@Override
protected void paintComponent(Graphics g){

    super.paintComponent(g);

    if(mode.equals("create")) {
            g.setColor(Color.white);
    }
    g.fillRect(curCoordinate.getX()*zoom, curCoordinate.getY()*zoom, 1*zoom, 1*zoom );
}

@Override
public void update(Observable observable, Object o) {

    curCoordinate = (Coordinate)o;
    paintComponent(canvas.getGraphics());

    try {
        Thread.sleep(getSpeed());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

see my controlloer with the action event:

public class MazeController {
 private MazeModel model;
 private MazeView view;
 private MazePanel mazePanel;
 private Builder mazeBuilder;

 public MazeController(MazeModel model, MazeView view) {
    this.model = model;
    this.view = view;

    mazePanel = new MazePanel();

    // Create Gui
    view.createAndShowGUI();

    // Add Listeners
    view.addChangeSpeedListener(new SpeedChangeAction());
    view.addCreateListener(new CreateActionListener());
}


private class CreateActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {

        // Configure the MazePanel object
        mazePanel.setMode("create");
        mazePanel.setZoom(view.getZoom());
        mazePanel.setDimension(view.getDimension());
        mazePanel.setSpeed(view.getSpeed());

        // Build panel
        mazePanel.buildFrame();

        // Get Build Type
        String createAlgorithm = view.getCreateAlgorithm();

        // Build selected maze
        if (createAlgorithm.equals("Depth-First")) {
            mazeBuilder = new DepthFirstSearch(model, view.getDimension());
        } 

        // Register observer
        mazeBuilder.registerObserver(mazePanel);


        // Build Maze
        mazeBuilder.build();

        // print data strucutre as array if debugging is enabled
        if(view.getDebug()){
            model.printAsArray();
        }

    }
}

actually the code is also available here: https://github.com/do3meli/Labyrinth/tree/MVC/src/main/java/ch/zhaw/labyrinth


Solution

  • You are mixing things up: Both the MazePanel as well as the JPanel called 'canvas' are components that can be 'painted'. While you are apparently trying to paint the 'canvas' component, you are invoking the paintComponent method in your class MazePanel. I guess what you want is to paint the 'canvas' component.

    Without being all that much into Swing, I think it is wrong to call the method paintComponent anyway. What you should do, is implementing you own subclass of JPanel and then override the paintComponent method. Whenever you want that component to be repainted, you call the method called 'repaint'.

    Painting in Swing: http://www.oracle.com/technetwork/java/painting-140037.html#swing