auslesen eines JTextFields in eine andere Klasse auslagern

slope90

Grünschnabel
Hallo zusammen,

ich möchte gern meine View von meiner Logik besser trennen. Was ich versuche ist: die Eingabewerte erst in einer anderen Klassen zu lesen.

Beispiel:
Die Klasse View, in der der Benutzer eine PLZ oder Orsteinagbe eingibt und anschließen mit dem "Okey"-Button bestätigt.

PHP:
package view;

import java.awt.BorderLayout;
import java.awt.Container;

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

import controller.Controller;

public class View {
	
	private MyTextField textfield=new MyTextField();
	
	public View() {
		
		JFrame frame=new JFrame("Wetterstation");
		Container con=frame.getContentPane();
		
		con.setLayout(new BorderLayout());
		
		con.add(textfield, BorderLayout.NORTH);
		con.add(new MyButton(), BorderLayout.SOUTH);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(200, 200);
		frame.setVisible(true);
	
	}
	
	public static void main(String[] args) {
		new View();
	}
}

class MyTextField extends JTextField{{
setText("Ort oder Postleitzahl eingeben");
}}


class MyButton extends JButton{
	
	public MyButton() {
		//verweis der Behandlung auf die Klasse Controller
		addActionListener(new Controller());
		setText("okey");
	}
}

Der Okey-Button hat einen ActionListener, der auf die Klasse Controller (implementiert actionPerformed())) verweist. Mein Vorhaben wäre nun, in actionPerfored() die Eingabe des JTextFields mit getText() auszulesen.

PHP:
package controller;

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

import javax.swing.JButton;
import javax.swing.JTextField;

public class Controller implements ActionListener {

	@Override
	public void actionPerformed(ActionEvent e) {
		//hier möchte ich nun mit .getText() auf die Eingabe 
		//des JTextField zugreifen
		//....
		
		
		//weiterer Verweis auf das Modell
	}

}

Wie ist es Möglich, das Auslesen in eine andere Klasse (In meinem Fall Controller) auszulagern?
 
Hi

der Controller müsste eben wissen, wo die View (oder direkt das Textfeld) ist.
Also im Konstruktor übergeben und für spätere Verwendung
in einer Klassenvariable vom Controller speichern.

ABER: Damit erreichst du das Gegenteil von deinem Vorhaben.
Du machst den Controller abhängig davon, dass es da ein JTextField mit getText gibt.
Wenn du das jetzt für die Konsole umschreiben musst, was dann...?

Sowas gehört in die View.
Der ganze Listener kann in die View.
Und der Controller bekommt nur einen String.

Gruß
 
Deinen zweiten Vorschlag habe ich lösen können, danke
PHP:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class View implements ActionListener {
	
	private MyTextField textfield=new MyTextField();
	private JButton btn=new JButton("OK");
	
	private String inputtextfield="";
	
	public View() {
		
		JFrame frame=new JFrame("Wetterstation");
		Container con=frame.getContentPane();
		con.setLayout(new BorderLayout());
		
		con.add(textfield, BorderLayout.NORTH);
		con.add(btn, BorderLayout.SOUTH);
		btn.addActionListener(this);
		
		
//		con.add(new MyButton(inputtextfield), BorderLayout.SOUTH);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(200, 200);
		frame.setVisible(true);
	
	}

	public MyTextField getTextfield() {
		return textfield;
	}
	
	public static void main(String[] args) {
		new View();
	}

 	@Override
	public void actionPerformed(ActionEvent e) {
		inputtextfield = textfield.getText();
		System.out.println(inputtextfield);
//		erzeuge Modell-Objekt ...
	}

}

class MyTextField extends JTextField{{
setText("Ort oder Postleitzahl eingeben");
}}

Allerdings konnte ich mit dem ersten Tipp nicht sehr viel anfangen:
Mein Lösungsansatz:
PHP:
package view;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

import controller.Controller;

public class View{
	
	private MyTextField textfield=new MyTextField();
	private JButton btn=new JButton("OK");
	
	private String inputtextfield="";
	
	public View() {
		
		JFrame frame=new JFrame("Wetterstation");
		Container con=frame.getContentPane();
		con.setLayout(new BorderLayout());
		
		textfield.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				inputtextfield=textfield.getText();
				
			}
		});
		
		//Inputtext und View dem Controller übergeben
		btn.addActionListener(new Controller(inputtextfield, this));
		
		con.add(textfield, BorderLayout.NORTH);
		con.add(btn, BorderLayout.SOUTH);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(200, 200);
		frame.setVisible(true);
	
	}

	public MyTextField getTextfield() {
		return textfield;
	}
	
	public static void main(String[] args) {
		new View();
	}


}

class MyTextField extends JTextField{{
setText("Ort oder Postleitzahl eingeben");
}}

Und der Controller:
Code:
package controller;

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

import view.View;

public class Controller implements ActionListener {
	
	private String text;
	private View view;
	
	public Controller(String text, View view) {
		this.text=text;
		this.view=view;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		
		//Wie erhalte ich den WErt im Controller?
		String value=this.getText();
		System.out.println(value);
		System.out.println("test");
	}

	public String getText() {
		return text;
	}

	public View getView() {
		return view;
	}

}

Meine Idee ist gewesen alle Events, die von der View gefeuert werden an einer zentrallen Stelle zu sammeln(dem Controller). Je nachdem welcher Button auf der View geklickt wurde, wird in actionPerformed mit getActionCommand() die quelle ermittelt und anschließend in einigen if Anweisungen an das zugehörige Modell weitergeleitet. Dieses Konstrukt wurde uns mal in einer Vorlesung theoretisch näher gebracht.
Code:
//in der Klasse Controller
public void actionPerformed(ActionEvent e) {
		String cm=e.getActionCommand();
		if(cm=="WETTERHEUTE")
			new WeatherToday(plz);
			....
		if(cm=="WETTERMORGEN")
			new WeatherTomorrow(plz);
			...
		if(cm=="WETTERDREITAGE");
			...
}
Jetzt versuche ich es praktisch umzusezten und habe das Problem, dass ich nicht auf alle Klassenvariablen/Objektvariablen (aus der View; plz oder Ortsnamen) zugreifen kann, als wenn ich alle Varibalen in einer Klasse verwalte und auch direkt dort den Handler(actionPerformed()) aufrufe. Ich hätte gern für den Handler eine zentrale Klasse.

Ich kann mich auch Irren, was das Design angeht. Bin noch ein Neuling...
 
im Controller ... String plz = this.view.gettextfield.gettext() .... oder halt einfach da wo du plz stehn hast
Java:
 this.view.gettextfield.gettext()
du hast dem controller die view gegeben... also das objekt...
daher kannst du dann mit this.view alle methoden aus der view aufrufen, wie z.B. gettextfield, was dein textfeld liefert (DAS GLEICHE TEXTFELD******!!) da du dem controller eben diese view gegeben hast...
und dann halt gettext noch dahinter um das textfeld auszulesen ^^

Schau dir am besten mal das MVC (Model View Controller) Prinzip an

Beispiel:
Java:
import javax.swing.JButton;
import javax.swing.JFrame;


public class BspView extends JFrame{
	
	private BspController c;
	private JButton b1;
	
	public BspView()
	{
		c = new BspController(this);
		init();
	}
	
	public void init()
	{
		this.setBounds(5,5,200,200);
		b1 = new JButton("Hallo");
		b1.setBounds(5,5,100,100);
		b1.setActionCommand("b1");
		b1.addActionListener(c);
		this.getContentPane().add(b1);
		this.setVisible(true);
	}

        public JButton getbtn()
        {
                return this.b1;
         }
	
	
	public static void main(String[] args)
	{
		BspView v = new BspView();
	}

}

Java:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class BspController implements ActionListener{

	private BspView view;
	
	public BspController(BspView view)
	{
		this.view=view;
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getActionCommand().equals("b1"))
		{
				System.out.println(view.getbtn().getText());
		}
		
	}

}


wie sheel aber schon sagte wäre es anders sauberer, z.B. in der view
Java:
public String getPLZ()
{
    return this.textfield.gettext();
}

und im controller dann halt für die plz
Java:
this.view.getPLZ();


BTW: dein == wird nicht funktionieren. == vergleicht die objektadressen wie sie im speicher liegen.
also wenn du z.B. 2 objekte hast, und diese den komplett gleichen inhalt haben, sind sie für == nicht gleich, weils sie an unterschiedlichen stellen im speicher liegen (2 verschiedene objekte halt, auch wenn die informationen innerlich gleich sind).
du musst ObjektA.equals(ObjektB) machen ;)
als
Java:
if(cm.equals("WETTERHEUTE"))
Jedenfalls bei Klassen ...
Primitive Datentypen (int, short, boolean...) funktionieren auch mit == (sind glaub ich im speicher vordefiniert, so das z.B. int i = 1 einfach nur nen verweis auf 1 setzt, welche aber schon vorhanden ist... int j =1 würd den gleiche verweis setzen, weshalb i==j -> true)
 
Zuletzt bearbeitet:
I2oxxi, vielen dank für deine ausführliche Erklärung. Hat mir sehr geholfen

Ich habe zwei Lösungen:

Variante I (Controller und View in einer Klasse):

Code:
package view;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

import reader.WeatherValues;

public class View2 {

	private MyPanel picPanel;
	private JLabel beschreibung, gradMax;
	private JTextField textField;
	private JButton btn;

	public void init() {

		JFrame frame = new JFrame("Wetterstation");
		Container con = frame.getContentPane();
		con.setLayout(new BorderLayout());

		Container innercon = new Container();
		innercon.setLayout(new BorderLayout());

		gradMax = new JLabel();
		beschreibung = new JLabel();
		picPanel = new MyPanel();
		innercon.add(gradMax, BorderLayout.NORTH);
		innercon.add(picPanel, BorderLayout.CENTER);
		innercon.add(beschreibung, BorderLayout.SOUTH);

		textField = new JTextField();
		btn = new JButton("Suche");
				btn.addActionListener(new ActionListener() {
		
					@Override
					public void actionPerformed(ActionEvent arg0) {
						WeatherValues wv=new WeatherValues(textField.getText());
						
						gradMax.setText(String.valueOf(wv.getTodayValues().getGradmax()));
						beschreibung.setText(wv.getTodayValues().getBeschreibung());
						
						picPanel.removeAll();
						//zugriff auf das Model
						picPanel.add(new MyPanel(wv.getTodayValues().getImg2()));
						picPanel.validate();
		
					}
				});
				
		con.add(textField, BorderLayout.NORTH);
		con.add(innercon, BorderLayout.CENTER);
		con.add(btn, BorderLayout.SOUTH);

		frame.setVisible(true);
		frame.setSize(300, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	public View2() {
		init();
	}
	
	

	public static void main(String[] args) {
		new View2();
	}
}

Variante II (auslagern der Komponenten in den Controller):

View:
Code:
package view;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionListener;

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

public class View3 {
	
	
	private JButton btn;
	private JTextField textField;
	private JPanel picPanel;
	private JLabel beschreibung, gradMax;
	
	public View3() {
		init();
	}

	private void init() {
		
		JFrame frame=new JFrame("Wetterstation");
		Container con=frame.getContentPane();
		con.setLayout(new BorderLayout());
		
		
		Container innercon=new Container();
		innercon.setLayout(new BorderLayout());
		this.picPanel=new JPanel();
		this.beschreibung=new JLabel();
		beschreibung.setHorizontalTextPosition(JLabel.CENTER);
		
		this.gradMax=new JLabel();
		gradMax.setHorizontalTextPosition(JLabel.CENTER);
		innercon.add(gradMax, BorderLayout.NORTH);
		innercon.add(picPanel, BorderLayout.CENTER);
		innercon.add(beschreibung, BorderLayout.SOUTH);
		
		
		this.textField=new JTextField();
		this.btn=new JButton("OKEY");
		con.add(btn, BorderLayout.SOUTH);
		con.add(innercon, BorderLayout.CENTER);
		con.add(textField, BorderLayout.NORTH);
		
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		frame.setSize(250, 250);
				
	}
	
	public String getTextField() {
		return this.textField.getText();
	}
//registrieren eines Listeners für den Button
	public void setBtnActionListener(ActionListener l){
		this.btn.addActionListener(l);
	}
	

	public JLabel getGradMax() {
		return gradMax;
	}

	public JPanel getPicPanel() {
		return picPanel;
	}
	
	public void setBeschreibung(String value){
		this.beschreibung.setText(value);
	}
	
	public void setGradMax(String value){
		this.gradMax.setText(value);
	}
	
}

und der Controller:
Code:
package controller;

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

import reader.WeatherValues;
import view.MyPanel;
import view.View3;

public class Controller3 implements ActionListener {
	
	private View3 _view;
	//hier könnte auch eine andere View stehen
	private WeatherValues _model;

	public Controller3() {
		_view=new View3();
		_view.setBtnActionListener(this);
		//falls ein anderer Listener benötigt wird
		_view.setBtnActionListener(new AnotherActionListener());
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		
		String value=_view.getTextField();
		_model=new WeatherValues(value);
		

		_view.setBeschreibung(_model.getTodayValues().getBeschreibung());
		_view.setGradMax(String.valueOf(_model.getTodayValues().getGradmax()));
		
		_view.getPicPanel().removeAll();
		_view.getPicPanel().add(new MyPanel(_model.getTodayValues().getImg2()));
		_view.getPicPanel().validate();
		
	}
}
//falls ein weiterer ActionListener verwendet wird...
class AnotherActionListener implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent arg0) {
		System.out.println("AnotherActionListener");
		
	}


}

Ich denke das ist so richtig. Sollten dennoch Programmiersünden oder Verbesserungsvorschläge dabei sein, nur her damit...
 
Zurück