Swing Herangehensweise an "komplexeres" zu zeichnendes Gebilde

ThomasB

Mitglied
Hallo zusammen,

mittlerweile habe ich ein wenig hier im Forum gelesen und auch schon nach grundsätzlichem was das Zeichnen mit Swing angeht gegoogelt. Allerdings habe ich einige Sachen noch nicht richtig kapiert, bzw. bin mir nicht sicher, wie ich das umsetzen könnte.

Ich möchte auf einem JPanel zeichnen. Und zwar vorerst eine Kombination aus sich überlappenden Kreisen und Linien (bzw. Kreisbögen). Die Anzahl der Kreise und Linien ist zur Laufzeit unterschiedlich, mir aber direkt vor dem Zeichnen bekannt. Ich kenne also Anzahl, Größe und Position der einzelnen Objekte. Das Zeichnen wird, nachdem eine Datei korrekt ausgelesen wurde, per Button ausgelöst

Und nun wollte ich mal hier fragen, bevor ich stundenlang nicht zielführendes ausprobiere, wie Ihr das angehen würdet. Quellcode oder so will ich nicht, da arbeite ich mich selbst rein.

Meine erste Überlegung war nun, mir eine von JComponent (oder JPanel??) abgeleitete Klasse zu schreiben, die ArrayLists für meine darzustellenden Objekte enthält. Wenn ich dann den Zeichnen-Button drücke, übergebe ich die ArrayLists an meine JComponent, iteriere durch die Objekte, lese die Koordinaten aus und rufe die vorgesehenen Zeichenfunktionen auf.

Würde das funktionieren?

Ich bin für alle Vorschläge offen und lasse mir gern Verständnisprobleme aufzeigen.

Wenn ich mich unverständlich ausgedrückt habe und noch unklar ist, was ich machen möchte, würde ich mich über einen Hinweis diesbezüglich freuen.

Vielen Dank und beste Grüße,
ThomasB
 

Michael...

Top Contributor
Meine erste Überlegung war nun, mir eine von JComponent (oder JPanel??) abgeleitete Klasse zu schreiben, die ArrayLists für meine darzustellenden Objekte enthält. Wenn ich dann den Zeichnen-Button drücke, übergebe ich die ArrayLists an meine JComponent, iteriere durch die Objekte, lese die Koordinaten aus und rufe die vorgesehenen Zeichenfunktionen auf.

Würde das funktionieren?
Ja. Wenn die Komponente allerdings schon die List der Objekte enthält brauch mir ihr diese nicht noch einmal übergeben ;-)
 

c_sidi90

Top Contributor
Ich würde die Zeichenfläche als eigene Klasse schreiben und diese von JPanel erben lassen. In der Klasse befindet sich dann auch die Arraylist mit den zu zeichnenden Objekten. Diese Objekte zeichnest du in der
Java:
public void paint(Graphics g)
Methode des JPanels. Zu beachten ist jedoch, das du mit dem aufruf von
Java:
g.draw
angeben musst, was für Objekte du zeichnest. Z.B
Java:
g.drawRect
oder
Java:
g.drawOval
Daher wäre es sinnvoll vorher abzufragen, um was für ein Objekt es sich im aktuellen Listenindex handelt und dementsprechend die Zeichenoperation auszuwählen.
 

schalentier

Gesperrter Benutzer
Java:
public void paint(Graphics g)
Methode des JPanels.

NEIN! Immer [c]paintComponent(Graphics g)[/c] nehmen!

Ich wuerd das so machen:

Java:
public interface Renderable {
   void render( Graphics2D g );
}
public class Kreis implements Renderable {
   private int x;
   private int y;
   private int r;

   public void render( Graphics2D g ) {
      g.drawOval( x-r, y-r, 2*r, 2*r );
   }
}
public class MeinPanel extends JPanel {
   private List<Renderable> renderables = new ArrayList<Renderable>();

   public void paintComponent( Graphics g ) {
      for( Renderable r : renderables ) {
         r.render( (Graphics2D) g );
      }
   }
}
 

ThomasB

Mitglied
Hallo,

vielen Dank für die Antworten. Zumindest steht schon mal fest, dass ich das Gelesene richtig interpretiert habe und dass meine Arbeit dann zielführend ist.

@Michael...
Die Listen werden während der Laufzeit unabhängig von der Darstellung erzeugt (grobes MVC-Pattern). Ich weise den Membern der Zeichenkomponente diese dann einfach zu, dann sollten sie ja auf die gleichen Objekte zeigen, wenn ich mich nicht irre.

@c_sidi90
Ja, mir kam es auch besser vor direkt vom JPanel abzuleiten, als von JComponent, als dann ein JPanel mit der JComponent drauf zu erzeugen. Da kann ich gleich das JPanel ableiten.
Die ArrayLists enthalten nur gleich Objekte, so dass ich bis zum Ende der Liste immer die gleiche Zeichenfunktion mit den jeweiligen Objektparametern aufrufen kann, bis ich dann zur neuen ArrayList und somit zur neuen Zeichenfunktion komme.

@schalentier
Ja, dass man paintComponent() statt paint() überschreiben sollte, ist mir bei meiner Recherche auch schon untergekommen. Der Ansatz sieht sehr gut aus, aber das Interface kann ich mir sparen, da wie o.a. meine ArrayLists nur gleiche Objekte referenzieren.

Noch mal vielen Dank. Ich mache mir jetzt einen Kaffee und setze mich dann mal an die Implementierung. Ich lasse den Thread vorerst offen, falls noch Fragen auftauchen sollten.

Gruß,
ThomasB
 

c_sidi90

Top Contributor
Kommt drauf an, was er alles in dem Programm haben möchte, paintComponent ist daher nicht zwingend notwendig, wenn er eh nur 1 Fenster hat welches aus dem Panel und evtl einem Button besteht.
 

ThomasB

Mitglied
Momentan besteht die GUI aus einem JFrame mit Menü und Statuszeile, in dem TabbedPanes liegen. In einem der Tabs befindet sich die Zeichenfläche.

Ich habe die Klassen soweit fertig, aber jetzt muss ich mich erst mal mit NetBeans rumschlagen. NetBeans frisst zwar die Klasse und erzeugt sie, aber er behandelt sie wie JPanel. Sprich: Ich kann auf meine eigenen Member bzw. Getter und Setter nicht zugreifen. Die IDE meckert, dass es keine Methoden der Klasse JPanel sind, was ja auch korrekt ist :)
 

ThomasB

Mitglied
So...
es hat alles so weit geklappt, nachdem ich die eigene JPanel-Klasse in die Palette eingefügt habe.
Vielen Dank also!! :)

Jetzt habe ich noch mehr oder minder Kleinigkeiten.

Bei dem einen bin ich mir nicht sicher, ob das überhaupt was mit dem Zeichnen zu tun hat, evtl muss ich einen eigenen Thread dafür aufmachen (gegoogelt habe ich bereits)

Folgende zwei Dinge:
1.
Um leichter Positionen bestimmen zu können, habe ich in die paintComponent()-Methode ein translate mit eingebunden. Allerdings habe ich nach dem translate() zwei graue Striche auf dem Panel, die vom (neuen) Ursprung in positive x- und y-Richtung laufen. Es ist zwar kein Problem, meine Komponenten ohne die Translation zu zeichnen, aber wünschenswert wäre es doch, da wie gesagt die Berechnungen dann leichter werden.
Ich habe in den Properties nichts gefunden, was mir Aufschluß darüber gab, was es mit diesen Strichen auf sich hat. Habt ihr eine Idee?

2.
Ich habe die Systemausgaben auf ein JTextPane umgeleitet (System.out und .err). Allerdings werden diese nicht sofort angezeigt. Wenn ich mich in einer Funktion befinde, dann werden die Ausgaben in dem JTextPane erst angezeigt, wenn die Funktion returnt. Das ist aber leider denkbar ungünstig, denn wenn ich meine Daten einlese und die Komponenten berechne vergehen zum Teil mehrere Minuten und der User denkt, das Programm ist tot. Erst nachdem alle Berechnungen beendet sind, kommt die komplette Ausgabe auf einmal. Und Methoden wie .repaint(), .update(), .invalidate() ändern das auch nicht.
Hier eine Idee wo das herrührt und wie ich das umgehen kann? Ich würde dem User gerne Ausgaben auswerfen, damit er sieht, dass das Programm noch arbeitet und ein Fortschritt stattfindet.

Beste Grüße,
ThomasB
 

Michael...

Top Contributor
zu 1) dazu müsste man wohl den Code sehen
zu 2) langwierige Prozesse in eigene Threads auslagern, sonst blockieren diese den EDT und die GUI kann nicht aktualisiert werden.
 

ThomasB

Mitglied
zu 1) Hat sich erledigt. Ich bin irgendwann drauf gestossen, dass aus irgendeinem Grund die border-property mittransformiert wird. Aber es geht auch ohne Border :)

zu 2) Okay, dann werde ich erst mal alle Funktionen integrieren und die massigen funktionen in andere Threads auslagern.

Vielen Dank für die Hilfe!
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben