【问题标题】:Can't make JComboBox update JFrame无法让 JComboBox 更新 JFrame
【发布时间】:2016-03-03 20:57:36
【问题描述】:

非常感谢您的帮助。

问题

我们有一个幻想类,上面有一个组合框。从组合框中选择一个编队时,框架会使用按钮进行更新。但是因为当我将动作监听器添加到组合框时,它只会让我在main方法中创建我的类时在幻想类的构造函数中进行,我必须将幻想类和小队类交给TeamController 类所以在创建幻想类时,动作监听器不在组合框中,所以它不起作用。任何帮助将不胜感激。

主类

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);
  }

}

幻想类

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 类

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;
  }
}

【问题讨论】:

  • 在你的Fantasy类中提供一个addActionListener方法,当它的构造函数被调用时,它可以被你的TeamController调用,它注册了JComboBox
  • @MadProgrammer 我正在使用严格的 MVC。所以我将无法在我的视图中使用控制器
  • 我没有要求你将控制器传递到视图中,我要求你将ActionListener 传递给视图,以便它可以生成执行ActionListener 的事件(控制器)可以做出反应,这通常与您最初尝试做的事情没有什么不同。如果您不能在视图中使用控制器,那么 private TextController tControl;Fantasy 类中做了什么?我的解决方案会让你摆脱这个
  • Swing 是 MVC 的一种形式(尽管是 M-VC),所以包装另一个 MVC 实现会让您头疼不已。相反,请关注每一层提供的功能,例如,您的视图会生成一个“formation changed”事件,您的控制器需要对此做出反应。控制器实际上并不关心它是如何生成的,只是它可以是,事实上,您的控制器根本不应该关心 UI 或 UI 组件,只需要维护它和视图之间的一些可定义的联系
  • @MadProgrammer 对不起,真的不明白。你想让我在幻想中创建一个新的 actionlistner,如果是,你想让它做什么?是否用于获取选定的组合框值并将其交给团队控制器?

标签: java swing jframe actionlistener jcombobox


【解决方案1】:

因此,您问题的基本答案是使用Observer Pattern,控制器可以在其中观察视图所做的更改并(可能)通知模型。

Swing 已经是 MVC 的一种形式(尽管是 M-VC),因此尝试在其上实现另一个 MVC 会让您头疼。

相反,退后一步。控制器不关心事情是如何完成的,它只关心它在完成时得到通知,所以它实际上不需要知道视图是如何实现的,只需要它符合一个已知的合同(它变成一个黑盒子)。

视图不关心控制器或模型

这样,您可以以任何您想要的方式实现他们的视图,而无需更改控制器以适应它,只要您维护两者定义的联系

当我做这样的事情时,我总是从接口开始,这让我可以专注于需求而不用担心细节,“我希望你这样做”,而不关心“你如何完成它” ...

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();
}

如您所见,FantasyView 通过ChangeListener 提供了一个观察者来观察阵型的变化(我很懒,所以我重新使用了可用的代码),它没有说明这是怎么回事生成,只有当阵型发生变化时,才会生成一个事件。

其他接口都没有真正实现ChangeListener,所以它本身不是合约的要求,但如果你想知道什么时候形成变化,你需要提供一个。

现在,控制器的可能实现可能类似于...

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;
    }

}

控制器是否暴露在视图中?不,它只是将ChangeListener 的实例注册到视图。视图不应该假设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);
    }
}

举个例子

【讨论】:

    猜你喜欢
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2014-04-11
    • 2012-01-11
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    相关资源
    最近更新 更多