-1

In my view I have overrided an actionPerformed() method, inside of it I want to call a method updateMap() that is in my Controller. I've tried writing: MapController.updateMap(selected), but this gives an error: non-static method 'updateMap(int)' cannot be referenced from a static context.

I've tried making updateMap() static but this gives me a load of errors inside the updateMap(). I just wish to know how I can call the updateMap() of the Controller inside my actionPerformed() method inside the View.

My controller:

package main.java.controllers;
import main.app.view.MapView;
import main.java.models.MapModel;
import org.w3c.dom.ls.LSOutput;

import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;

public class MapController {
    private MapView view;
    private MapModel model;

    public MapController(MapView view, MapModel model) {
        this.view = view;
        this.model = model;
        this.model.getAllRoutes();

        ArrayList<String> routes = model.getAllRoutes();
        this.view.getRouteComboBox().getSelectedItem();
        this.view.setComboBoxValues(routes);
        this.updateMap(2);
        this.view.setVisible(true);
    } //constructor end

    public void updateMap(int routeID){
        model.fillCoordinateListArray(routeID);
        Image image = null;
            try {
                URL url = new URL("https://maps.googleapis.com/maps/api/staticmap?" +
                        "&size=600x450" +
                        "&maptype=roadmap" +
                        this.model.parseCoordinates() +
                        //"San+Francisco,CA" + "%7C" +
                        //"&markers=label:1%7C40.702147,-74.015794" + "%7C" +

                        "&key=AIzaSyAbLM94WcbkB-cf_ubHXOHmCDSsNWEz7XE");
                image = ImageIO.read(url);
              //  System.out.print(url);
            } catch (IOException e) {
                System.out.println("Ongeldige URL");
                e.printStackTrace();
        }
        this.view.setImage(image);
        this.view.repaint();
    } //method end



      /*  public int getSelected(){
            return this.selected;
        } */


} //class end

My view:

package main.app.view;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;


import main.java.controllers.MapController;
import main.java.models.MapModel;
import main.resources.ConnectionManager;

public class MapView extends JPanel {
    public Image image;
    private JLabel jlImage;
    private static JButton jbOk;
    private ArrayList<String> comboBoxValues;
    private JComboBox routeComboBox = new JComboBox();
    //private JComboBox<ArrayList<>>;
    private ActionListener actionListener;

    public MapView(){
        super(new FlowLayout());
        setSize(900, 450);
        this.add(getRouteComboBox());
        jbOk = new JButton("OK");
        jbOk.setActionCommand("OK");
        ListenerOfActions listener = new ListenerOfActions();
        jbOk.addActionListener(listener);
        add(jbOk);

    } //constructor end

    public void setComboBoxValues(ArrayList<String> comboBoxValues) {
        this.comboBoxValues = comboBoxValues;
        for (String item: comboBoxValues) {
            routeComboBox.addItem( item );
        }
    }

    public void setImage(Image image){
        this.image = image;
    }


    public MapView getView(){
        jlImage = new JLabel(new ImageIcon(this.image));
        add(jlImage);
        return this;
    }

    public void addListenerOfActions(ActionListener listenForAction) {
        this.actionListener = listenForAction;
    }

    public JComboBox getRouteComboBox(){
        return routeComboBox;
    }

    class ListenerOfActions implements ActionListener {
        int selected = 0;

        @Override
        public void actionPerformed(ActionEvent e) {

            String actionCommand = e.getActionCommand();
            if(actionCommand.equals("OK")) {
                 int selected = getRouteComboBox().getSelectedIndex() + 1;
                 System.out.println(selected);
                System.out.println("print1");

                   MapController.updateMap(selected);
            }
            System.out.println("print2");

        }

        public int getSelected(){
            return this.selected;
        }


    } //class end
} //class end

1 Answers1

0

Trying to call controller methods in a static way is definitely not the answer, and I don't recommend using a singleton unless absolutely necessary (as was recommended by another answer), since singleton use can be tricky as per the Stack Overflow What is so bad about singletons? Q/A.

Why not simply give MapView a MapController field and pass in the instance via a setter method that can be called in the MapController constructor? For example:

public class MapView {
    private MapController controller;
    // ...

    public MapView() {
        //......
    }

    public void setMapController(MapController controller) {
        this.controller = controller;
    }

    // then here you can call the instance methods as needed

}

and wire it up like this:

public class MapController {

    public class MapController {
        private MapView view;
        private MapModel model;

        public MapController(MapView view, MapModel model) {
            this.view = view;
            this.model = model;    
            view.setMapController(this);

            // .....
}

Since in this example, the controller is being passed into the view via a setter parameter and not a constructor parameter, there is no guarantee present that this wiring will occur. and so within the view, it would be wise to do a null test before trying to call controller methods, and if null is detected, perhaps throw an exception that makes sense to you and the user.

So, again, this is bad: private static JButton jbOk;

Make all GUI components instance and not static. I also prefer to avoid using a single ActionListener for the whole GUI, the so-called "switch-board" listener, since that can increase program complexity unnecessarily. Better to use anonymous inner listeners, ones that call the controller methods.