# Richtig debuggen mit Eclipse



## Seropt (8. Sep 2014)

*Ratespiel - MAIN*


```
import javax.swing.JFrame;

public class Ratespiel {

	public static void main(String[] args) {

		JFrame jf = new Aussehen();
		jf.setVisible(true);
	}
}
```

*Aussehen*


```
import java.awt.Font;

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

public class Aussehen extends JFrame {

	private static final long serialVersionUID = 1L;

	private JLabel jlAufforderung, jlVersuche;
	private JTextField tfZahleneingabe;
	private JButton jbBewertung;

	public Aussehen() {

		setSize(400, 600);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLocationRelativeTo(null);
		setLayout(null);
		setTitle("Rate doch!");
		setResizable(false);

		jlAufforderung = new JLabel();
		jlAufforderung.setBounds(50, 50, 300, 20);
		add(jlAufforderung);

		jbBewertung = new JButton("Bewertung");
		jbBewertung.setBounds(140, 280, 120, 50);
		add(jbBewertung);

		jlVersuche = new JLabel(
				"<html><body><br>Du hast noch 5 Versuche!</body></html>");
		jlVersuche.setBounds(20, 165, 400, 50);
		add(jlVersuche);

		Font font = new Font("Arial", Font.BOLD, 15);
		jlAufforderung.setFont(font);

		jlVersuche.setFont(font);

		tfZahleneingabe = new JTextField();
		tfZahleneingabe.setBounds(160, 90, 60, 40);
		add(tfZahleneingabe);

		Font font2 = new Font("Arial", Font.BOLD, 20);
		tfZahleneingabe.setFont(font2);

		tfZahleneingabe.setHorizontalAlignment(JLabel.CENTER);
		jbBewertung.setHorizontalAlignment(JLabel.CENTER);
		jbBewertung.setFont(font);

		jbBewertung.addActionListener(new Bewertung(tfZahleneingabe,
				jlAufforderung, jbBewertung, jlVersuche));
		tfZahleneingabe.addCaretListener(new LeeresJTextField(tfZahleneingabe,
				jbBewertung));
		tfZahleneingabe.addKeyListener(new NurZahlenErlauben());

	}

}
```

*Bewertung*


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

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

public class Bewertung implements ActionListener {

	JLabel jlVersuche;
	JTextField tfZahleneingabe;
	JLabel jlAufforderung;
	JButton jbBewertung;
	private int i = 1, zufallszahl, maxZahl = 100, minZahl = 1, versuche = 5,
			input;

	public Bewertung(JTextField tfZahleneingabe, JLabel jlAufforderung,
			JButton jbBewertung, JLabel jlVersuche) {

		this.tfZahleneingabe = tfZahleneingabe;
		this.jlAufforderung = jlAufforderung;
		this.jbBewertung = jbBewertung;
		this.jlVersuche = jlVersuche;

		this.jlAufforderung.setText("Tippe auf eine Zahl zwischen " + minZahl
				+ " und " + maxZahl + ":");
		this.zufallszahl = (int) (Math.random() * 100 + 1);

		this.jbBewertung.setEnabled(false);

	}

	Breakpoint gesetzt   public void actionPerformed(ActionEvent anzahlMausklick) {

		Pruefprogramm doppelteZahl = new Pruefprogramm(tfZahleneingabe);
		doppelteZahl.doppelteZahlVerbieten();

		new EingabeBegrenzen(tfZahleneingabe, jlVersuche, jbBewertung);

		int zahleneingabe = konvertierung();

		if (zahleneingabe > 100 || zahleneingabe < 1) {

			return;
		}

		if (versuche != 1) {

			versuche();

			versuche--;

		} else {

			jlVersuche.setText("");
			JOptionPane.showMessageDialog(null,
					"Du hast verloren, die richtige Zahl wäre " + zufallszahl
							+ " gewesen.", "Verlierer",
					JOptionPane.ERROR_MESSAGE);
			return;
		}

		if (jbBewertung == anzahlMausklick.getSource() && (i++ == 5))
			jbBewertung.setEnabled(false);

		konvertierung();

		if (zufallszahl == input) {

			jlVersuche.setText("");
			JOptionPane.showMessageDialog(null,
					"Volltreffer, du hast gewonnen!", "Gewinner",
					JOptionPane.PLAIN_MESSAGE);
			jbBewertung.setEnabled(false);

		} else {

			System.out.println(zufallszahl);
			if (input < zufallszahl) {

				jlVersuche
						.setText("<html><body>Deine Zahl war zu niedrig!<br> "
								+ versuche());

			} else {

				jlVersuche.setText("<html><body>Deine Zahl war zu hoch!<br> "
						+ versuche());

			}

		}

	Ende der Methode actionPerformed   }

	public String versuche() {

		return "Du hast noch " + versuche + " Versuche!</body></html>";
	}

	public int konvertierung() {

		input = Integer.parseInt(tfZahleneingabe.getText());

		return input;
	}

}
```

*LeeresJTextField*


```
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

public class LeeresJTextField implements CaretListener {

	JButton jbBewertung;
	JTextField tfZahleneingabe;

	public LeeresJTextField(JTextField tfZahleneingabe, JButton jbBewertung) {

		this.jbBewertung = jbBewertung;
		this.tfZahleneingabe = tfZahleneingabe;

	}

	public void caretUpdate(CaretEvent e) {

		String s = tfZahleneingabe.getText();

		s = s.trim();

		if (s.isEmpty()) {

			jbBewertung.setEnabled(false);

		} else {

			jbBewertung.setEnabled(true);

		}

	}

}
```

*NurZahlenErlauben*


```
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;

public class NurZahlenErlauben extends KeyAdapter {

	public void keyTyped(KeyEvent e) {
		char vChar = e.getKeyChar();
		if (!(Character.isDigit(vChar) || (vChar == KeyEvent.VK_BACK_SPACE) || (vChar == KeyEvent.VK_DELETE))) {

			e.consume();

			JOptionPane.showMessageDialog(null,
					"Nur numerische Eingaben sind zul\u00e4ssig!",
					"Ung\u00fcltige Eingabe", JOptionPane.ERROR_MESSAGE);

		}
	}

}
```

*Pruefprogramm*


```
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class Pruefprogramm {

	private int zaehler[] = new int[5];
	JTextField tfZahleneingabe;
	private static int i = -1;
	private static int n = 0;

	public Pruefprogramm(JTextField tfZahleneingabe) {

		this.tfZahleneingabe = tfZahleneingabe;

	}

	public void doppelteZahlVerbieten() {

		i++;

		int zahlenPruefen = Integer.parseInt(tfZahleneingabe.getText());

		zaehler[i] = zahlenPruefen;

		while (n < i) {

			if (zaehler[n] == zaehler[i]) {

				JOptionPane
						.showMessageDialog(
								null,
								"Die Zahl wurde schon einmal verwendet. Bitte verwenden Sie eine andere Zahl.",
								"Doppelte Zahl", JOptionPane.ERROR_MESSAGE);
			}

			n++;
		}

	}

}
```

*EingabeBegrenzen*


```
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class EingabeBegrenzen {

	JTextField tfZahleneingabe;
	JLabel jlVersuche;
	JButton jbBewertung;

	public EingabeBegrenzen(JTextField tfZahleneingabe, JLabel jlVersuche,
			JButton jbBewertung) {

		this.tfZahleneingabe = tfZahleneingabe;
		this.jlVersuche = jlVersuche;
		this.jbBewertung = jbBewertung;

		int zahleneingabe = Integer.parseInt(tfZahleneingabe.getText());

		if (zahleneingabe > 100 || zahleneingabe < 1) {

			JOptionPane
					.showMessageDialog(null,
							"Nur Zahlen von 1 bis 100 sind zul\u00e4ssig!",
							"Eingabeaktion nicht gestattet!",
							JOptionPane.ERROR_MESSAGE);

			tfZahleneingabe.addFocusListener(new Markieren(tfZahleneingabe));

		}

	}

}
```

*Markieren*


```
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JTextField;

public class Markieren implements FocusListener {

	JTextField tfZahleneingabe;

	public Markieren(JTextField tfZahleneingabe) {

		this.tfZahleneingabe = tfZahleneingabe;

	}

	public void focusGained(FocusEvent e) {

		tfZahleneingabe.selectAll();

	}

	public void focusLost(FocusEvent e) {

	}

}
```


Hey Leute,
habe schon mal meinen Code "hineingeklatscht", um euch ein wenig zu schocken! Haha, nein, Spaß beiseite.

Mein Ratespielprogramm ist leider noch nicht so, wie ich es gerne möchte.
Da ich keinerlei Lösungen von euch erwarte, wie man bspw. mein Problem löst, wenn ich eine doppelte Eingabe in mein JTextField mache und dann eine Fehlermeldung kommt, sondern ich nur wissen möchte, wie ich selbst *mithilfe* des Debuggers drauf kommen kann.

Ich habe mir schon die grundlegenden Elemente des "Schmuckstücks" Debugger angeschaut und hätte eine Frage dazu, wie es möglich ist, spezifisch auf meinen Fall, weil ich einfach nicht drauf komme, so zu debuggen, dass ich das ganze Programm durchlaufe bzw. bei meinem oben genannten Fehler die Methode *doppelteZahlVerbieten()* in der Klasse *Pruefprogramm* zu wiederholen, um so die kontinuierlich ändernden Variablen zu beobachten.

*Wichtig!*

Sagen wir, um das ganze ein wenig abzukürzen, dass ich meinen Breakpoint in der implementierten Methode *public void actionPerformed(ActionEvent anzahlMausklick)* in die Klasse *Bewertung* gesetzt habe und von dort aus debugge.
Als erstes kommt das JFrame (GUI), in der ich im JTextField irgendeinen beliebigen Wert eingebe, drücke auf den JButton _Bewertung_ und dann gelangt die grüne Markierung zum ersten Code, in der der Konstruktor *Pruefprogramm* aufgerufen wird. Mit _Step Into_ könnte ich in den Konstruktor gelangen. Gut, lassen wir mal den Konstruktor außen vor und machen wir statt _Step Into_ gleich _Step Over_, um die Methode *doppelteZahlVerbieten()* in der Klasse *Bewertung* aufzurufen (Ich meine, mit "Step Over" gelange ich zur Methode "doppelteZahlVerbieten() und mit "Step Into" springe ich dann in diese hinein.).

Dann gehe ich die ganze Methode von *doppelteZahlVerbieten()* durch, bis ich wieder in das Stack Frame der *public void actionPerformed(ActionEvent anzahlMausklick)-Methode* komme.

Jetzt bin ich wieder in der Klasse *Bewertung* und tippe ständig _Step Over_, bis ich merke, dass ich bis ans Ende der geschlossenen Klammer von *public void actionPerformed(ActionEvent anzahlMausklick)* komme. Wenn ich dann auf _Step Over_ drücke, geht das Programm nicht mehr weiter (habe Step Filters und Select All gesetzt).

*Was ich gerne möchte:*

Wie schaffe ich es, dass ich z. B. die Breakpoints so setzen muss, dass das JFrame *javax.swing.JFrame;* + dazugehörige Tools, wie z. B. JButton, JLabel, ... immer wieder auftritt, ich in das JTextField meine 5 Versuche habe und die Zahl eingebe? Im normalen Java-Mode geht das. Aber ich möchte, dass das Programm auch im Debug-Mode so abläuft wie im Java-Mode, so dass ich die Veränderungen der jeweiligen Variablen nach jedem erneuten Methodenaufruf von *doppelteZahlVerbieten()* prüfen kann und so die Fehler beseitigen kann.

*Ziel*

Ziel ist es, dass, wenn ich z. B. im Ratespiel als erstes im JTextField die Zahl 5 eingebe, JButton klicke und dann nochmals 5 eintippe, dass dann eine Fehlermeldung kommt, dass ich die Zahl nicht doppelt eingeben darf. Dies ist mir schon gelungen. Aber wenn ich es jetzt folgendermaßen mache: Ich gebe 8 ein, dann klicke ich auf JButton, dann gebe ich 9 ein, dann klicke ich auf JButton und dann klicke ich wieder 8 ein, dann kommt leider keine Fehlermeldung, die besagt, dass es nicht erlaubt sei, doppelte Zahlen einzugeben.

Mein Consolencode geht schon in die richtige Richtung, aber das Integrieren in die GUI erweist sich ohne gute Debugging-Kenntnisse als äußerst schwierig, besonders, wenn man den exakten Programmablauf, wie dort der Compiler vorgeht, nicht weiß.

Hier mein Konsolenprogramm:


```
import java.util.Scanner;

public class Pruefprogramm {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);

		boolean error = true;

		int zaehler[] = new int[5];

		for (int i = 0; i < 5; i++) {

			error = true;

			zaehler[i] = scan.nextInt();

			for (int n = 0; n < i; n++) {

				if (error == true) {

					if (zaehler[n] == zaehler[i]) {

						System.out.println("Error");

						error = false;

					}
				}
			}

		}

	}

}
```

Ich hoffe, ihr versteht, was ich meine und könnt mir die Lösung bzgl. des Debuggens aufzeigen.
Das wäre sehr nett von euch!

Ich wünsche euch noch einen schönen Tag!

Liebe Grüße,
Seropt


----------



## lord239123 (8. Sep 2014)

Ich habe mir jetzt zwar nicht deinen ganzen Quellcode durchgelesen, aber was du allgemein machen kannst, um eine Fehlerquelle zu finden , ist mit System.out.println() immer wieder zu testen, ob der Code noch läuft bzw. richtig läuft und so die Fehlerquelle einzugrenzen.


----------



## AndiE (8. Sep 2014)

Ich glaube nicht, dass das so geht, wie du möchtest. Grundsätzlich unterliegt deine Anwendung auch dem MVC-Modell. So weit ich das erkennen kann, übernimmt Swing den View-Part. Was mir aber fehlt ist die Entkoppelung zu einem Control-Part. Im Prinzip gibt es ja keinen Model-Part bei dem Programm. Daher mein Vorschlag: Erstelle erst einmal eine Controler-Klasse für dein Spiel. Diese kannst du genau testen, auch auf Doppeleingaben. Ich meine, dass du die Ansichtsklasse auch um die Interfaces für die Listener erweitern(implements) und dann von dort aus deine Controler-Methoden aufrufen solltest.
Hintergrund ist einfach, dass du die Interfaces der Komponenten per debug besser kontrollieren kannst.


----------



## kaoZ (9. Sep 2014)

*assertions* (vgl. vor und nachbedingungen) wären hier auch stellenweise Sinnvoll würde ich nun einfach mal in den Raum werfen


----------

