Überlagerung von Kreisen

Hallo,

ich habe ein Problem mit Überlagerungen von JPanels die einen Kreis darstellen. Und zwar geht es darum das ich bei jedem klick mit der Maus an der Stelle einen neuen Kreis zeichne, die alten Kreise bleiben bestehen. Wenn ich nun einen neuen Kreis über einen anderen lege, dann bekomme ich an den Seiten Ecken. Hört sich jetzt bescheuert an, ein Kreis mit Ecken. Es ist ja nicht das der Kreis die Ecken bekommt sondern das die Ecken des Panels sichtbar werden. Ich habe nun schon versucht das Panel über die Methode “setOpaque” transparent zu machen, dann habe ich versucht die Ecken abzurunden doch auch diese Variante hat nichts gebracht.

Vielleicht hat jemand von Euch eine Ahnung wie man das Problem am besten löst.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MovingCircle2 implements MouseListener
{
  static int x;
  static int y;
  private int i,j;

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

  MovingCircle2()
  {
    JFrame wrapper = new JFrame("MouseMotion2");
    wrapper.setLocation(250,250);
    wrapper.setSize(400,300);
    wrapper.setResizable(true);
    wrapper.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    x = (int) (wrapper.getWidth() / 2) - 40;
    y = (int) (wrapper.getHeight() / 2) - 40;

    Container content = wrapper.getContentPane();
    OvalPanel paintOval = new OvalPanel();
    paintOval.setOpaque(true);
    paintOval.setFocusable(true);
    paintOval.addMouseListener(this);
    content.add(paintOval);
    content.setBackground(new Color(240,227,255));

    wrapper.setVisible(true);
  }

  public void mouseClicked(MouseEvent evt)
  {
    int[][] points = new int[50][2];

    OvalPanel newOval = (OvalPanel)evt.getSource();

    points**[0] = evt.getX();
    points**[1] = evt.getY();
    i++;
    
    for( ; j < i; j++)
    {
        x = points[j][0];
        y = points[j][1];
        newOval.repaint(x, y, 40, 40);
    }
  }
  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
  public void mousePressed(MouseEvent e){}
  public void mouseReleased(MouseEvent e){}
  
  public static int getXPoint() { return x;}
  public static int getYPoint() { return y;}
}

class OvalPanel extends JPanel
  {
    public void paintComponent(Graphics oval)
    {
      super.paintComponent(oval);
      oval.setColor(new Color(255,0,0));
      oval.fillOval(MovingCircle2.getXPoint(),MovingCircle2.getYPoint(),40,40);
    }
  }

Warum zeichnest du deine Kreise nicht in ein einziges JPanel?
Um deine Kreise zu speichern, legst du dir eine passende Collection an und durchläufst diese beim Zeichnen.
Dann gibts garantiert auch keine Ecken, durch übereinander liegende JPanels mehr. :wink:

Warum ich kein einzelnes Panel benutze ist leicht zu klären, es entspricht nicht der Aufgabenstellung. Gemäß der Aufgabenstellung soll jeder Kreis in seinem eigenem Panel liegen.
Das verwenden von Collection ist ebenfalls nicht erwünscht.

mal setOpaque(false); versucht?

Sowohl “true” als auch “false”. Wobei “true” der letztere und eher ein Verzweiflungsversuch war.

Das Problem ist:

Du zeichnest nur ein einziges mal einen Kreis!

mit newOval.repaint(x, y, 40, 40); lässt du dann wiederum nur den neuen Kreis zeichnen, die alten werden ja gar nicht gezeichnet.

Vielleicht so?


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MovingCircle2 extends MouseAdapter {

	Point points[] = new Point[50];
	int usedPoints = 0;;

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new MovingCircle2();
			}
		});
	}

	MovingCircle2() {
		JFrame wrapper = new JFrame("MouseMotion2");
		wrapper.setLocation(250, 250);
		wrapper.setSize(400, 300);
		wrapper.setResizable(true);
		wrapper.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		Container content = wrapper.getContentPane();
		OvalPanel paintOval = new OvalPanel();
		paintOval.setOpaque(true);
		paintOval.setFocusable(true);
		paintOval.addMouseListener(this);
		content.add(paintOval);
		content.setBackground(new Color(240, 227, 255));

		wrapper.setVisible(true);
	}

	public void mousePressed(MouseEvent evt) {
		if (usedPoints < points.length) {
			usedPoints++;
			points[usedPoints-1] = evt.getPoint();
			((JPanel) evt.getSource()).repaint(points[usedPoints-1].x - 20,
					points[usedPoints-1].y - 20, 40, 40);
			
		}
	}

	class OvalPanel extends JPanel {
		private static final long serialVersionUID = 1L;

		public void paintComponent(Graphics oval) {
			super.paintComponent(oval);
			oval.setColor(new Color(255, 0, 0));
			for (int i = 0; i < usedPoints; i++) {
				Point p = points**;
				oval.fillOval(p.x - 20, p.y - 20, 40, 40);
			}

		}
	}

}

Beachte vorallem die Schleife in der paintComponent.

Warum ich kein einzelnes Panel benutze ist leicht zu klären, es entspricht nicht der Aufgabenstellung

Du möchtest nicht alles in ein Panel zeichnen? Dann solltest du vielleicht mal damit anfangen mehrere Panels zu erstellen ?!

Vielen Dank für die Hilfe.

@Sunshine
Dein Code ist, meiner Ansicht nach, deutlich einfacher und eleganter.
Aber auf „MouseAdapter“ und „Point“ habe ich verzichtet weil ich nicht wusste das es diese gibt. :smiley:

Nach dem Ändern der for-Schleife in der Methode MouseClicked und dem Hinzufügen der Schleife in der Klasse OvalPanel funktioniert es. Also nochmals danke.

@all
Kann mir jemand „.invokeLater()“ und „serialVersionUID“ näherbringen?

Dir ist aber bewußt, dass die Lösung nicht der von Dir wiedergegebenen Aufgabenstellung entspricht?

zu invokeLater http://openbook.galileodesign.de/javainsel5/javainsel15_032.htm#Rxx747java15032040005581F03B1BC

zu serialversionuid: Ist im Zusammenhang mit der Serialisierung und Deserialisierung von Objekten relevant und dient zur eindeutigen Bestimmung einer Version eine Klasse. Eine ausführliche Erläuterung hierzu http://www.javapractices.com/topic/TopicAction.do?Id=45

EDIT: Dein ursprüngliches Problem mit den „Ecken“ liegt darin, dass Du immer nur einen Kreis auf dem Panel dargestellt und nur das den Kreis umschließende Rechteck aktualisieren hast lassen. Da der restliche Teil des Panels nicht aktualisiert wurde, sah es so aus, als wären noch mehrere Kreis auf dem Panel.

Aufgefallen ist mir das schon, ich weiß nur nicht so recht wie ich da am besten vorgehe und ansetze.

Ich hatte mir überlegt das ich immer wieder bei einem neuen Kreis ein neues Objekt der Klasse “OvalPanel” erzeuge, da die Klasse ja von JPanel abgeleitet ist. Ich müsste dann doch jeden Kreis auf einem neuem Panel haben, bin mir dessen aber nicht sicher.

Nur um das klar zu stellen, ich halte es für unnötig, “verschwenderisch” und falsch immer wieder neue Panels zu erzeugen. Wollte nur noch mal auf die Aufgabenstellung hinweisen. Die Lösung alles auf ein Panel zu zeichnen ist die bessere. Aktuell problematisch ist die verwendung eines Arrays fester Größe, besser wäre eine List die dynamisch erweitert werden kann. Wenn die Kreise nur gezeichnet und nie wieder manipuliert werden sollen wäre das Zeichnen auf ein Image ebenfalls eine recht effiziente Möglichkeit.

Wenn das ganze mit mehreren Panels umgesetzt werden soll, benötigst Du ein transparentes Panel in der Größe des Kreises, das diesen Kreis darstellt. Bei Mausklick erzeugt man einen neue Instanz dieses Panels und platziert es an der Position des Mausklicks (der Container muss dazu ein “Null” Layout besitzen).

Ich kann deine Aussage verstehen und so langsam halte ich die Aufgabenstellung auch für ungeeignet.
Ein Array mit fixer Größe halte ich allerdings, für dieses Beispiel, legitim. Denn, das Programm hat keine höhere Bedeutung in einem Projekt, es soll nur zur Vertiefung des bisherigen Stoffes dienen.

Der oder die Kreise sollen im nachhinein durch das drücken der Leertaste wieder gelöscht und durch betätigen der ‘+’, ‘-’ Taste in ihrer Größe verändert werden.

Abweichend zur Aufgabenstellung werde ich jetzt nur noch die Funktion der Tasten implementieren und meinen Dozenten davon überzeugen dass das Zeichnen der Kreise auf einzelne Panels ungeeignet ist. Auch die Verwendung von Null-Layout finde ich nicht besonders gut.