简体   繁体   English

无法使JComboBox更新JFrame

[英]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. 但是,因为当我将动作侦听器添加到组合框时,当在main方法中创建我的类时,它只会让我在Fantasy类的构造函数中进行操作,因此我必须将Fantasy类和squad类交给TeamController类,因此在创建幻想类时,动作列表器不在组合框上,因此无法正常工作。 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 ActionListner-TeamController类

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. Swing已经是MVC的一种形式(也称为M-VC),因此尝试在其上实现另一个MVC会让您头疼。

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. 如您所见, FantasyView通过ChangeListener提供了一个观察构造变化的观察者(我很懒,所以我在重复使用可用的代码),它没有说明它是如何产生的,只有当形成时更改,它将生成一个事件。

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. 其他接口实际上都没有实现ChangeListener ,因此它本身并不是合同的要求,但是如果您想知道格式何时发生变化,则需要提供一个接口。

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. 不,它只是向视图注册一个ChangeListener实例。 The view should never make assumptions about what the implementation of ChangeListener is and should only interact with the interface's contract 该视图永远不应该假设ChangeListener的实现是什么,而应该仅与接口的协定进行交互

Now, you're probably wanting to know how you go from an ActionListener to a ChangeListener .... 现在,您可能想知道如何从ActionListener变为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 举个例子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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