Swing repaint und Nullpointer

Status
Nicht offen für weitere Antworten.

Antoras

Top Contributor
Hallo,

ich hab zwei kleine Probleme mit meinem Programm:
Ich möchte einen Kreis auf ein JPanel zeichnen und diesen immer in Richtung des Mauszeigers verschieben sobald man mit der Maus klickt. Das geht auch, das Problem ist nur, dass mein JPanel nicht repaintet wird. Die Methoden dafür hab ich implementiert, trotzdem geht es nicht.

Weiter möchte ich den Kreis ein- bzw. ausblenden sobald ich den dafür vorgesehen JButton drücke. Wenn ich diese jedoch betätige bekomme ich immer einen NullPointer. Bei diesem Vorgang wird eigentlich nur der Wahrheitswert show auf false bzw. true gesetzt

Der ungefähr gleiche Code funktioniert wenn ich nur eine Klasse hab, die abstrakte und vererbte Klassen brauche ich aber, da ich später neben Kreisen gerne auch noch andere geometrische Formen erstellen möchte.

Könnte sich jemand den Code durchschauen und mir sagen was die Probleme verursacht? Ich kann in meinem Programm die Fehler einfach nicht erkennen.

Meine Main-Klasse:
Code:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class myGF extends JFrame {
	
	private GeometrieForm gf;
	
	private Kreis kreis;
	
	JPanel panel;

	/**
	 * Launch the application
	 * @param args
	 */
	public static void main(String args[]) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					myGF frame = new myGF();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame
	 */
	public myGF() {
		super();
		setBounds(100, 100, 500, 375);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		try {
			initGUI();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		//
	}
	
	private void initGUI() throws Exception {
		
		System.currentTimeMillis();
		setTitle("Geometrie Formen");
		panel = new JPanel(){
			public void paintComponent(Graphics g) {
				paintComponents(g);
				if (kreis == null) {
					kreis = new Kreis(100, 100, 100, 10);
				}
				kreis.malen(g);
			}
		};
		panel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent e) {
				bewegen(e);
			}
		});
		panel.setLayout(new FlowLayout());
		getContentPane().add(panel, BorderLayout.CENTER);

		final JButton button_zeigen = new JButton();
		button_zeigen.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent e) {
				gf.zeigen();
			}
		});
		button_zeigen.setText("zeigen");
		panel.add(button_zeigen);

		final JButton button_verstecken = new JButton();
		button_verstecken.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent e) {
				gf.verstecken();
			}
		});
		button_verstecken.setText("verstecken");
		panel.add(button_verstecken);
	}
	
	protected void bewegen(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();
		int bewegung = 1;
		panel.repaint(kreis.getXPos(), kreis.getYPos(), kreis.getDurchmesser() + bewegung,
				kreis.getDurchmesser() + bewegung);
		kreis.gehen(x, y);
		panel.repaint(kreis.getXPos(), kreis.getYPos(), kreis.getDurchmesser() + bewegung, 
				kreis.getDurchmesser() + bewegung);
	}
}

Die abstrakte Klasse:
Code:
import java.awt.Graphics;


public abstract class GeometrieForm {
	
	protected int xPos;
	protected int yPos;
	protected int schrittweite;
	protected boolean show = false;
	
	
	protected void zeigen() {
		show = true;
	}
	
	protected void verstecken() {
		show = false;
	}
	
	protected abstract void malen(Graphics g);	
	
	protected int getXPos() {
        return xPos;
    }
	
    protected int getYPos() {
        return yPos;
    }
	
}

Der Kreis:
Code:
import java.awt.Graphics;
import java.awt.event.MouseEvent;


public class Kreis extends GeometrieForm {
	
	private int durchmesser;
	
	public Kreis(final int x, final int y, final int d, final int s) {
		xPos = x;
        yPos = y;
		durchmesser = d;
		schrittweite = s;
		show = true;
	}

	@Override
	protected void malen(Graphics g) {
		if (show) {
			g.drawOval(xPos, yPos, durchmesser, durchmesser);
		}
	}
	
	public void gehen(final int x, final int y) {
		if (xPos < x) {
			xPos = xPos + schrittweite;
		}
        if (xPos > x) {
        	xPos = xPos - schrittweite;
        }
        if (yPos < y) {
        	yPos = yPos + schrittweite;
        }
        if (yPos > y) {
        	yPos = yPos - schrittweite;
        }
    }	
	
	public int getDurchmesser() {
        return durchmesser;
    }
}
 
> panel.repaint(kreis.getXPos(), kreis.getYPos(), kreis.getDurchmesser() + bewegung,
kreis.getDurchmesser() + bewegung);

hast du dir dieses Kommando ausgedacht? sowas gibts doch gar nicht,
zumal es in Kreis schon die Methode malen() gibt, die macht doch das gleiche, nie Code doppelt schreiben

der richtige Aufruf ist
repaint();

dazu musst du die paintComponent()-Methode überschreiben und darin malen() von Kreis aufrufen,
einmal reicht, warum zwei Kreise malen?

http://java.sun.com/docs/books/tutorial/uiswing/painting/index.html
insbesondere das Beispiel unter
http://java.sun.com/docs/books/tutorial/uiswing/painting/step2.html

-------

Methoden schreibt man üblicherweise in der Befehlsform,

nicht gebenDurchmesser() sondern gibDurchmesser() bzw. getDurchmesser(),
-> genauso male() + gehe() statt malen() + gehen()
 
SlaterB hat gesagt.:
> panel.repaint(kreis.getXPos(), kreis.getYPos(), kreis.getDurchmesser() + bewegung,
kreis.getDurchmesser() + bewegung);

hast du dir dieses Kommando ausgedacht? sowas gibts doch gar nicht,
zumal es in Kreis schon die Methode malen() gibt, die macht doch das gleiche, nie Code doppelt schreiben
Ne, die hab ich mir nicht selbst ausgedacht. Das steht so auf der Seite, auf die du mich verwiesen hast.

SlaterB hat gesagt.:
der richtige Aufruf ist
repaint();

dazu musst du die paintComponent()-Methode überschreiben und darin malen() von Kreis aufrufen,
einmal reicht, warum zwei Kreise malen?
Ich hab gedacht, ich brauch repaint unter Swing zweimal, da ich damit zum Einen die geänderte Fläche und zum Anderen die neu beschriebene Fläche neu zeichnen muss. Weiß auch nicht genau, das hat mir irgendjemand mal gesagt.

SlaterB hat gesagt.:
Da steht eigentlich das Gleiche wie ich schon haben. In der Methode paintComponent() übergebe ich die Zahlenwerte an malen(), damit zeichne ich dann das Objekt Kreis und mit bewegen() erstell ich es ja nicht neu, sondern repainte es nur. Oder ist das das Selbe?

SlaterB hat gesagt.:
Methoden schreibt man üblicherweise in der Befehlsform,

nicht gebenDurchmesser() sondern gibDurchmesser() bzw. getDurchmesser(),
-> genauso male() + gehe() statt malen() + gehen()
Aha. Ist gut. Hab ich geändert.
Hm, da frag ich mich grad ob es vllt nicht besser wäre nur auf Englisch zu programmieren. Dann gäbs das Problem nicht...
 
> Da steht eigentlich das Gleiche wie ich schon haben. In der Methode paintComponent() übergebe ich die Zahlenwerte an malen(), damit zeichne ich dann das Objekt Kreis und mit bewegen() erstell ich es ja nicht neu, sondern repainte es nur. Oder ist das das Selbe?


hmm stimmt, da habe ich recht ungenau geschaut,
der Anfang der Methode sollte aber unbedingt wie im Link lauten:

public void paintComponent(Graphics g) {
super.paintComponent(g);

nicht

public void paintComponent(Graphics g) {
paintComponents(g);


---------

repaint();
schreibst aber dennoch weiterhin nur als
repaint();
nicht als
repaint(kreis.getXPos(), kreis.getYPos(), kreis.getDurchmesser() + bewegung,
kreis.getDurchmesser() + bewegung);
😉

-----

ansonsten: was genau funktioniert noch nicht?
 
SlaterB hat gesagt.:
der Anfang der Methode sollte aber unbedingt wie im Link lauten:

public void paintComponent(Graphics g) {
super.paintComponent(g);

nicht

public void paintComponent(Graphics g) {
paintComponents(g);
Ah, ja, das war der Fehler. Jetzt wird richtig repaintet.

SlaterB hat gesagt.:
repaint();
schreibst aber dennoch weiterhin nur als
repaint();
nicht als
repaint(kreis.getXPos(), kreis.getYPos(), kreis.getDurchmesser() + bewegung,
kreis.getDurchmesser() + bewegung);
Stimmt, das brauch ich echt nicht.


Ok. Dann wäre das schon mal gelöst.
Jetzt gibt es noch das Problem mit dem Nullpointer, der kommt, sobald ich auf einen der beiden Buttons drücke.

Nochmal der upgedatete Code:
Code:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class myGF extends JFrame {
	
	private GeometryForm gf;
	
	private Circle circle;
	
	JPanel panel;

	/**
	 * Launch the application
	 * @param args
	 */
	public static void main(String args[]) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					myGF frame = new myGF();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame
	 */
	public myGF() {
		super();
		setBounds(100, 100, 500, 375);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		try {
			initGUI();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		//
	}
	
	private void initGUI() throws Exception {
		
		System.currentTimeMillis();
		setTitle("Geometry Forms");
		panel = new JPanel(){
			public void paintComponent(Graphics g) {
				super.paintComponent(g);
				if (circle == null) {
					circle = new Circle(100, 100, 100, 10);
				}
				circle.paint(g);
			}
		};
		panel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent e) {
				move(e);
			}
		});
		panel.setLayout(new FlowLayout());
		getContentPane().add(panel, BorderLayout.CENTER);

		final JButton button_display = new JButton();
		button_display.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent e) {
				gf.display();
			}
		});
		button_display.setText("display");
		panel.add(button_display);

		final JButton button_hide = new JButton();
		button_hide.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent e) {
				gf.hide();
			}
		});
		button_hide.setText("hide");
		panel.add(button_hide);
	}
	
	protected void move(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();
		circle.go(x, y);
		panel.repaint();
	}
}
Code:
import java.awt.Graphics;


public abstract class GeometryForm {
	
	protected int xPos;
	protected int yPos;
	protected int stepsize;
	protected boolean show = false;
	
	
	protected void display() {
		show = true;
	}
	
	protected void hide() {
		show = false;
	}
	
	protected abstract void paint(Graphics g);
}
Code:
import java.awt.Graphics;
import java.awt.event.MouseEvent;


public class Circle extends GeometryForm {
	
	private int average;
	
	public Circle(final int x, final int y, final int a, final int s) {
		xPos = x;
        yPos = y;
		average = a;
		stepsize = s;
		show = true;
	}

	@Override
	protected void paint(Graphics g) {
		if (show) {
			g.drawOval(xPos, yPos, average, average);
		}
	}
	
	public void go(final int x, final int y) {
		if (xPos < x) {
			xPos = xPos + stepsize;
		}
        if (xPos > x) {
        	xPos = xPos - stepsize;
        }
        if (yPos < y) {
        	yPos = yPos + stepsize;
        }
        if (yPos > y) {
        	yPos = yPos - stepsize;
        }
    }
}
 
gf ist null, auf null kannst du nichts aufrufen,

gf wird nie gesetzt, wenn das der Kreis sein soll dann musst du irgendwann mal
gf = kreis; schreiben
 
Aha. Eigentlich ganz logisch...irgendiwe hab ich es mit den Nullpointern noch nicht so. Naja, das wird schon noch.

Danke dir, hast mir sehr weiter geholfen. 😀

Jetzt kann ich ja beruhigt mein Programm so umcoden, dass ich verschiedene Formen darstellen kann. Wenn es da dann wieder Probleme gibt melde ich mich nochmal 😉
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben