7年前关闭。
我试图了解如何在我的Java应用程序中实现MVC,阅读一些教程和MVC hello世界,但是我仍然不确定很多事情,因此,如果您能帮助我理解所有这些内容,我将非常高兴。
假设我有一个简单的GUI应用程序,用于存储和使用各种建筑物。我可以通过从列表中选择类型并按按钮来添加建筑物。这些建筑物将存储在一些arraylist中,在GUI中显示,并且可以编辑(房间数,层数.....不重要)。建筑物将显示在JComboBox中,选择某些建筑物后,将显示该建筑物的设置面板。
到目前为止,我有2个“组件”。 建筑物(容器)和建筑物。我创建了 BuildingsModel 类,该类保存建筑物,并提供一些与建筑物配合使用的方法,并在更改后通知观察者。然后,我有一个 BuildingsView 类,它正在观察BuildingsModel。然后,我仅使用构造函数方法使用 BuldingsController 类,该类将BuildingsModel和BuildingsView作为参数,将视图绑定为模型作为观察者,创建一些初始建筑物并向该视图添加一些侦听器。
现在我不知道如何继续。有些事情我不是很高兴。
这是代码中最重要的部分。我没有包括BuildingModel类及其子类,因为目前它们只是带有toString()方法的空白类。
public class BuildingsController {
public BuildingsController(final BuildingsModel model, final BuildingsView view) {
class addBuildingButtonActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String selectedBuildingType;
if ((selectedBuildingType = view.getSelectedBuildingType()) != null) {
try {
BuildingModel newBuilding = (BuildingModel) Class.forName("building.models." + selectedBuildingType + "BuildingModel").newInstance();
model.addBuilding(newBuilding);
} catch (InstantiationException ex) {
//addToErrorLog
} catch (IllegalAccessException ex) {
//addToErrorLog
} catch (ClassNotFoundException ex) {
//addToErrorLog
}
} else {
//addToLog - NO_BUILDING_SELECTED
}
}
}
class buildingComboBoxSelectListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
BuildingModel selectedBuilding;
if ((selectedBuilding = view.getSelectedBuilding()) != null) {
//display current building form???
}
}
}
model.addObserver(view);
model.addBuilding(new HospitalBuildingModel());
model.addBuilding(new SchoolBuildingModel());
view.fillBuildingTypesList(BuildingsModel.getAllBuildingsTypes());
view.addAddBuildingButtonListener(new addBuildingButtonActionListener());
view.addActiveBuildingsListener(new buildingComboBoxSelectListener());
}
}
public class BuildingsModel extends Observable {
private static String[] allBuildingsTypes = {"School", "Hospital", "Stadion"};
private ArrayList<BuildingModel> buildings = new ArrayList<BuildingModel>();
public void addBuilding(BuildingModel building){
this.buildings.add(building);
this.setChanged();
this.notifyObservers();
}
public BuildingModel[] getAllBuildings(){
return this.buildings.toArray(new BuildingModel[this.buildings.size()]);
}
public static String[] getAllBuildingsTypes(){
return BuildingsModel.allBuildingsTypes;
}
}
public class BuildingsView implements Observer {
private static String name = "Buldings";
private static String addBuildingButtonText = "Add building";
private JComboBox allActiveBuildings = new JComboBox();
private JList buildingTypesList = new JList();
private JButton addBuildingButton = new JButton(BuildingsView.addBuildingButtonText);
@Override
public void update(Observable model, Object o){
BuildingModel[] allBuildings = ((BuildingsModel) model).getAllBuildings();
this.allActiveBuildings.removeAllItems();
for(BuildingModel building : allBuildings){
this.allActiveBuildings.addItem(building);
}
}
public String getSelectedBuildingType(){
return (String) this.buildingTypesList.getSelectedValue();
}
public BuildingModel getSelectedBuilding(){
return (BuildingModel) this.allActiveBuildings.getSelectedItem();
}
public void fillBuildingTypesList(String[] buildingTypes){
this.buildingTypesList.setListData(buildingTypes);
}
public void addAddBuildingButtonListener(ActionListener l){
this.addBuildingButton.addActionListener(l);
}
public void addActiveBuildingsListener(ActionListener l){
this.allActiveBuildings.addActionListener(l);
}
public JComponent display(){
JPanel panel = new JPanel();
Border border = BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(BuildingsView.name), BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.setBorder(border);
panel.add(this.allActiveBuildings);
panel.add(this.buildingTypesList);
panel.add(this.addBuildingButton);
panel.setPreferredSize(new Dimension(200, 262));
return panel;
}
}
主要:
public static void main(String[] args) {
BuildingsView buildingsView = new BuildingsView();
BuildingsModel buildingsModel = new BuildingsModel();
BuildingsController buldingsController = new BuildingsController(buildingsModel, buildingsView);
mainWindow window = new mainWindow("MVC test", buildingsView);
window.generateDefaultLayout();
window.showMainWindow();
}
窗口:
public class mainWindow extends JFrame {
private JPanel buildingsPanel = new JPanel();
private BuildingsView buildingsView;
public mainWindow(String title, BuildingsView buildingsView) {
this.buildingsView = buildingsView;
this.setTitle(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void generateDefaultLayout(){
this.setLayout(new FlowLayout());
this.setPreferredSize(new Dimension(1200, 920));
this.addBuildingsPanel();
}
public void addBuildingsPanel(){
this.buildingsPanel.add(this.buildingsView.display());
this.add(this.buildingsPanel);
}
public void showMainWindow(){
this.pack();
this.setVisible(true);
}
}
谢谢 :)
最佳答案
我已将侦听器绑定到该按钮,该按钮将从视图中的JList获取当前选择,创建新对象(xxxBuildingModel)并将其添加到BuildingsModel。但是,JList仅包含所有建筑类型的String表示形式,并且为了避免冗长的if-else状态菜单和为该String找到正确的类,我不得不使用反射。 (每种建筑类型都有其自己的扩展BuildingModel的类。)还有更好的方法吗?
是。不要让您的JList包含字符串,而是让它包含Building(非GUI)对象。使用ListCellRenderer告诉JList如何最好地显示每个建筑物。然后,当用户从JList中选择一项时,他们选择的是实际的建筑对象,而不是其String表示形式。当然,不要考虑任何反射Reflection 。
第二个侦听器绑定到包含已创建的建筑实例的JComboBox。在该组合框中选择建筑物后,我要显示该建筑物的设置表单。因此,我猜应该有一些与BuildingModel相关的视图类将显示其当前设置(模型的状态)。但是我不确定如何从BuildingsController的构造函数上下文中执行此操作。
您可以在Control类中拥有AbstractAction类,并将其用作JComboBox的侦听器(有关此问题的更多信息,请参见我对上一个问题here的回答)。
我只能访问建筑物的模型,因此如何为该实例“找到”正确的视图并显示它?
您将从侦听器中获取选定的建筑物,然后侦听器将通过在视图上调用公共方法来通知GUI在选择后更改视图。
也许我做错了所有事情,并且组合框不应该只包含模型,而应该包含控制器(可以访问模型和视图),
组合框的侦听器将是控件的一部分,是的。这将可以访问模型和视图。
在这种情况下,我可以调用控制器的view方法,该方法将从模型中获取所需的数据,并将其传递给视图并显示。
我对您的程序本身的具体细节还不确定,是否能够回答这个问题。
编辑1
在检查您的代码时,我发现一个潜在的问题:
private static String[] allBuildingsTypes = {"School", "Hospital",
"Stadion"};
private ArrayList<BuildingModel> buildings = new ArrayList<BuildingModel>();
您不应该在这里使用Strings,而应该使用行为良好的面向对象的Building类,该类具有名称String,以及所有其他对Building对象所需的属性都重要的属性。然后,您的模型应处理建筑对象集合,而不是建筑的字符串表示形式。您的视图将显示这些建筑物的属性,并使用户能够更新您允许它们更改的属性。
这涉及到程序结构的核心,因此我认为这非常重要,并且这样做可能需要您更改所有内容,但从长远来看,这是非常值得的。
编辑1b :我已纠正。看来您有一个与此相关的类,BuildingModel,该类的代码尚未在此处发布。我想知道您的BuildingTypes是否应该是BuildingModel类的一部分的枚举。
编辑2
有关与Swing-MVC相关的代码的更多答案,请查看以下链接: