Auf Components zeichnen: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
K
 
(7 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
 
Siehe auch [[Malen in AWT und Swing]]
 
Siehe auch [[Malen in AWT und Swing]]
  
Um Grafik in 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 von dem GUI-Thread in regelmäßigen Abständen aufgerufen. Bei {{API|javax/swing/JComponent|JComponents}}sollte übrigens die Methode paintComponent überschrieben werden. Vor allem bei JFrames ist es auch wichtig, die paint-Methode der Superklasse aufzurufen:
+
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 [[Swing]]-Komponenten ist zudem zu beachten, dass [[Swing]] nicht threadsicher ist, und diese aus anderen Threads nicht gezeichnet werden können, es sei denn, diese [[Thread|Threads]] wurden über die statischen Methoden aus {{API|javax/swing/SwingUtilities|SwingUtilities}}oder mit einem [[SwingWorker]] mit dem [[Swing]]-[[Thread]] synchronisiert.
+
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. Bei dem nächsten repaint wird das so gezeichnete wieder überzeichnet.
+
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.
Der einzige Ausweg besteht darin, die Methode update leer zu implementieren, wodurch auf die Komponente aber überhaupt nicht mehr gezeichnet würde, wenn der Frame zum Beispiel minimiert und wieder maximiert worden wäre.
 
  
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]], {{API|java/util/ArrayList|ArrayList}}, {{API|java/util/Vector|Vector}}usw.) zu speichern. Dies könnte zum Beispiel so aussehen:
+
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:
  
<code=java>import javax.swing.*;
+
<syntaxhighlight lang="java">
import java.util.Vector;
+
import javax.swing.*;
 
import java.awt.*;
 
import java.awt.*;
 +
import java.util.*;
 +
import java.util.List;
  
 
/**
 
/**
  *Dieses Component muss hinzugefügt werden.
+
  * Diese Component muss zum JFrame hinzugefügt werden.
 
  */
 
  */
public class JPaintComponent extends JComponent
+
public class JPaintComponent extends JComponent {
{
+
 
private Vector<PaintableObject> paints = new Vector<PaintableObject>();
+
    private List<PaintableObject> paints = new ArrayList<PaintableObject>();
paintableObjects = new Vector();
+
 
public void paintObj (PaintableObject po)
+
    public void paintObj(final PaintableObject po) {
{
+
        paints.add(po);
paints.add (po);
+
    }
}
+
 
public Vector<PaintableObject> getObjects()
+
    public List<PaintableObject> getObjects() {
{
+
        return paints;
return paints;
+
    }
}
+
 
public void removeObj (PaintableObject po)
+
    public void removeObj(final PaintableObject po) {
{
+
        paints.remove(po);
paints.remove (po);
+
    }
}
+
 
public void removeAll()
+
    public void clear() {
{
+
        paints.clear();
paints.removeAllElements();
+
    }
}
+
 
public void paintComponent (Graphics g){
+
    @Override
for (PaintableObject po : paints){
+
    protected void paintComponent(final Graphics g) {
po.update (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;
+
    private Color actual;
public PaintableObject (Color actual)
+
 
{
+
    public PaintableObject(final Color actual) {
this.actual = actual;
+
        this.actual = actual;
}
+
    }
public void setColor (Color newColor)
+
 
{
+
    public void setColor(final Color newColor) {
actual = newColor;
+
        actual = newColor;
}
+
    }
void update (Graphics g)
+
 
{
+
    void update(final Graphics g) {
g.setColor(actual);
+
        g.setColor(actual);
paint (g);
+
        paint(g);
}
+
    }
public abstract void paint (Graphics 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 {
{
+
 
int x1, y1, x2, y2;
+
    private int x1;
public PaintableLine (Color c, int x1, int y1, int x2, int y2)
+
    private int y1;
{
+
    private int x2;
super (c);
+
    private int y2;
this.x1 = x1;
+
 
this.x2 = x2;
+
    public PaintableLine(final Color c, final int x1, final int y1, final int x2, final int y2) {
this.y1 = y1;
+
        super(c);
this.y2 = y2;
+
        this.x1 = x1;
}
+
        this.x2 = x2;
public void paint (Graphics g)
+
        this.y1 = y1;
{
+
        this.y2 = y2;
g.drawLine (x1, y1, x2, y2);
+
    }
}
+
 
}</code=java>
+
    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:Programmierung]]
 
[[Kategorie:Java]]
 
 
[[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.