Start - Publikationen - Wissen - TOGAF - Impressum -

Grundlagen


Das Zeichnen grafischer Oberflächen ist aus Betriebssystemsicht eine aufwändige Angelegenheit. Aus diesem Grunde wird das Zeichnen bei modernen GUI Frameworks auf ein Minimum reduziert - es werden möglichst immer nur die Teile der GUI neu gezeichnet, die sich wahrscheinlich geändert haben. Dabei hilft, dass die grafischen Komponente der GUI in einer Hierarchie organisiert sind und diese Hierarchie entspricht normalerweise auch Sichtbarkeitsregeln. Bei AWT und Swing wird das Aktualisieren der Komponente über ein invalid-Flag und das Anmelden am RepaintManager abgewickelt und funktioniert in den meisten Fällen korrekt beim Aufruf von Standardmethoden wie add(Component).

AWT unterscheidet zwischen heavyweight components (HWC) und leightweight components (LWC). HWC nutzen für ihre Darstellung und Ereignisverarbeitung letztlich die Resourcen des Betriebssystems. LWC nutzen dafür eine der HWC in der sie eingebettet sind. Wenn man so will sind LWC grafische Komponenten, die innerhalb einer HWC emuliert werden. Mit dieser Strategie werden die Resourcen des Betriebssystems erheblich geschont. Das eigentliche Zeichnen der Komponente erfolgt innerhalb der Methode paint(Graphics g).

Das Zeichnen von HWC


Das Zeichnen an einer HWC kann vom System oder von der Anwendung ausgelöst werden. Bei der Auslösung durch das System (zum Beispiel wird eine Komponente sichtbar oder ihre Größe geändert) wird der Eventdispatching Thread bei der nächsten Gelegenheit das paint() dieser Komponente aufrufen. Bei der Auslösung durch die Anwendung wird durch Aufruf von repaint() bei der nächsten Gelegenheit das update() der Komponente gerufen. Die HWC wird anschließend ihre eigene und rekursiv das paint ihrer LWC aufrufen. Hier nochmal der Ablauf

  • ausgelöst durch das System
    1. AWT stellt fest, ob und was neu zu zeichnen ist
    2. Der Eventdispatching Thread wird bei Gelegenheit paint rufen
  • ausgelöst durch die Anwendung
    1. Die App stellt fest, ob und was neu zu zeichnen ist und ruft ein geeignetes repaint
    2. bei der nächsten Gelegenheit wird update gerufen, dieses mündet letztlich in einem Aufruf von paint
    3. In der Standardimplementierung (HWC) wird dann der Hintergrund gelöscht und paint gerufen
  • Damit ergeben sich klare Regeln für die Implementierung eigener Painting-Funktionalität für HWC:
    • Für eigene Painting-Implementierungen ist paint() geeignet zu überschreiben.
    • Für eine Beeinflussung des Ablaufs beim Neuzeichnen ist update() geeignet zu überschreiben.
    • Weder paint noch update() wird von der Anwendung direkt gerufen.

Das Zeichnen von LWC


LWC haben in jedem Fall ein HWC Ancestor, dessen Zeichenfläche sie belegen. Dieser Ancestor ist verantwortlich für den rekursiven Aufruf von paint aller seiner LWC Kinder. update löscht bei LWC standardmäßig nicht den Hintergrund (wegen Transparency etc.). Bei LWC kann man sich also auf den update-Hook nicht verlassen, ein Überschreiben von update bei LWC scheint nicht sinnvoll. Auch für LWC gilt: paint wird niemals direkt gerufen, App triggered kann man das Rufen der paint Methode aber (asynchron) auslösen, indem man eine der repaint Methoden ruft. Regeln für die Implementierung eigener Painting-Funktionalität für LWC:

  • paint ist auch für LWC der richtige Platz für eigene Implementierungen beim Zeichnen. Ein Aufruf von super.paint() muss dabei auf jeden Fall erfolgen.
  • Das update wird bei systemausgelösten Ereignissen vom HWC Ancestor nicht gerufen, es eignet sich damit nicht zum Überschreiben.
  • paint wird von der Anwendung nie direkt gerufen, sondern immer asynchron durch einen geeigneten repaint Aufruf.
  • repaint sollte dabei möglichst mit Argumenten gerufen werden.

Referenzen


JComponent JavaDoc
Forum 1
Forum 2
Weiterführend:
Painting in Swing and AWT

copyright © 2003-2021 | Dr. Christian Dürr | prozesse-und-systeme.de | all rights reserved