DoubleBuffering nutzung?

Status
Nicht offen für weitere Antworten.
W

wayne0101

Gast
hallo zusammen,

ich möchte eine kleine animation schreiben. da ich schon länger mit java programmiere und weiß, daß es doublebuffering gibt und das die grafik sonst flackert, habe ich mich durch diverse tutorials gehangelt, welche mir alle das selbst sagten. ich soll die update(Graphics) methode meiner Component überschreiben und darin ein offscreen-image anlegen. das sieht bei mir nun (vereinfacht) so aus:
Code:
class MyAnimation extends Panel implements Runnable {
    private Image dbImage;
    private Graphics dbGraphics;
    private boolean isInterrupted;

    public MyAnimation(){
        super();
        isInterrupted = false;
    }

    public void startAnimation(){
        isInterrupted = false;
        Thread thread = new Thread(this);
        thread.start();
    }

    public void stopAnimation(){
        isInterrupted = true;
    }

    public void run(){
        while( !isInterrupted ){
            repaint();
            waitFor(40);
        }
    }

    private synchronized void waitFor(long ms){
        try {
            wait(ms);
        }
        catch( Exception e ){        
        }
    }

    public void update(Graphics g){
        if( dbImage == null ){
            dbImage = createImage(getWidth(),getHeight());
            dbGraphics = dbImage.getGraphics();
        }
        paint(dbGraphics);

        g.drawImage(dbImage,0,0,null);
    }

    public void paint(Graphics g){
         g.setColor(...);
         g.drawLine(...);
         // etc. etc. etc. ... nur zeichenoperationen auf g; nichts weiter
    }
}
so jedenfalls haben mir das alle tutorials suggeriert, daß dies funktioniert. dort steht überall zu lesen, daß laut der ursprünglichen implementierung durch meinen repaint()-aufruf dann zunächst beim neuzeichnen update(Graphics) aufgerufen wird, welches normalerweise den zeichenbereich mit der hintergrundfarbe übermalt und anschließend paint(Graphics) aufruft.

nur ist das bei mir leider nicht so. ich musste feststellen, daß, nach dem repaint() aufgerufen wurde, immer nur die paint(Graphics) methode direkt aufgerufen wird. update(Graphics) hingegen bleibt unberührt liegen und wird niemals aufgerufen. hab schon versucht das ganze mit anstatt von Panel von JPanel, von JComponent und von Component erben zu lassen. bei den Swing-Instanzen habe ich dann noch extra dazu versucht im konstruktor meiner klasse setDoubleBuffering(true) aufzurufen. alles ohne erfolg, aber mit viel flackern.

hat sich da was geändert bei java, daß das mit der 5er von java so nicht mehr funktioniert und die von mir studierten tutorials alle veraltet sind oder mach ich was verkehrt? zur not würd ich mir meine eigene UI-klasse schreiben, aber da würd ich dann doch noch gern drum herum kommen ... ist etwas viel aufwand für dieses problem.

vielen lieben dank

wayne[/code]
 

Marco13

Top Contributor
Von JPanel erben, und die paintComponent überschreiben (und NUR darin zeichnen) - Swing Components sind automatisch double buffered, darum braucht man sich dann nicht mehr zu kümmern...
 
G

Guest

Gast
ok, hab ich grad eben mal ausprobiert. klasse erbt von JPanel und paint(Graphics) habe ich in paintComponent(Graphics) umbenannt. ergebnis ist, daß die animation zwar läuft aber eben tierisch flackert. sicherheitshalber habe ich im konstrutor nochmals setDoubleBuffering(true) aufgerufen. bringt aber nix, was zu erwarten war, denn das sollte ja per default schon auf true stehen.

es sieht definitiv so aus, als würde vor meiner zeichenoperation erst die gesamte Component (in diesem fall das JPanel) schwarz ausgefüllt und angezeigt werden, bevor ich meine zeichenoperationen durchführen kann, die dann das ganze wieder mit farbe füllen. wäre super, wenns dafür ne einfache lösung gäbe das zu unterbinden.

trotzdem vielen dank

wayne
 
G

Guest

Gast
problem erkannt, aber nicht gelöst. habe gerade den entsprechenden code aus meinem programm herausgelöst und in einen testtreiber gepackt, damit ich ihn hier posten kann. dabei ist mir aufgefallen, daß ich anstatt die repaint() des JPanels, die des parents des JPanels aufgerufen habe. im testtreiber hab ich das dann geändert auf das direkte repaint() und schon lief es ruckelfrei.

das bringt mir nun zwar die erkenntnis, wie ich das doublebuffering nutzen kann, jedoch verhilft es mir immer noch nicht zu einem funktionierenden programm. letzteres leidet nämlich unter einem repaint()-problem. rufe ich im orginal quellcode repaint() des JPanels auf, so passiert nicht das geringste. die paint(Graphics) methode des JPanel wird nur einmal durchlaufen, dannach kann mein thread repaint() feuern so oft er will, es tut sich nichts.

zum verständnis: ich arbeite an einem medien-player, der verschiedene medien anzeigen kann. einerseits video-dateien mittels JMF, aber auch diverse inhalte aus datenbanken. letztere werden demnächst um eine newstickerfunktion erweitert und eben den programmier ich grad.

mein problem liegt wohl in der struktur des ganzen programms. bei programmstart wird ein Window erzeugt, welches alle inhalte darstellen wird. darauf wird ein Panel platziert, welches ab diesem zeitpunkt als viewport des players verwendet wird. es werden für alle möglichen inhalte die entsprechenden player-klassen instanziiert, alle abgeleitet von einer abstrakten player-klasse, welche pro instanz u.a. ein Panel als "VisualComponent" erzeugt und hält. ein scheduler wird parallel instanziiert und durch einträge aus einer datenbank gefüllt. feuert dieser ein event, wird der passende player dazu verwendet diesen inhalt anzuzeigen. dazu verankert er seine wiedergabeoberfläche auf seiner VisualComponent. die beauftragende instanz platziert diese auf dem viewport, nachdem die vorhergehende VisualComponent entfernt wurde. der benutzer merkt von dem wechsel nichts und da der scheduler seine events durch eine festgelegte pufferzeit vorab ankündigt, können die jeweiligen player ihren inhalt bereits zur wiedergabe vorbereiten, wobei ihnen ihre oberfläche bereits vollständig zur verfügung steht ... einzige ausnahme: die oberfläche ist halt noch nicht visible.

soweit so gut. problem hab ich nur, daß alle player schon von anfang ihre darstellung verweigerten. erst als ich die paint(Graphics)-methoden des viewport und der VisualComponent überschrieben hatte, klappte es:
Code:
pnViewport = new Panel(){
    public void paint(Graphics g){
        super.paint(g);
        for( int i = 0; i < getComponentCount(); i++ )
            getComponent(i).paint(g);
    }
}
also zusammenfassen ist der aufbau meiner oberfläche:
Window <- existiert genau 1x
Panel <- überschriebene paint(...), existiert genau 1x
Panel <- überschriebene paint(...), existiert pro instanziiertem player
wechselnde Wiedergabe-Einheit <- aktuell ein JPanel

und wenn ich nun von letzterem repaint() aufrufe passiert original gar nix. erst der aufruf getVisualComponent().repaint() in meinem NewstickerPlayer hat das repaint-event ausgelöst. ich hatte den ganzen baum schon in Swing testweise realisiert, jedoch mit gleichem ergebnis. egal ob ich doLayout(), validate() oder repaint() aufrufe, es funktioniert nur, wenn ich die paint-methoden überschreibe. LayoutManager verwende ich übrigends keinen, also ein NULL-Layout.

weiß nicht, vielleicht kann mir ja jemand dazu einen tip geben, warum das repaint nicht funktioniert oder wie ich rausfinden kann, warum es nicht funktioniert. vorrausgesetzt natürlich, daß ihr nicht die hände über eurem kopf zusammenschlagt, was da für ein scheiß zusammenprogrammiert wurde ;-)

soweit jedenfalls ist nun aber mein ursprüngliches problem gelöst und abgehackt

vielen dank

wayne
 

Quaxli

Top Contributor
Du mischt AWT (Panel, Frame) und Swing (JPanel), das ist grundsätzlich schon mal nicht gut.

...die paint(Graphics) methode des JPanel wird nur einmal durchlaufen, ...
In Swing überschreibt man paintComponent(Graphics)!

Halte Dich doch mal an den Rat von Marco13 und poste ein Stück compilierbaren Code. Ein (J)Frame, mit einem (J)Panel, in dem die Animation läuft. Inkl. main-Methode.
Und natürlich nur Swing oder AWT, wobei Swing die bessere Wahl wäre, wenn es nicht unbdingt AWT sein muß.
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben