MVC Architektur

PhilippGer

Mitglied
Hi!
Ich soll für ein Uni-Projekt ein kleines Testprogramm nach Model-View-Controller-Architektur erstellen.

Ein Fenster mit einer Liste, ich kann in einem textfeld etwas eingeben, dass wird dann an die Liste angehängt. Beim Beenden des Programms soll sich die liste in eine Datei hinnein serialisieren und beim Starten soll sie aus dieser Datei heraus wieder geladen werden.

Soweit eigentlich kein Problem.

Das Reagieren auf Starten/Beenden des Programms woltle ich per WindowListener des View-Teils machen. Allerdings wirft er mir jedes mal eine, mir nicht erklärliche Exception, wenn ich das tun will.
Hier mal der, für diese Teile relevante, Quellcode:

View:
Code:
public class View{
	
	private JFrame frame;
	private List list;
	private Modell modell;
	protected JTextField obstnameTf;
	protected JTextField obstpreisTf;
	private JButton addButton;

	// Action Listener für den Hinzufügen-knopf
	void addAddListener(ActionListener al){
		this.addButton.addActionListener(al);
	}
	
	// Action Listener für das Schließen
	void addWindowListener( WindowListener w){
		// NullPointerException
		this.frame.addWindowListener(w);
	}

}



Controller:
Code:
public class Controller {
	
	private Modell modell;
	private View view;
	private String filepath = "obstliste.ser";

	public Controller( Modell modell, View view){
		this.modell = modell;
		this.view = view;
		this.view.addAddListener( new addListener() );
		this.view.addWindowListener( new wListener() );
	}

	// Hinzufügen-Befehl
	class addListener implements ActionListener { 
	    public void actionPerformed(ActionEvent e){ 
	    	modell.add( view.nameTf.getText() + ": " + view.preisTf.getText() + "€" );
	    	view.update(); // Im add-Befehl werdne nur bestimmte Textfelder im View abgefragt
	    }
	}
	
	// Schließ-Befehl
	class wListener implements WindowListener {
		@Override
		public void windowClosing(WindowEvent arg0) {
			modell.saveToFile(filepath);
		}

		@Override
		public void windowOpened(WindowEvent arg0) {
			modell.loadFromFile(filepath);
			view.update();
		} 
                          /*Alle anderen durch WindowListener erforderlichen Methoden sind leer gelassen*/
	}
	
}


Erstellt wird das Ganze durch:
Code:
Modell modell = new Modell();
View view = new View(modell);
Controller controller = new Controller( modell, view);

Als Exception wirft er mir:
Code:
java.lang.NullPointerException
	at Aufgabe4.View.addWindowListener(View.java:85)
	at Aufgabe4.Controller.<init>(Controller.java:18)
	at Aufgabe4.Main.main(Main.java:12)


Ich habe absolut keine Idee, warum an der Stelle eine NullPointerException kommen soll. Ich sehe nicht, wo da etwas fehlerhaft sein sollte.
Seh ich den Wald vor lauter Bäumen nicht oder wieso?

Anm. das Hinzufügen des Listeners für den Button funktioniert einwandfrei!
 
Ist das der ganze Code? Ich sehe nämlich nicht, dass irgendwie in deiner View-Klasse (inbesondere der Button und der Frame) jemals zugewiesen werden.
 
Nein, ist wiegesagt der mir relevant erscheinende Teil!

Aber hier nochmal der gesamte Code:
Code:
package Aufgabe4;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

public class Controller {
	
	private Modell modell;
	private View view;
	private String filepath = "obstliste.ser";

	public Controller( Modell modell, View view){
		this.modell = modell;
		this.view = view;
		this.view.addAddListener( new addListener() );
		this.view.addWindowListener( new wListener() );
	}

	// Hinzufügen-Befehl
	class addListener implements ActionListener { 
	    public void actionPerformed(ActionEvent e){ 
	    	modell.add( view.obstnameTf.getText() + ": " + view.obstpreisTf.getText() + "€" );
	    	view.update();
	    }
	}
	
	// Schließ-Befehl
	class wListener implements WindowListener {
		@Override
		public void windowActivated(WindowEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void windowClosed(WindowEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void windowClosing(WindowEvent arg0) {
			modell.saveToFile(filepath);
		}

		@Override
		public void windowDeactivated(WindowEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void windowDeiconified(WindowEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void windowIconified(WindowEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void windowOpened(WindowEvent arg0) {
			modell.loadFromFile(filepath);
			view.update();
		} 
	}
	
}


Code:
package Aufgabe4;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.List;
import java.awt.event.ActionListener;
import java.awt.event.WindowListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class View{
	
	private JFrame frame;
	private List list;
	private Modell modell;
	protected JTextField obstnameTf;
	protected JTextField obstpreisTf;
	private JButton addButton;
	
	/** Konstruktor
	 * Registriert das Quellen-Modell und zeichnet die Oberfläche
	 * 
	 * @param modell Modell das als Datenquelle (nicht Ziel) verwendet wird.
	 */
	public View( Modell modell){
		this.modell = modell;
		//this.modell.registerObserver(this);
		this.draw();
	}
	
	
	/**
	 * Zeichnet die Oberfläche
	 */
	public void draw(){
		JFrame frame = new JFrame("Obstliste");
		JPanel pane = new JPanel();
		
		pane.setLayout( new BorderLayout() );
		pane.setPreferredSize(new java.awt.Dimension(500, 400));
		
		JPanel panel1 = new JPanel();
		panel1.setLayout( new GridLayout(1,1) );
			
			// Elemente auf Panel1 plazieren
			this.list = new List(20,false);
			panel1.add( list );
		panel1.add(list);
		
		pane.add(panel1, BorderLayout.SOUTH);
		
		JPanel panel2 = new JPanel();
		panel2.setLayout( new GridLayout(2,3) );
		
			// Elemente auf Panel 2 Plazieren
			panel2.add( new JLabel("Obstsorte:"));
			panel2.add( new JLabel("Preis:"));
			panel2.add( new JPanel() );
			obstnameTf = new JTextField();
			obstpreisTf = new JTextField();
			panel2.add( obstnameTf );
			panel2.add( obstpreisTf );
			this.addButton = new JButton("hinzufügen");
			panel2.add( addButton);				
		pane.add( panel2, BorderLayout.NORTH);
		this.update();
		frame.setContentPane(pane);
		frame.pack();
		frame.setVisible(true);
	}
	
	// Action Listener für den Hinzufügen-knopf
	void addAddListener(ActionListener al){
		this.addButton.addActionListener(al);
	}
	
	// Action Listener für das Schließen
	void addWindowListener( WindowListener w){
		// NullPointerException
		this.frame.addWindowListener(w);
	}
	
	/**
	 * Updated die Oberfläche
	 * 
	 * Holt sich vom Quellmodell eine neue
	 * Stringliste und ersetzt die Alte dadurch
	 */
	public void update(){
		ArrayList<String> list = new ArrayList<String>();
		list = modell.giveStringList();
		this.list.removeAll();
		for( int i=0; i<list.size(); i++){
			this.list.add( list.get(i) );
		}
	}
}


Button und Frame werden in view.draw() initialisiert.
 
frame hast du aber in der draw Methode als lokale Variable definiert und nicht dem Feld frame zugewiesen. Somit ist das Feld natürlich null.
 
X-)
Du hast Recht... Wald vor lauter Bäumen nicht gesehen!
hatte es am Anfang testweise lokal geschrieben und dann niemehr geändert!

Hab es nun umgeschrieben und getestet.
Allerdigns führt er meine beiden Methoden im WindowListener nicht aus....
Exceptions wirft er keine, aber der Code in den Methoden wird auch nicht ausgeführt.

Die 2 Methoden müssten doch aber beim öffnen/schließen des Fensters über den WindowListener aufgerufen werden...


Aber zunächsteinmal großes Danke für das hinschauen :)


€dit:
ist geklärt.. Fehler gefunden :)

Nochmal großes Danke an zeja!
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück