Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

programmieren:java:grafikkontext [2015/02/05 15:06] (aktuell)
Zeile 1: Zeile 1:
 +====== Richtiger Umgang mit dem Grafikkontext ======
 +In Delphi ist es jederzeit erlaubt, sich von einer Komponente einen Grafikkontext (= TCanvas) zu besorgen und darauf zu zeichnen. Das ist insbesondere praktisch, wenn ein Maus-Event eine grafische Reaktion (z.B. Ziehen eines Rechtecks über eine Zeichenfläche) hervorruft. Die Zeichenaktion wird einfach innerhalb der Event-Bearbeitungsmethode platziert.
  
 +Auch unter Java kann man sich jederzeit mit JComponent.getGraphics() einen Grafikkontext zu jeder beliebigen Komponente besorgen. Meine ersten Versuche, grafische Reaktionen auf Mausereignisse zu implementieren,​ sahen daher etwas so aus:
 +
 +<code java>
 + public void mousePressed(MouseEvent arg0) {
 +                /*
 +                 * Don't do this:
 +                 */
 + Graphics2D g2d = (Graphics2D) getGraphics();​
 + g2d.setColor(Color.red);​
 + g2d.drawRect(arg0.getX(),​ arg0.getY(),​ 10, 10);
 + }
 +</​code>​
 +
 +Sie produzierten zwar manchmal das richtige Ergebnis, oft kam es aber auch zu sehr seltsamen Artefakten oder zu gar keiner Reaktion. Inzwischen ist mir klar:
 +** Zeichnen in Java ist nur innerhalb der PaintComponent(Graphics g) - Methode erlaubt! **
 +Es gibt eine [[http://​java.sun.com/​products/​jfc/​tsc/​articles/​painting/#​swing|ausführliche Dokumentation von Sun]] zum Zeichnen unter AWT/Swing, die recht gut erklärt, welche Methoden beim Neuzeichnen eines Bildschirmausschnitts der Reihe nach aufgerufen werden. Weshalb obiges unter Swing nicht funktioniert,​ wird leider nicht erklärt, aber zumindest findet man unter der Überschrift ** Lightweights & System-triggered Painting ** einen Hinweis darauf sowie die Anleitung, wie man es richtig macht:
 +  * Überschreiben der paintComponent()-Methode,​ allen Code zum Zeichnen dort unterbringen
 +  * Aufruf der Zeichenmethode mit repaint(new Rectangle(...)) oder paintImmediately(...). Dabei das kleinste Rechteck übergeben, das den zu zeichnenden Bereich umfasst. \\
 +
 +Ein Problem besteht weiterhin: Alles im übergebenen Rechteck muss ** komplett ** neugezeichnet werden. Im Fall eines vektororientierten Zeichenprogramms kann dies aufwändige Zeichenoperationen vieler hundert kleiner Objekte unter- und überhalb des veränderten Objekts bedeuten. Dies dauert i.a. viel zu lange.
 +
 +** Lösung: **
 +Zu Beginn der Mausziehaktion werden zwei Puffer (BufferedImage) angelegt. In den ersten wird der Hintergrund sowie alle Objekte ** unterhalb ** des gezogenen Objekts gezeichnet. Der zweite wird zunächst transparent gefüllt. Dann werden alle Objekte hineingezeichnet,​ die ** unterhalb ** des gezogenen Objekts liegen. Beim jedem MouseMove-Event wird dann der Reihe nach folgendes gemacht: \\
 +
 +  - Ersten Puffer in den Bildschirm kopieren
 +  - gezogenes Objekt zeichnen
 +  - zweiten Puffer in den Bildschirm kopieren
 + \\
 +Befinden sich viele Objekte auf dem Bildschirm, so kommt es durch das Füllen der beiden Puffer zu Beginn des "​Ziehvorgangs"​ zu einer kurzen Verzögerung,​ die sich anfühlt, als müsse man das gezogene Objekt von seinem bisherigen Platz "​wegreißen"​ und linear mit der Anzahl der Objekte auf dem sichtbaren Teil des Bildschirms skaliert. Danach läuft der ganze Ziehvorgang glatt durch (konstante Laufzeit).
Drucken/exportieren
QR-Code
QR-Code programmieren:java:grafikkontext (erstellt für aktuelle Seite)