# Applet Fenster nach Verdecken neu zeichnen?



## Guest (24. Okt 2005)

Hallo,
ich habe ein Applet indem ich ein neues Fenster öffne (AWT) und dort etws hinein male (Polygone). Doch jedesmal wenn das Fenster etwas verdeckt wurde muß der Inhalt neu gezeichnet werden. Dies dauert im Programm aber immer etwa eine Sekunde, weil ich jede Sekunde meine Daten update und neu zeichne. Wenn sich die Daten aber nicht verändern bräuchte ich eigentlich auch nicht neu zeichnen, aber dann würde das Fenster ja nach einem Verdecken leer bleiben.
Gibt es nicht soetwas wie einen Speicher der auch ein unverändertes Fenster gleich wieder voll darstellt?

THX


----------



## Mag1c (24. Okt 2005)

Hi,

als Schlagwort fällt mir dazu "double buffering" ein.

Lass dein Applet ein BufferedImage anzeigen, zeichne die Daten auf ein anderes BufferedImage und tausche es gegen das angezeigte aus.

Gruß
Mag1c


----------



## Guest (24. Okt 2005)

Ja, mach ich auch schon so mit dem Hauptfenster. Ich dachte das geht auch irgendwie einfacher, ich kenne da aus anderen Programmiersprachen z.B. AutoReDraw, wenn das true ist, übernimmt Windows den Refresh...
Naja, da bleibt mir wohl michts anderes übrig.

Danke trotzdem


----------



## MPW (24. Okt 2005)

ähm, wer so'n Müll wie awt nimmt muss sich natürlich nicht wundern...


in swing ist das nulloproblemo.

Du musst bedenken, wie alt die AWTKlassen sind, die neueren Swingklassen können das natürlich:

Nimm einfach ein JLabel, und übergib im Konstruktor dein ImageIcon(man kann auch irgendwie Image in ImageIcon umwandeln) dann wird autoredrawt....

//edit: Natürlich heißt's unter swing JLabel^^ //korrigiert!


----------



## L-ectron-X (24. Okt 2005)

@MPW: Manchmal muss man aus Kompatibilitätsgründen die Klassen des AWT benutzen.
Und ganz speziell, wenn man ein Applet einer möglichst breiten Masse zur Verfügung stellen will.
Der Grund sind Browser-Inkompatibilitäten, besonders beim IE, wenn dort kein aktuelles JRE installiert ist.


----------



## MPW (25. Okt 2005)

@L-ectron-X

Das ist natürlich klar, aber ich denke mal, wenn man sich überlegt aus welcher Zeit die AWT Klassen kamen - da gab's diese Programmiersprachen mit dem autoredraw auf die oben angesprochen wird auch noch nicht!

Kombilität ist ja bekanntlich immer ein großes Problem, man kann aber auch beim IE mal schnell ein aktuelles JRE einspielen....sofern man dies nicht ablehnt etc...


----------



## Sky (25. Okt 2005)

Anonymous hat gesagt.:
			
		

> Hallo,
> ich habe ein Applet indem ich ein neues Fenster öffne (AWT) und dort etws hinein male (Polygone). Doch jedesmal wenn das Fenster etwas verdeckt wurde muß der Inhalt neu gezeichnet werden. Dies dauert im Programm aber immer etwa eine Sekunde, weil ich jede Sekunde meine Daten update und neu zeichne. Wenn sich die Daten aber nicht verändern bräuchte ich eigentlich auch nicht neu zeichnen, aber dann würde das Fenster ja nach einem Verdecken leer bleiben.
> Gibt es nicht soetwas wie einen Speicher der auch ein unverändertes Fenster gleich wieder voll darstellt?
> 
> THX


Hast Du schon mal versucht einen ComponentListener und auf das Event componentShown mit einem Repaint zu reagieren? Damit Du die Berechnung nicht erneut durchführen musst, siehe oben (Stichwort BufferedImage).


----------



## MPW (25. Okt 2005)

@author of this thread:

Spricht denn prinzipiell was gegen Upgrade auf 1.4 oder 1.5?


----------



## Mag1c (25. Okt 2005)

Hi,

@MPW:
was, bitte schön, ist denn bei der Verwendung von ImageIcon anders gegenüber BufferedImage (außer daß das eine AWT und das andere Swing ist) ?? Das Problem des OP war doch wohl, daß immerzu das paint(...) aufgerufen wird, was eben bei seinen Daten etwas dauert. Und IMHO ist das unter Swing nicht anders. Lösungsvorschlag war, BufferedImage zu verwenden, so daß das Zeichen vom Darstellen getrennt arbeiten. Dein Vorschlag mit dem ImageIcon geht sicher auch, ist aber letztendlich das Gleiche.

Gruß
Mag1c


----------



## Bleiglanz (25. Okt 2005)

> Dies dauert im Programm aber immer etwa eine Sekunde, weil ich jede Sekunde meine Daten update und neu zeichne. Wenn sich die Daten aber nicht verändern bräuchte ich eigentlich auch nicht neu zeichnen, aber dann würde das Fenster ja nach einem Verdecken leer bleiben.


ist doch komisch

wie genau machst du das "jede Sekunde" neu zeichnen? schreib eine ganz normale paint Methode, die immer neu zeichnet?

und in deinem jede-Sekunde-Thread prüfst du halt vor dem Neuzeichnen, "ob sich was geändert" hat, ist mir jetzt nicht ganz klar, was denn das Problem ist


----------



## MPW (25. Okt 2005)

Bleiglanz hat gesagt.:
			
		

> > Dies dauert im Programm aber immer etwa eine Sekunde, weil ich jede Sekunde meine Daten update und neu zeichne. Wenn sich die Daten aber nicht verändern bräuchte ich eigentlich auch nicht neu zeichnen, aber dann würde das Fenster ja nach einem Verdecken leer bleiben.
> 
> 
> ist doch komisch
> ...



Du hast das Problem nicht verstanden, es geht nicht um eine Änderung innerhalb seines Programmes, sondern um Fensterüberdeckung, und das dann neu gezeichnet wird.

Dies macht er durch einen Thread wahrscheilnich!


----------



## Bleiglanz (25. Okt 2005)

```
new Timer().scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run() {
                if(/*hatsichwasgeaendert...*/) MyApplet.this.repaint();
            }},1000,1000);
```
wieso: er will jede Sekunde neuzeichnen UND wenn das Fenster kaputtet ist

aber paint wird ja eh aufgerufen, wenn das Fenster "überdeckt" worden ist???


----------



## MPW (25. Okt 2005)

nope, nicht wenn man unbuffered nimmt!


----------



## Bleiglanz (25. Okt 2005)

wie "nimmt" man "unbuffered"?

und warum sollte man das in so einem Fall nehmen?


----------



## Mag1c (25. Okt 2005)

Hi,

@MWP:
ich weiß ja nicht, was du hier immer von buffered, unbuffered und autoredrawt erzählst. Die Komponenten werden immer mit paint(...) gezeichnet, egal ob Swing oder AWT.

Falls du auf JComponent#isDoubleBuffered bzw. JComponent#setDoubleBuffered anspielst ... das ganze dient nur dazu, den Zeichenvorgang (durch paint(...) !! ) zunächst auf einem versteckten Buffer durchzuführen und anschließend den Buffer in den sichtbaren Bereich zu transferieren.
Das nützt dem OP nicht wirklich, da er ja erst bei Datenänderung neu Zeichnen will.

Gruß
Mag1c


----------



## MPW (25. Okt 2005)

hi,

@Mag1c

Sorry, aber du redest immer am topic vorbei, lies dir nochmal den Eröffnungpost durch.

Dort steht eindeutig, dass nachdem der Browser durch ein anderes Fenster verdeckt wurde, nicht automatisch neu gezeichnet wird!
Genau dies möchte der Author jetzt aber haben, und dafür braucht man entweder die swing-Komponenten, die dies automatisch tun, man nimmt double-buffered-Images oder repaintet regelmäßig durch einen Thread, was aber sehr unschön gelöst ist.

So, das sind die drei Möglichkeiten die du da hast, such' dir eine aus, und wenn du Probleme hast, meld' dich nochmal, ich klink mich jetzt aus aus dem Thread.


----------



## Sky (25. Okt 2005)

MPW hat gesagt.:
			
		

> oder repaintet regelmäßig durch einen Thread, was aber sehr unschön gelöst ist.


Nochmal die Frage: Warum nicht einfach ein ComponentListener, der auf das Event componentShown reagiert !?


----------



## MPW (25. Okt 2005)

Sky hat gesagt.:
			
		

> MPW hat gesagt.:
> 
> 
> 
> ...



Bist du denn sicher, das der dann auch ausgelöst wird wenn ein Fenster zwischendurch oben drüber war?

Oder wird der nur ausgelöst, wenn eine Componente setVisible(true) gesetzt wird?


----------



## Sky (25. Okt 2005)

bin mir nicht sicher, ist ein vorschlag; bis jetzt gab's darauf nur keine antwort


----------



## MPW (25. Okt 2005)

hm....wenn ich nicht so müde wäre und morgen Erde schreiben würde, würd' ich's ja ausprobieren, aber so muss das wohl jemannd anderes machen, wie wär's mal mit dem owner des Theads?


----------



## Mag1c (26. Okt 2005)

Moin,



			
				MPW hat gesagt.:
			
		

> hi,
> 
> @Mag1c
> 
> ...



Na dann zeig mir mal bitte genau, wo das steht  :bahnhof: 

Und paint(...) wird auch bei AWT zum Zeichnen der Komponenten aufgerufen.

Gruß
Mag1c


----------



## Bleiglanz (26. Okt 2005)

> Dort steht eindeutig, dass nachdem der Browser durch ein anderes Fenster verdeckt wurde, nicht automatisch neu gezeichnet wird!
> Genau dies möchte der Author jetzt aber haben, und dafür braucht man entweder die swing-Komponenten, die dies automatisch tun, man nimmt double-buffered-Images oder repaintet regelmäßig durch einen Thread, was aber sehr unschön gelöst ist.


irgendwie hat es der Autor des Originalpostings geschafft, seine paint Methode so zu schreiben, dass sein Fenster nach dem Verdecken nicht mehr neu gezeichnet wird

das wär nämlich das Standardverhalten unter AWT, man braucht dazu kein Swing und keine double-bufferei


----------



## Mag1c (26. Okt 2005)

ja genau,

bzw. braucht seine paint(...)-Methode aus unerfindlichen Gründen eine Sekunde, was natürlich zu einem paint()-Harakiri führt, wenn man durch die Fenster zappt.

Gruß
Mag1c


----------



## MPW (26. Okt 2005)

Also ich hatte diesen Effekt auch schonmal, und ich meine das es an dem unbuffered liegt.

(Mit swing geht's auf jeden Fall, so hab' ich das nämlich gemacht.)

Kann es vielleicht an der Performance des Rechners leigen?

Poste mal bitte die paint-Methode!!


----------



## Guest (27. Okt 2005)

Hi,

ich bin der der am Anfang die Frage gestellt hatt, mensch so eine Diskussion... aber ich will mal näher beschreiben wie ich das mache. Also ich habe ein Applet indem ich ein neues Frame erstelle in das ich von meinem Hauptfenster aus zeichnen kann:


```
Frame VisuZust;
...
VisuZust = new MyFrame("Zustand Fahrzeug");
VisuZust.addWindowListener(new WindowClosingAdapter(true));
VisuZust.setLayout(new BorderLayout());
VisuZust.setSize(350, 330);
VisuZust.show();
...

//mit einer Klasse MyFrame:

class MyFrame extends Frame  {
    public void main(String[] args) {

    }

    public MyFrame() {
        super("Dummy Titel");

    }

    //es wird der übergebene Titel übernommen
    public MyFrame(String Titel) {
        super(Titel);
    }

 }
```

und um jetzt in dieses neue Frame zeichnen zu können rufe ich "paintInThatFrame" jede Sekunde auf weil da neue Daten kommen:


```
//um etwas in ein bestimmtes Frame zu zeichnen
public void paintInThatFrame( Color c[] ) {
    int i;

    //in VisuZust zeichnen
    Graphics g = VisuZust.getGraphics();


    //Meldungen
       for (i=0; i<10; i++) {
           g.setColor(c[i]);
           if (i<5) {
               g.fillRoundRect(10,40+(i*30),20,20,2,2);
           } else {
               g.fillRoundRect(120,40+((i-5)*30),20,20,2,2);
           }

       }

        //Zustandsleuchte
        g.setColor(c[10]);
        g.fillRoundRect(10,190,60,60,2,2);

        //Auflieger zeichnen
        g.setColor(Color.blue);
        g.fillRect(250,40,80,210);
        g.setColor(Color.yellow);
        g.fillRect(255,45,32,200);
        g.fillRect(293,45,32,200);

        //Dock zeichnen
        g.setColor(Color.darkGray);
        g.fillRect(240,250,100,30);

        //Beschriftungen
        g.setColor(Color.black);
        g.drawString("Segment Ende",35,55);
        g.drawString("Automatik aktiv",35,85);
        g.drawString("Motor an",35,115);
        g.drawString("Handbremse",35,145);
        g.drawString("Fahrplan Stop",35,175);
        g.drawString("Abfahrbereit voll",145,55);
        g.drawString("Abfahrbereit leer",145,85);
        g.drawString("Hecktor zu",145,115);
        g.drawString("Störung Hydraulik",145,145);
        g.drawString("Seitentüren zu",145,175);

}
```

Das funktioniert auch alles. Nur ebend wird nach einem Verdecken des Frames VisuZust im worstcase erst wieder nach einer Sekunde neu gezeichnet und solange bleibt es weiß. Ich dachte nur irgendwie kann man dem Fanster sagen, dass es sich den Zustand merkt und gleich wieder darstellt bis zur nächsten Veränderung.
Ich hoffe es ist jetzt etwas klarer ... ;o)


----------



## Mag1c (27. Okt 2005)

Hmm,

von außen auf das Graphics malen ... ich glaub, das tut man so nicht   :roll: 

entweder du packst das ganze Zeichnengelumpe in die paint(...)-Methode des Frames (oder am besten noch ein Panel dazwischen). Dann wird das auch neu gezeichnet, wenn das Fenster wieder sichtbar wird,

oder du zeichnest in ein BufferedImage (da gibts auch ne getGraphics()-Methode) und läßt in der paint(...)-Methode des Frames das BufferedImage anzeigen.

Gruß
Mag1c


----------



## Sky (27. Okt 2005)

Bei AWT muss man glaub ich auf'n Canvas malen


----------



## Mag1c (27. Okt 2005)

Hi,

naja, läuft ja am Ende auf das selbe hinaus:


```
public class ImageCanvas extends Canvas
{

    public ImageCanvas(Image img)
    {
        image = img;
    }

    public void setImage(Image img)
    {
        image = img;
        invalidate();
        repaint();
    }

    public Dimension getPreferredSize()
    {
        Dimension dimension = null;
        if(image == null)
            dimension = new Dimension(200, 200);
        else
            dimension = new Dimension(image.getWidth(this), image.getHeight(this));
        return dimension;
    }

    public void paint(Graphics g)
    {
        if(image != null)
            g.drawImage(image, 0, 0, this);
    }

    private Image image;
}
```

Gruß
Mag1c


----------

