Java Swing - Wann paint und wann paintComponent()?
Hi, ich verstehe nicht ganz wann man die Methoden paint() und wann paintComponent() überschrieben kann?
Hier ein Beispiel:
public class KlickFrame extends JFrame {
private int clicks = 0;
private int x;
private int y;
public KlickFrame(){
super("KlickFrame");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(500, 100));
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
++clicks;
x = e.getX();
y = e.getY();
repaint();
}
});
pack();
setVisible(true);
}
public void paint(Graphics g){
//super.paintComponent(g);
g.drawString("AnzahlClicks: " + clicks, x, y);
}
public static void main(String[] args) {
new KlickFrame();
}
}
Warum wird hier die paint()-Methode überschrieben und nicht paintComponent()?
Gruß
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.
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);
Erstmal vielen Dank für die sehr ausführliche Antwort. Hat mir sehr geholfen !
Würde dies bedeuten, wenn ich jetzt eine Klasse von z.B JPanel erben lassen würde könnt ich eine paintComponent benutzen?