Auf Components zeichnen: Unterschied zwischen den Versionen
K |
K |
||
(11 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
− | Um Grafik | + | Siehe auch [[Malen in AWT und Swing]] |
+ | |||
+ | Um eine Grafik auf eine [[Component (Java)|Component]]- also auch z.B. einen Frame - zu zeichnen, muss grundsätzlich die Methode <code>public void paint (Graphics g)</code> überschrieben werden. Diese Methode wird vom Toolkit jedesmal auf dem GUI-Thread aufgerufen, wenn es Zeit ist zu malen. Bei {{JAPI|JComponent}} sollte übrigens die Methode paintComponent überschrieben werden. Vor allem bei JFrames ist es auch wichtig, die paint-Methode der Superklasse aufzurufen: | ||
<code>super.paint(g);</code> | <code>super.paint(g);</code> | ||
− | Bei [[ | + | Generell wird jedoch davon abgeraten, direkt auf einen JFrame zu malen. Statt dessen sollte man auf eine JComponent malen, die dem JFrame hinzugefügt wird. |
+ | Bei [[GUI]]-Komponenten ist zudem zu beachten, dass [[AWT]] und [[Swing]] nicht threadsicher sind, und diese aus anderen Threads nicht gezeichnet werden können, es sei denn, diese [[Thread|Threads]] wurden über die statischen Methoden aus {{JAPI|java.awt.EventQueue}}, {{JAPI|javax.swing.SwingUtilities}} oder mit einem [[SwingWorker]] mit dem [[GUI]]-[[Thread]] synchronisiert (dieser Thread wird auch Event Dispatch Thread genannt, oder kurz EDT). | ||
− | Ziemlich nutzlos ist es hingegen, über die Graphics aus Component#getGraphics zu zeichnen. | + | Ziemlich nutzlos ist es hingegen, über die {{JAPI|Graphics}} aus {{JAPI|Component#getGraphics()}} zu zeichnen. Beim nächsten ''repaint'', oder wenn der Frame zum Beispiel minimiert und wieder maximiert wird, wird das so Gezeichnete wieder verschwinden. Wann immer man also getGraphics()-Methode benutzt wird (und das wird fast nie der Fall sein), sollte man genau wissen, was man macht. |
− | |||
− | Die einzige Möglichkeit, während des Programmablaufes gezeichnete Dinge permanent auf die Component zu zeichnen, besteht somit darin, alles, was gezeichnet werden soll, in einer Datenstruktur ([[Array]], {{ | + | Die einzige Möglichkeit, während des Programmablaufes gezeichnete Dinge permanent auf die Component zu zeichnen, besteht somit darin, alles, was gezeichnet werden soll, in einer Datenstruktur ([[Array]], {{JAPI|ArrayList}}, usw.) zu speichern und das dann in der Methode paint()/paintComponent() auf das Graphics-Objekt zu übertragen, das dort als Parameter vom {{JAPI|Toolkit}} übergeben wird. Dies könnte zum Beispiel so aussehen: |
− | < | + | <syntaxhighlight lang="java"> |
− | + | import javax.swing.*; | |
import java.awt.*; | import java.awt.*; | ||
+ | import java.util.*; | ||
+ | import java.util.List; | ||
/** | /** | ||
− | * | + | * Diese Component muss zum JFrame hinzugefügt werden. |
*/ | */ | ||
− | public class JPaintComponent extends JComponent | + | public class JPaintComponent extends JComponent { |
− | + | ||
− | + | private List<PaintableObject> paints = new ArrayList<PaintableObject>(); | |
− | + | ||
− | + | public void paintObj(final PaintableObject po) { | |
− | + | paints.add(po); | |
− | + | } | |
− | + | ||
− | + | public List<PaintableObject> getObjects() { | |
− | + | return paints; | |
− | + | } | |
− | + | ||
− | + | public void removeObj(final PaintableObject po) { | |
− | + | paints.remove(po); | |
− | + | } | |
− | + | ||
− | + | public void clear() { | |
− | + | paints.clear(); | |
− | + | } | |
− | + | ||
− | + | @Override | |
− | + | protected void paintComponent(final Graphics g) { | |
− | + | for (PaintableObject po : paints) { | |
− | + | po.update(g); | |
− | + | } | |
+ | } | ||
+ | |||
+ | //nur zum Testen: | ||
+ | public static void main(final String[] args) { | ||
+ | Runnable gui = new Runnable() { | ||
+ | |||
+ | public void run() { | ||
+ | JFrame f = new JFrame("JPaintComponent"); | ||
+ | f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||
+ | f.setSize(220, 250); | ||
+ | f.setLocationRelativeTo(null); | ||
+ | JPaintComponent c = new JPaintComponent(); | ||
+ | c.paintObj(new PaintableLine(Color.RED, 10, 10, 200, 200)); | ||
+ | c.paintObj(new PaintableLine(Color.BLUE, 10, 200, 200, 10)); | ||
+ | f.add(c); | ||
+ | f.setVisible(true); | ||
+ | } | ||
+ | }; | ||
+ | EventQueue.invokeLater(gui); | ||
+ | } | ||
} | } | ||
+ | </syntaxhighlight> | ||
+ | <syntaxhighlight lang="java"> | ||
+ | import java.awt.*; | ||
+ | |||
/** | /** | ||
− | *Nur Klassen, die von dieser Klasse abgeleitet wurden, können gezeichnet werden. | + | * Nur Klassen, die von dieser Klasse abgeleitet wurden, können gezeichnet werden. |
*/ | */ | ||
− | abstract class PaintableObject | + | public abstract class PaintableObject { |
− | + | ||
− | + | private Color actual; | |
− | + | ||
− | + | public PaintableObject(final Color actual) { | |
− | + | this.actual = actual; | |
− | + | } | |
− | + | ||
− | + | public void setColor(final Color newColor) { | |
− | + | actual = newColor; | |
− | + | } | |
− | + | ||
− | + | void update(final Graphics g) { | |
− | + | g.setColor(actual); | |
− | + | paint(g); | |
− | + | } | |
− | + | ||
+ | public abstract void paint(final Graphics g); | ||
} | } | ||
+ | </syntaxhighlight> | ||
+ | <syntaxhighlight lang="java"> | ||
+ | import java.awt.*; | ||
+ | |||
/** | /** | ||
− | *Beispielimplementation einer Linie. | + | * Beispielimplementation einer Linie. |
*/ | */ | ||
− | class PaintableLine extends PaintableObject | + | public class PaintableLine extends PaintableObject { |
− | + | ||
− | + | private int x1; | |
− | + | private int y1; | |
− | + | private int x2; | |
− | + | private int y2; | |
− | + | ||
− | + | public PaintableLine(final Color c, final int x1, final int y1, final int x2, final int y2) { | |
− | + | super(c); | |
− | + | this.x1 = x1; | |
− | + | this.x2 = x2; | |
− | + | this.y1 = y1; | |
− | + | this.y2 = y2; | |
− | + | } | |
− | + | ||
− | }</ | + | public void paint(final Graphics g) { |
+ | g.drawLine(x1, y1, x2, y2); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
− | Um neu zeichnen zu lassen, kann die Methode repaint aufgerufen werden. | + | Um neu zeichnen zu lassen, kann die [[Methode]] repaint() aufgerufen werden. Es wird <u>nicht</u> empfohlen, dass Programme paint()/paintComponent() direkt aufrufen. Die Aufrufe dieser Methoden werden durch die VM automatisch erledigt, sobald dies nötig werden sollte. |
− | |||
− | |||
[[Kategorie:Tutorials (Java)]] | [[Kategorie:Tutorials (Java)]] | ||
[[Kategorie:Swing]] | [[Kategorie:Swing]] |
Aktuelle Version vom 28. März 2018, 07:59 Uhr
Siehe auch Malen in AWT und Swing
Um eine Grafik auf eine Component- also auch z.B. einen Frame - zu zeichnen, muss grundsätzlich die Methode public void paint (Graphics g)
überschrieben werden. Diese Methode wird vom Toolkit jedesmal auf dem GUI-Thread aufgerufen, wenn es Zeit ist zu malen. Bei JComponent
sollte übrigens die Methode paintComponent überschrieben werden. Vor allem bei JFrames ist es auch wichtig, die paint-Methode der Superklasse aufzurufen:
super.paint(g);
Generell wird jedoch davon abgeraten, direkt auf einen JFrame zu malen. Statt dessen sollte man auf eine JComponent malen, die dem JFrame hinzugefügt wird.
Bei GUI-Komponenten ist zudem zu beachten, dass AWT und Swing nicht threadsicher sind, und diese aus anderen Threads nicht gezeichnet werden können, es sei denn, diese Threads wurden über die statischen Methoden aus java.awt.EventQueue
, javax.swing.SwingUtilities
oder mit einem SwingWorker mit dem GUI-Thread synchronisiert (dieser Thread wird auch Event Dispatch Thread genannt, oder kurz EDT).
Ziemlich nutzlos ist es hingegen, über die Graphics
aus Component#getGraphics()
zu zeichnen. Beim nächsten repaint, oder wenn der Frame zum Beispiel minimiert und wieder maximiert wird, wird das so Gezeichnete wieder verschwinden. Wann immer man also getGraphics()-Methode benutzt wird (und das wird fast nie der Fall sein), sollte man genau wissen, was man macht.
Die einzige Möglichkeit, während des Programmablaufes gezeichnete Dinge permanent auf die Component zu zeichnen, besteht somit darin, alles, was gezeichnet werden soll, in einer Datenstruktur (Array, ArrayList
, usw.) zu speichern und das dann in der Methode paint()/paintComponent() auf das Graphics-Objekt zu übertragen, das dort als Parameter vom Toolkit
übergeben wird. Dies könnte zum Beispiel so aussehen:
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* Diese Component muss zum JFrame hinzugefügt werden.
*/
public class JPaintComponent extends JComponent {
private List<PaintableObject> paints = new ArrayList<PaintableObject>();
public void paintObj(final PaintableObject po) {
paints.add(po);
}
public List<PaintableObject> getObjects() {
return paints;
}
public void removeObj(final PaintableObject po) {
paints.remove(po);
}
public void clear() {
paints.clear();
}
@Override
protected void paintComponent(final Graphics g) {
for (PaintableObject po : paints) {
po.update(g);
}
}
//nur zum Testen:
public static void main(final String[] args) {
Runnable gui = new Runnable() {
public void run() {
JFrame f = new JFrame("JPaintComponent");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(220, 250);
f.setLocationRelativeTo(null);
JPaintComponent c = new JPaintComponent();
c.paintObj(new PaintableLine(Color.RED, 10, 10, 200, 200));
c.paintObj(new PaintableLine(Color.BLUE, 10, 200, 200, 10));
f.add(c);
f.setVisible(true);
}
};
EventQueue.invokeLater(gui);
}
}
import java.awt.*;
/**
* Nur Klassen, die von dieser Klasse abgeleitet wurden, können gezeichnet werden.
*/
public abstract class PaintableObject {
private Color actual;
public PaintableObject(final Color actual) {
this.actual = actual;
}
public void setColor(final Color newColor) {
actual = newColor;
}
void update(final Graphics g) {
g.setColor(actual);
paint(g);
}
public abstract void paint(final Graphics g);
}
import java.awt.*;
/**
* Beispielimplementation einer Linie.
*/
public class PaintableLine extends PaintableObject {
private int x1;
private int y1;
private int x2;
private int y2;
public PaintableLine(final Color c, final int x1, final int y1, final int x2, final int y2) {
super(c);
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
public void paint(final Graphics g) {
g.drawLine(x1, y1, x2, y2);
}
}
Um neu zeichnen zu lassen, kann die Methode repaint() aufgerufen werden. Es wird nicht empfohlen, dass Programme paint()/paintComponent() direkt aufrufen. Die Aufrufe dieser Methoden werden durch die VM automatisch erledigt, sobald dies nötig werden sollte.