[英]Can't make JComboBox update JFrame
A little help would be really appreciated. 一点帮助将不胜感激。
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. 任何帮助将不胜感激。
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;
}
}
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.