2D-Grafik Kreis "von Hand" zeichnen -> jedesmal repaint()?

thousands

Mitglied
Hi,

ich versuche derzeit in Java ein Paint-ähnliches Zeichenprogramm umzusetzen und bin dabei auf ein Problem gestoßen, bei dem ich aktuell nicht weiter komme. Bei meiner google-Recherche hab ich dieses Forum hier entdeckt und mir gedacht ich schildere mein Problem hier einfach mal, in der Hoffnung, dass mir evtl. jmd. weiterhelfen oder den ein oder anderen nützlichen Tipp geben kann.

Zu meinem Problem: Nach erfolgreicher Umsetzung des "Freihand"-Zeichnens widme ich mich momentan dem Zeichnen von Shapes wie Kreisen und Rechtecken.
Mir ist dabei bekannt, wie das grundsätzliche Erstellen und Einfügen der jeweiligen Shape funktioniert, das Problem ist das "dynamische" Zeichnen der Shape während der Benutzereingabe (also das "ziehen" der Kreis- oder Rechteckgröße per Maus).

Ein Beispiel: Der Benutzer will einen Kreis zeichnen. Das soll analog zu (z.B.) MS Paint funktionieren, der Benutzer klickt also auf den gewünschten Ausgangspunkt für den Kreis und "zieht" (=dragged) dann die Maus, wobei sich die Kreisgröße entsprechend anpasst. Bei mouse-release soll der Kreis dann (endgültig) auf die Zeichenfläche übernommen werden.
Die Realisierung habe ich mir folgendermaßen vorgestellt: bei jedem MouseDragged-Event zeichne ich einen Kreis entsprechend den aktuellen Koordinaten; sollte dies nicht der erste Kreis sein, so wird der vorherige entfernt (sonst zeichne ich ja eine "3D-Röhre" aus vielen Kreisen).

Das Problem dabei ist nun folgendes: es gibt scheinbar keine Möglichkeit von meiner Zeichenfläche (Canvas oder JPanel, beides bereits versucht) das jeweils zuletzt (per .draw()) gezeichnete Objekt (hier: der obsolete Kreis der des alten MouseDragged-Events) wieder zu löschen. Das gezeichnete Objekt "verschmilzt" gewissermaßen mit der Zeichenfläche und lässt sich nachträglich nicht removen. Das bedeutet, dass ich bei jedem MouseDragged-Event ein repaint() ohne die Kreise aufrufen müsste, um den gezeichneten Kreis wieder zu "löschen", also den "ursprünglichen" Bildinhalt wiederherzustellen.
Dies würde zwar von der reinen Programmier-Logik her funktionieren (denk ich... :)), aber da MouseDragged ja mehrmals pro Sekunde aufgerufen wird dürfte dies (gerade wenn das bestehende Bild aufwendig ist) zu massiven Performanceproblemen führen.

Dafür muss es doch irgendwie eine wesentlich elegantere Variante geben, nur komm ich momentan scheinabar nicht von alleine drauf.

Schonmal vielen Dank für jegliche Hilfestellung!

Gruß,
thousands
 
Zuletzt bearbeitet:

thousands

Mitglied
Nachtrag: hier der Code der View eines kleines Testprogrammes zum Zeichnen von Kreisen. Den Controller poste ich der Übersichtlichkeit halber nicht mit, nur soviel: bei jedem MouseDragged-Event wird drawCircle aufgerufen, notFirst ist dabei beim ersten aufruf der aktuellen "Ziehbewegung" false, sonst true.

Anzumerken ist vielleicht noch, dass das ständige repaint() hier kein größeres Performanceproblem ist, da das zu "repaintente" Bild nicht sehr komplex ist. Sollte ich aber später z.B. die Funktion implementieren ein "richtiges" Bild (jpg, bmp etc..) zu importieren, dann dürften mehrere repaint()s pro Sekunde wohl zum Problem werden.

Java:
public class View extends JPanel
{
    private Point2D.Double pMerker;
    private Shape oval;
    private ArrayList<Shape> shapeList;

    public View()
    {
        this.setBackground(Color.WHITE);
        pMerker = new Point2D.Double();
        shapeList = new ArrayList<Shape>();
        this.setDoubleBuffered(true);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
		
        for (Shape elem : shapeList)
        {
            g2.draw(elem);
        }
    }


    public void drawCircle(Point p, boolean notFirst)
    {
        this.repaint();

        if (notFirst == false) // ist dies der erste Punkt der Ziehbewegung? ...
        {
            this.pMerker.setLocation(p.getX(), p.getY()); // ... dann speichern ...
        }
        else
        {
            shapeList.remove(shapeList.size() - 1); // ... sonst zuletzt gespeicherten Kreis löschen
        }

        oval = new Ellipse2D.Double(pMerker.getX(), pMerker.getY(), p.getX()-pMerker.getX(), p.getY()-pMerker.getY());
        shapeList.add(oval);
    }  
}

P.S.: sorry für den Doppelpost, ich wollte vermeiden, dass mein erster Post allzu riesig wird!
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Hmja, also so ganz hab' ich das Problem nicht verstanden. Ein paar Stichpunkte
- Ja, man kann das Objekt nicht löschen. (Mit PaintMode XOR könnte man tricksen, ist aber aufwändig und meistens unnötig)
- Richtig: Alles, was gezeichnet wird, muss von der paintComponent aus gezeichnet werden - und zwar IMMER ALLES. Das ist eben so. (Einschränkung: Man könnte bei "repaint" den Bereich angeben, der neu gezeichnet werden muss, und hoffen, dass der Zeichnende das berücksichtigt....)
- Ein Hintergrundbild zu malen ist (speziell (oder "nur") wenn es keine Transparenz enthält) schnell. U.u. ist es schneller und einfacher als ein "komplexes" Shape: Bei einem Shape muss wirklich gerechnet werden. Ein Bild malen bedeutet im besten Fall: Kopier' einen Block Daten von hier nach da. Das geht so weit, dass man bei "vielen" Shapes (also wenn shapeList "viele" Einträge hat) das erstmal in ein BufferedImage malen könnte, damit beim Zeichnen eines neuen Elements nur das Bild und nicht die vielen komplexen Shapes neu gezeichnet werden muss
 

thousands

Mitglied
Hmja, also so ganz hab' ich das Problem nicht verstanden. Ein paar Stichpunkte
- Ja, man kann das Objekt nicht löschen. (Mit PaintMode XOR könnte man tricksen, ist aber aufwändig und meistens unnötig)
- Richtig: Alles, was gezeichnet wird, muss von der paintComponent aus gezeichnet werden - und zwar IMMER ALLES. Das ist eben so. (Einschränkung: Man könnte bei "repaint" den Bereich angeben, der neu gezeichnet werden muss, und hoffen, dass der Zeichnende das berücksichtigt....)
- Ein Hintergrundbild zu malen ist (speziell (oder "nur") wenn es keine Transparenz enthält) schnell. U.u. ist es schneller und einfacher als ein "komplexes" Shape: Bei einem Shape muss wirklich gerechnet werden. Ein Bild malen bedeutet im besten Fall: Kopier' einen Block Daten von hier nach da. Das geht so weit, dass man bei "vielen" Shapes (also wenn shapeList "viele" Einträge hat) das erstmal in ein BufferedImage malen könnte, damit beim Zeichnen eines neuen Elements nur das Bild und nicht die vielen komplexen Shapes neu gezeichnet werden muss

Danke, gerade der dritte Punkt war sehr hilfreich. Ich hab nun einfach mal ein relativ großes bmp (gewissermaßen als "Stresstest") in meine Zeichenfläche eingefügt und das ständige repaint() macht tatsächlich überhaupt keine Performanceprobleme. Mein ursprüngliches Problem wäre damit denke ich gelöst!

Ich hätte aber noch eine weitere Frage: wo genau liegt der Unterschied zwischen der Verwendung von JPanel und Canvas als Zeichenfläche, was sind die jeweiligen Vor- und Nachteile?
Soweit ich gesehen hab hat Canvas keine paintComponent() Methode, ersatzweise kann man scheinbar sowohl paint(), als auch update() verwenden (funktioniert beides). Welche Methode ist die "richtige"?

Gruß,
thousands
 

Michael...

Top Contributor
Ich hätte aber noch eine weitere Frage: wo genau liegt der Unterschied zwischen der Verwendung von JPanel und Canvas als Zeichenfläche, was sind die jeweiligen Vor- und Nachteile?
Soweit ich gesehen hab hat Canvas keine paintComponent() Methode, ersatzweise kann man scheinbar sowohl paint(), als auch update() verwenden (funktioniert beides). Welche Methode ist die "richtige"?
Canvas ist AWT und JPanel/JComponent ist Swing. In den meisten Fällen sollte ein überschreiben der paint() [AWT] bzw. paintComponent() [Swing] ausreichen.
 

muckelzwerg

Bekanntes Mitglied
Versteh ich das richtig, dass Du nur zwei Layer hast? Das Bild und das aktuell zeichnende Objekt?
Dann besteht der Ablauf beim Zeichnen eigentlich nur aus dem Zeichnen von Hintergrund und Vordergrund.
Sobald der Kreis fertig ist, wird er in den Hintergrund übertragen.
In der paintComponent() wird dann bei jedem Durchlauf zuerst das Hintergrundbild (BufferedImage) gezeichnet und danach das aktuelle Zeichenobjekt (Kreis, etc.)
Sobald der Kreis fertig ist, zeichnest Du ihn dann fix auf das Hintergrundbild. In diesem Durchlauf ist der zweite Layer komplett leer.

Der zweite Layer ist kein echtes Bild, sondern nur eine Funktion, die eben das zeichnet, was gerade "getan" wird.
Wenn Du mit mehreren Ebenen arbeitest musst Du da ein wenig mit Masken umgehen.
Solange Du die gezeichneten Elemente nicht wieder "anklicken" willst, ist es doch gar kein Problem, wenn Du sie alle in das gleiche Bild zusammenpresst.
 

thousands

Mitglied
Versteh ich das richtig, dass Du nur zwei Layer hast? Das Bild und das aktuell zeichnende Objekt?
Dann besteht der Ablauf beim Zeichnen eigentlich nur aus dem Zeichnen von Hintergrund und Vordergrund.
Sobald der Kreis fertig ist, wird er in den Hintergrund übertragen.
In der paintComponent() wird dann bei jedem Durchlauf zuerst das Hintergrundbild (BufferedImage) gezeichnet und danach das aktuelle Zeichenobjekt (Kreis, etc.)
Sobald der Kreis fertig ist, zeichnest Du ihn dann fix auf das Hintergrundbild. In diesem Durchlauf ist der zweite Layer komplett leer.

Der zweite Layer ist kein echtes Bild, sondern nur eine Funktion, die eben das zeichnet, was gerade "getan" wird.
Wenn Du mit mehreren Ebenen arbeitest musst Du da ein wenig mit Masken umgehen.
Solange Du die gezeichneten Elemente nicht wieder "anklicken" willst, ist es doch gar kein Problem, wenn Du sie alle in das gleiche Bild zusammenpresst.

Alles klar, danke. Ich dachte nur ursprünglich, dass der repaint() des unteren Layers (also des bisherigen Bildes) bei jedem einzelnen MouseDragged-Event ziemliche Performanceprobleme bereiten würde. Ich hab mittlerweile durch testen heraus gefunden, dass dem nicht so ist, selbst dann nicht, wenn meine Zeichenfläche nicht doubleBuffered ist.

Das Problem hat sich damit denke ich erledigt, danke nochmal an alle für die Hilfe!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
W JavaFX Ich kann keinen Kreis richtig zeichnen AWT, Swing, JavaFX & SWT 8
L 2D-Grafik Linie von Kreis zu Kreis AWT, Swing, JavaFX & SWT 3
S Kreis vergrößern/verkleinern mit Buttons AWT, Swing, JavaFX & SWT 1
S GUI Kreis zeichnen AWT, Swing, JavaFX & SWT 13
M JavaFX Bild zur ImageView in einem Kreis anzeigen. AWT, Swing, JavaFX & SWT 4
L 2D-Grafik Dreieck in einem Kreis??? AWT, Swing, JavaFX & SWT 1
T Swing / Kreis zeichnen AWT, Swing, JavaFX & SWT 2
G Mehrere Strings um Kreis zeichnen und positionieren AWT, Swing, JavaFX & SWT 0
D Swing Manuellen Kreis zeichen AWT, Swing, JavaFX & SWT 22
T Kreis in Jlabel darstellen. AWT, Swing, JavaFX & SWT 13
J Grafik (Kreis) schneller bewegen? AWT, Swing, JavaFX & SWT 6
E Kreis-Mal-Programm AWT, Swing, JavaFX & SWT 7
S Kreis in Kreis AWT, Swing, JavaFX & SWT 5
P Elemente im Kreis aufstellen AWT, Swing, JavaFX & SWT 5
M 2D-Grafik "Unvollständiger" Kreis(kontur) AWT, Swing, JavaFX & SWT 8
T Einen Kreis anzeigen AWT, Swing, JavaFX & SWT 14
B 2D-Grafik Text in einem Kreis zentrieren AWT, Swing, JavaFX & SWT 3
Semox 2D-Grafik Radialer Verlauf in einem Kreis AWT, Swing, JavaFX & SWT 4
P Swing FocusTraversalPolicy dreht sich im Kreis AWT, Swing, JavaFX & SWT 2
J Java2D Kreis/Kurven Frage AWT, Swing, JavaFX & SWT 2
Semox Swing Kreis löschen durch Mausklick in der Nähe AWT, Swing, JavaFX & SWT 2
Dit_ Ein Kreis als Graphics2D oder als Ellipse2D Objekt AWT, Swing, JavaFX & SWT 19
K Wenn Mauszeiger in der Nähe vom Kreis, soll Kreis an eine andere Stelle springen AWT, Swing, JavaFX & SWT 8
Spin Hilfe - Erklärungsbedarf für Kreis AWT, Swing, JavaFX & SWT 5
H Punkte im Kreis AWT, Swing, JavaFX & SWT 3
G kreis malen -> welche funktion? AWT, Swing, JavaFX & SWT 3
G Farbe ändern bei Klick auf einen Kreis AWT, Swing, JavaFX & SWT 5
M Kreis mit gedrückter Maus bewegen AWT, Swing, JavaFX & SWT 20
U Farbe von Kreis AWT, Swing, JavaFX & SWT 3
G Kreis zeichnen und mit Maus ziehen AWT, Swing, JavaFX & SWT 3
S Kreis als JFrame AWT, Swing, JavaFX & SWT 9
TheJavaKid Kreis, Rechteck, Linie. verschieben AWT, Swing, JavaFX & SWT 5
T Kreis ActionListener AWT, Swing, JavaFX & SWT 5
J Gibt es brauchbare GUI-Builder, oder doch besser alles per Hand machen? AWT, Swing, JavaFX & SWT 6
G Grafische Oberflächen mit Java - GUI Builder oder von Hand? AWT, Swing, JavaFX & SWT 19
I GUI Builder? Framework? Per Hand? AWT, Swing, JavaFX & SWT 9
M Mandelbrot mit BigDecimal erstellen und in der UI zeichnen, funktionierte nicht. AWT, Swing, JavaFX & SWT 1
H JavaFX Canvas neu zeichnen anstoßen AWT, Swing, JavaFX & SWT 34
H Transparent zeichnen mit drawImage in paintComponent Methode AWT, Swing, JavaFX & SWT 3
N JavaFX Unicode zeichnen in javafx Label verwenden AWT, Swing, JavaFX & SWT 2
G 2D-Grafik Grafik in zwei verschiedenen Fenstern gleichzeitig zeichnen AWT, Swing, JavaFX & SWT 9
S Event Handling Neu zeichnen nur wenn Berechnung fertig ist AWT, Swing, JavaFX & SWT 4
CptK Funktionsgraphen effizient zeichnen und nur Teile von JPanel erneuern AWT, Swing, JavaFX & SWT 2
G Dreieck aus Pixeln zeichnen AWT, Swing, JavaFX & SWT 8
N Mit KeyListener ein rechteck zeichnen AWT, Swing, JavaFX & SWT 9
B 2D-Grafik paintcomponent Probleme beim zeichnen AWT, Swing, JavaFX & SWT 10
Z Swing Graph zeichnen lassen AWT, Swing, JavaFX & SWT 16
O Kann kei neues Panel zum zeichnen aufrufen... AWT, Swing, JavaFX & SWT 4
L Swing zeichnen AWT, Swing, JavaFX & SWT 14
S GUI Kreuz zeichnen und Position ausgeben AWT, Swing, JavaFX & SWT 3
S Swing Rechteck über JTable zeichnen (per MouseListener) AWT, Swing, JavaFX & SWT 1
L Swing Ein Rechteck in ein Grid Zeichnen AWT, Swing, JavaFX & SWT 5
L JavaFX Animation, erst zeichnen dann anzeigen AWT, Swing, JavaFX & SWT 4
K Mehrere Linien zeichnen AWT, Swing, JavaFX & SWT 8
E Transparent zeichnen AWT, Swing, JavaFX & SWT 2
S AWT Probleme beim Zeichnen AWT, Swing, JavaFX & SWT 3
T Tic Tac Toe - GUI Linien zeichnen AWT, Swing, JavaFX & SWT 14
C Applet Zeichnen über Button-Click AWT, Swing, JavaFX & SWT 13
Soloeco Graph zeichnen AWT, Swing, JavaFX & SWT 1
G Zeichnen Programm AWT, Swing, JavaFX & SWT 1
I Graph mit Swing zeichnen AWT, Swing, JavaFX & SWT 8
H Swing + Paint: Mehrere Objekte zeichnen lassen AWT, Swing, JavaFX & SWT 3
W Swing JPanel nur einmal nach mehreren Änderungen neu zeichnen AWT, Swing, JavaFX & SWT 1
D Quadrat, Rechteck zeichnen AWT, Swing, JavaFX & SWT 3
K Probleme beim zeichnen mit paintComponent() AWT, Swing, JavaFX & SWT 1
JG12111989 mehrere Polyline-Objekte zeichnen AWT, Swing, JavaFX & SWT 3
A Swing JRadioButton zeichnen nicht AWT, Swing, JavaFX & SWT 4
J Swing Vertikales Zeichnen eines Strings mit Java2D AWT, Swing, JavaFX & SWT 1
7 JavaFX Problem beim Zeichnen eines Dreiecks in einem GUI AWT, Swing, JavaFX & SWT 6
P 2D-Grafik Bogen(Arc) zwischen zwei Punkten zeichnen AWT, Swing, JavaFX & SWT 2
F Java Swing Rechteck in JPanel zeichnen AWT, Swing, JavaFX & SWT 7
KilledByCheese Swing 2D JLabel Array Maze zeichnen AWT, Swing, JavaFX & SWT 2
S Parallele Linien zeichnen AWT, Swing, JavaFX & SWT 5
J Linien auf JPanel zeichnen AWT, Swing, JavaFX & SWT 3
P AWT Canvas freihändig zeichnen AWT, Swing, JavaFX & SWT 1
llabusch Linien in JPanel zeichnen AWT, Swing, JavaFX & SWT 6
S passende PaintComponent ? Zeichnen in TextArea mit Scrollpane ? AWT, Swing, JavaFX & SWT 2
I Applet BlueJ Applet - Bild mit if-Schleife zeichnen lassen AWT, Swing, JavaFX & SWT 16
L JavaFX JavafX Timelime zeichnen und schön stylen? AWT, Swing, JavaFX & SWT 2
I JFrame neu zeichnen, nicht überzeichnen! AWT, Swing, JavaFX & SWT 2
I Spielsteine zeichnen und entfernen AWT, Swing, JavaFX & SWT 3
H JavaFX Freezes beim Zeichnen mit Canvas AWT, Swing, JavaFX & SWT 3
H Swing BufferedImage zeichnen AWT, Swing, JavaFX & SWT 1
M JFreeChart neu zeichnen sich Wenn Jtable sich ändert AWT, Swing, JavaFX & SWT 5
S 2D-Grafik MouseDragged Linien zeichnen AWT, Swing, JavaFX & SWT 4
M Zeichnen ohne vorherige Linien zu löschen AWT, Swing, JavaFX & SWT 2
T Problem beim Zeichnen von Rechteck AWT, Swing, JavaFX & SWT 3
I Text zur Linie zeichnen AWT, Swing, JavaFX & SWT 1
I Pfeil zeichnen am Ende einer Linie AWT, Swing, JavaFX & SWT 1
D 2D-Grafik Inhalt eines Graphics in anderes Graphics zeichnen.... AWT, Swing, JavaFX & SWT 3
F Zeichnen des Button AWT, Swing, JavaFX & SWT 4
B Zeichnen mit paintComponent? Oder anders? AWT, Swing, JavaFX & SWT 15
C Swing Aus verschiedenen Klassen zeichnen. AWT, Swing, JavaFX & SWT 2
C Swing BufferedImage zeichnen und JLabels setzen. AWT, Swing, JavaFX & SWT 17
M Kein Zeichnen der Figuren auf JPanel AWT, Swing, JavaFX & SWT 4
J JButton neu zeichnen lassen AWT, Swing, JavaFX & SWT 9
S Quadrat auf Frame zeichnen AWT, Swing, JavaFX & SWT 2
P Image oder Icon auf Tooltip zeichnen AWT, Swing, JavaFX & SWT 4
C Graphics Objekt in Zeitschleife zeichnen AWT, Swing, JavaFX & SWT 4
X Swing JPanel mehrere Ebenen zeichnen AWT, Swing, JavaFX & SWT 13

Ähnliche Java Themen

Neue Themen


Oben