简体   繁体   中英

Can't make JComboBox update JFrame

A little help would be really appreciated.

Problem

We have a fantasy class with aa combo box on it. When selecting a formation from the combobox, the frame gets updated with buttons. However because when I add the action listener to the combo box, it will only let me do it in the constructor of the fantasy class when creating my class in the main method, I have to hand in the fantasy class and the squad class to the TeamController class so when creating the fantasy class, the action listner isn't on the combo box, so it's not working. Any help would be highly appreciated.

Main Class

public class Main {

  public static void main(String[] args) {
    Fantasy f = new Fantasy();
    Squad s = new Squad();
    TeamController tc = new TeamController(f, s);
    TextController txC = new TextController(s);
    f.updateController(tc, txC);
    f.setVisible(true);
  }

}

Fantasy class

public class Fantasy extends JFrame {
  private JPanel goalPanel;
  private JPanel defendPanel;
  private JPanel midPanel;
  private JPanel attPanel;
  private JPanel bench;
  private JComboBox formation;
  private Button myButton;
  private TeamController control;
  private TextController tControl;
  private List < Button > buttons;

  public Fantasy() {
    super("Fantasy Football");
    buttons = new ArrayList < Button > ();
    createWidgets();
  }

  public void createWidgets() {
    JPanel formPanel = new JPanel(new GridLayout(1, 0));
    goalPanel = new JPanel(new FlowLayout());
    defendPanel = new JPanel(new FlowLayout());
    midPanel = new JPanel(new FlowLayout());
    attPanel = new JPanel(new FlowLayout());
    bench = new JPanel(new FlowLayout());

    JComboBox formation = new JComboBox();
    String[] addFormation = {
      "4 - 4 - 2", "4 - 3 - 3", "3 - 5 - 2", "5 - 3 - 2", "3 - 4 - 3", "4 - 5 - 1"
    };

    for (String newForm: addFormation) {
      formation.addItem(newForm);
    }

    formation.addActionListener(control);

    setLayout(new GridLayout(6, 0));
    add(formPanel);
    formPanel.add(formation);
    add(goalPanel);
    add(defendPanel);
    add(midPanel);
    add(attPanel);
    add(bench);

    pack();
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public JComboBox getForm() {
    return formation;
  }

  public JPanel getGoal() {
    return goalPanel;
  }

  public JPanel getDef() {
    return defendPanel;
  }

  public JPanel getMid() {
    return midPanel;
  }

  public JPanel getAtt() {
    return attPanel;
  }

  public JPanel getBench() {
    return bench;
  }

  public void createDefender(String text, String ID) {
    addButtons(text, ID, defendPanel);
  }

  public void createMid(String text, String ID) {
    addButtons(text, ID, midPanel);
  }

  public void createAtt(String text, String ID) {
    addButtons(text, ID, attPanel);
  }

  public void addButtons(String text, String ID, JPanel panel) {
    myButton = new Button(text, ID);
    myButton.getButton().addActionListener(control);
    myButton.getText().addTextListener(tControl);
    buttons.add(myButton);
    panel.add(myButton);
  }

  public void updateController(TeamController control, TextController tControl) {
    this.control = control;
    this.tControl = tControl;
  }

  public List < Button > getButtons() {
    return buttons;
  }

}

ActionListner - TeamController class

public class TeamController implements ActionListener {
  private Fantasy fantasy;
  private Squad squad;
  private JComboBox form;
  private ArrayList < Button > button;

  public TeamController(Fantasy fantasy, Squad squad) {
    this.fantasy = fantasy;
    this.form = fantasy.getForm();
    this.button = (ArrayList < Button > ) fantasy.getButtons();
    this.squad = squad;
  }


  public void actionPerformed(ActionEvent e) {
    if (e.getSource() == form) {
      comboChooser((JComboBox) e.getSource());
    } else {
      fileChooser((Button) e.getSource());
    }
  }

  public void comboChooser(JComboBox form) {
    //restart the pane
    fantasy.getContentPane().removeAll();
    fantasy.createWidgets();
    //add the goalie buttons and labels in
    fantasy.addButtons("GoalKeeper", squad.getAllGoal().get(0).getID(), fantasy.getGoal());
    //2. break it up into each def mid att
    //JComboBox format = form;
    String[] split = ((String) form.getSelectedItem()).split("-");
    int[] splits = new int[3];
    for (int i = 0; i < split.length; i++) {
      splits[i] = Integer.parseInt(split[i].trim());
    }
    //3. create number of widgets for each posit in each panel
    //4. add leftover to bench

    makeDefender(splits[0], squad.getAllDef());
    makeMid(splits[1], squad.getAllMid());
    makeAttack(splits[2], squad.getAllAtt());

    fantasy.pack();
  }

  public void fileChooser(Button button) {
    final JFileChooser fileChooser = new JFileChooser("C:\\Users\\Michael\\Documents\\Java WorkSpace\\ExerciseThree\\Minor Piece of Coursework 3 Resources\\squad");
    int getVal = fileChooser.showOpenDialog(button.getButton());
    if (getVal == JFileChooser.APPROVE_OPTION) {
      File file = fileChooser.getSelectedFile();
      button.getButton().setVisible(false);
      button.add(button.updateButton(file), BorderLayout.CENTER);
      Player selectedPlayer = squad.getByID(button.getName());
      selectedPlayer.setPath(file.getPath());
      String playerName = file.getName();
      if (playerName.endsWith(".jpg")) {
        playerName.substring(0, playerName.length() - 4);
        selectedPlayer.setName(playerName);
      }
      button.getText().setText(playerName);
    } else {
      System.out.println("Cancelled your choice");
    }

  }

  public void makeDefender(int number, List < Defender > list) {
    for (int i = 0; i < number; i++) {
      String ID = list.get(i).getID();
      fantasy.createDefender("Defender", ID);
    }
  }

  public void makeMid(int number, List < Midfielder > list) {
    for (int i = 0; i < number; i++) {
      String ID = list.get(i).getID();
      fantasy.createMid("Midfielder", ID);
    }
  }

  public void makeAttack(int number, List < Striker > list) {
    for (int i = 0; i < number; i++) {
      String ID = list.get(i).getID();
      fantasy.createAtt("Striker", ID);
    }
  }

  public void updateSquad(Squad squad) {
    this.squad = squad;
  }
}

So the basic answer to your question is to use an Observer Pattern , where the controller can observer changes the view makes and (presumably) notify the model.

Swing is already a form of MVC (albit a M-VC), so trying to implement another MVC on it is going to cause you headaches.

Instead, take a step back. The controller doesn't care how things get done, it only cares that it gets notified when they are done, so it doesn't actually need to know anything about how the view is implemented, only that it conforms to a known contract (it becomes a black box).

The view in turn doesn't care anything about the controller or model

This way, you could implement they view in any way you wanted and never have to change the controller to suit it, so long as you upheld the contact defined by the two

When I do things like this, I always start with interfaces, this allows me to focus on the requirements without needing to worry about the detail, "I want you do this", without caring about "how you get it done"...

public interface FantasyView {

    public String getFormation();
    public void setFormation(String formation); // Maybe throw an IllegalArgumentException or use an object or enum

    // Other information which the might be useful to return
    public void addFormationChangedObserver(ChangeListener listener);
    public void removeFormationChangedObserver(ChangeListener listener);

    public JComponent getView();

}

public interface SquadModel {
    // Some getters and setters
    // Some observers so the controller and get notified by changes and
    // update the view accordingly...
}

public interface TeamController {
    public FantasyView getView();
    public SquadModel getModel();
}

As you can see, FantasyView provides an observer for the change in formation through a ChangeListener (I'm lazy, so I'm re-using the available code), it doesn't say how that is generated, only that when the formation changes, it will generate an event.

None of the other interfaces actually implement ChangeListener , so it in of itself is not a requirement for the contract, but if you want to know when the formation changes, you will need to provide one.

Now, a possible implementation of the controller might look something like...

public class DefaultTeamController implements TeamController {

    private FantasyView view;
    private SquadModel model;

    public DefaultTeamController(FantasyView view, SquadModel model) {
        this.view = view;
        this.model = model;

        view.addFormationChangedObserver(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                SquadModel model = getModel();
                // update model accordingly
            }
        });

        // Add observers to model...
    }

    @Override
    public FantasyView getView() {
        return view;
    }

    @Override
    public SquadModel getModel() {
        return model;
    }

}

Has the controller been exposed to the view? No, it simply registers an instance of ChangeListener to the view. The view should never make assumptions about what the implementation of ChangeListener is and should only interact with the interface's contract

Now, you're probably wanting to know how you go from an ActionListener to a ChangeListener ....

JComboBox formation = new JComboBox();
//...
formation.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        fireFormationChanged();
    }
});

//...

protected void fireFormationChanged() {
    // changeListeners is a simple List of ChangeListener
    // this is instance of FantasyView
    ChangeEvent evt = new ChangeEvent(this);
    for (ChangeListener listener : changeListeners) {
        listener.stateChanged(evt);
    }
}

as an example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM