Java Swing - Wann paint und wann paintComponent()?

1 Antwort

Jede Komponente - das heißt jede Swing-Klasse, die von JComponent erbt, besitzt zum einen eine paint sowie eine paintComponent-Methode.

Erstere macht etwas mehr, als nur die Komponente selbst zu zeichnen. Sie zeichnet ebenso den Rahmen um die Komponente und die Kindkomponenten. Da man im Regelfall mit Subklassen nur das Aussehen einer Komponente ändern möchte, macht es keinen Sinn, paint zu überschreiben.

Top-Level-Container (TLC) wie JFrame oder JDialog wiederum besitzen keine paintComponent-Methode und erben paint von der AWT-Klasse Window. Es handelt sich hierbei also um eine andere Methode, die zwar gleich heißt, aber eine etwas andere konkrete Implementation hat.

Aber auch hier gibt es einige Punkte zu beachten bzw. abzuwägen.

  • Wenn du die Methode überschreibst, solltest du immer auch die Basisimplementation erst aufrufen, da sie auch Eigenschaften wie die Deckkraft definiert, die wichtig für das Rendering der Kindelemente ist.
  • TLC verwenden anders als Komponenten kein Doublebuffering beim Zeichnen. Das kann also bei häufigem Neuzeichnen der Fläche zu einem unschönen Flackereffekt führen.
  • Wenn du bei deinem Beispielprogramm sehr nah unter der Kante der Fenstertitelleiste klickst, sollte dir etwas auffallen: Der Text wird auch noch unter der Titelleiste eingefügt. Wenn du in der paint-Methode zeichnest, musst du die Höhe der Titelleiste mit einbeziehen, da der Koordinatenursprung tatsächlich in der linken oberen Ecke des Fensters liegt und die Titelleiste dabei nicht berücksichtigt.

Besser wäre es also auch hier, das Überschreiben einer Komponente (z.B. einem JPanel) vorzuziehen, die man dann dem Frame anhängt. Gerade dein Beispiel stellt so einen Anwendungsfall dar.

Ein Vorteil, der sich dabei möglicherweise noch ableiten lässt, ist die Wiederverwendbarkeit einer überschriebenen Komponente, denn die kann auch noch in andere TLC (oder andere Komponenten) eingehängt werden.

Zudem ist es dann nicht notwendig, die eigene Klasse von der TLC-Klasse (in deinem Beispiel JFrame) abzuleiten. Es reicht aus, ein einfaches TLC-Objekt anzulegen und die eigene Klasse hat wieder die Freiheit, bei Bedarf von einer anderen Klasse zu erben.


fastfurry 
Beitragsersteller
 10.08.2022, 17:54

Erstmal vielen Dank für die sehr ausführliche Antwort. Hat mir sehr geholfen !

Top-Level-Container (TLC) wie JFrame oder JDialog wiederum besitzen keine paintComponent-Methode und erben paint von der AWT-Klasse Window. Es handelt sich hierbei also um eine andere Methode, die zwar gleich heißt, aber eine etwas andere konkrete Implementation hat.

Würde dies bedeuten, wenn ich jetzt eine Klasse von z.B JPanel erben lassen würde könnt ich eine paintComponent benutzen?

regex9  10.08.2022, 20:32
@fastfurry

Ja.

class MyPanel extends JPanel {
  @Override
  protected void paintComponent(Graphics graphics) {
    /* ... */
  }
}

// frame:
frame.add(new MyPanel());

Wenn du die Komponente nicht komplett neuzeichnen (also nur etwas ergänzen) möchtest, rufe in paintComponent erst noch die Implementation der Basisklasse auf.

super.paintComponent(graphics);