Pixelweises Painten eines Graphics-Objektes

Hallo,

ich habe eine Frage zu einem Applet, das ich gerade schreibe.

Ich habe in der init()-Methode einige Komponenten (Buttons, Canvas etc.) „geaddet“.

Wenn er jetzt paint() aufruft, dann erscheint alles auf einmal. Ich möchte aber, daß es fließend erscheint. Es sollen die Pixel zufällig hinzukommen, bis der gesamte Inhalt sichtbar ist.

Wie macht man das?

Ich habe mir schon überlegt, das Ganze wie beim DoubleBuffering zu machen. Dazu müßte ich aber die Buttons, Canvas etc. irgendwie in ein Image bekommen. Gibts sowas wie Img.getImage(g)?

Vielen Dank für Eure Mühe!

Servus,
Gustav

Moin

Wie macht man das?

Das ist verdammt komplex. Man kann einerseits ein „Bild“ vom Applet machen und das langsam erscheinen lassen und dann gegen das „Orignal“ austauschen => Die Buttons funktionieren erst nach dem Tauschen und das Tauschen ist als Ruck sichtbar

Oder man zeigt schon das Orginal, löscht aber die Teile die noch nicht sichtbar sein sollen. (Applet.paint(Graphics g) überschreiben und Teile ausblenden) => Die Buttons funktionieren sofort, aber das ganze verbraucht sehr viel Rechenpower, was besonders bei 1.1.8-Applets ein riesen Problem ist.

Wie gut kanns du programmieren ?

Ich habe mir schon überlegt, das Ganze wie beim
DoubleBuffering zu machen. Dazu müßte ich aber die Buttons,
Canvas etc. irgendwie in ein Image bekommen. Gibts sowas wie
Img.getImage(g)?

java.awt.image und Applet.paint… den Rest kann man zusammenraten. Das wäre Variante 1.

cu

Servus Pumpkin,

ich glaube, ich mache Variante 1. Habe ich das so richtig verstanden: Ich lege in der init() ein Graphics g_Fade_In = new Graphics(); an und mache meine g_Fade_In. add (steuerButton); g_Fade_In.add(meinCanvas); usw…

Wie bekomme ich jetzt den Fade_In-Effekt zustande? Ich müßte doch jetzt das g_Fade_In in ein Image img_von_g_Fade_In kopieren. Wie heißt der Befehl? Hab schon alle möglichen Bücher gewälzt, finde einfach nix.

Wenn ich dann das Image img_von_g_Fade_In habe, dann kann ich doch irgendwie mit dem PixelGrabber jedes einzelne Pixel in ein int[][] überführen.

Jetzt müßte ich ein Image img_Sichtbar erstellen, das z. B. eine schwarze Fläche hat.

Und jetzt kommt in der paint() die Routine, die zufällig alle Pixel von int[][] auf das img_Sichtbar einzeln kopiert und immer wieder repaintet. Das ist dann der sichtbare Fade_In - Effekt.

Wenn alles fertig ist, kommt das eigentliche Graphics g dran, und die Buttons etc. werden aktiv und anklickbar.

Gehts so?

Danke!
Servus,
Gustav

Moin

Habe ich das so richtig
verstanden: Ich lege in der init() ein Graphics g_Fade_In =
new Graphics();
an und mache meine
g_Fade_In. add (steuerButton); g_Fade_In.add(meinCanvas);
usw…

nein, nicht ganz:

Du erzeugts deine GUI wie immer und kommts dann irgendwann zu deinem normalen Pane/JPane (der einfachheit halber hier „comp“ genannt). Davon machts du ein Image:

Image komplett = comp.createImage(int width, int height); //schneller

ODER:

Image komplett = new BufferedImage (Höhe, Breite, TYPE_RGB) //langsamer, aber zuverlässiger

und malts das comp in das image:

Graphics g = komplett.getGraphics();
comp.paint(g); //*

komplett enthält nun ein Bild der GUI. Das Bild wird auf nix reagieren, man kann da nix anklicken. (deshalb bevorzuge ich Variante 2, aber ich schreib ja auch keine 1.1.8-Applets)

Jetzt gibts 2 Möglichkeiten:

Entweder du zeigts ein anderes temporärers Bild an oder du überschreibst comp.paint(Graphics g). Wenn du paint überschreibst musst du bei dem Aufruf * aufpassen.

–Variante temp-Bild:

Image temp = comp.createImage(int width, int height);

JLabel JB = new JLabel (new ImageIcon(temp));

Das Label JB zeigt du im Applet an.

Graphics g2 = temp.getGraphics();

nun mit g2.drawImage (…) Teile aus komplett in temp reinmalen, ein repaint von JB auslösen und abwarten (SwingUtils.invokeAndWait(Runnable doRun), man will ja dem AWT-Thread nicht zuviel auf die Füsse tretten), neue Teile reinmalen … bis das Bild durch ist. Dann JB aus dem Applet entfernen und die reale GUI einfügen. fertig.

–Variante überschriebenes comp.paint(Graphics g):

In der paint-Methode bei jedem Aufruf mehr Teile von komplett in g malen. Am Ende von paint(Graphics g) per repaint() den nächsten Aufruf auslösen. Wenn alle Teile komplett sind in paint nur noch super.paint(g) aufrufen und damit die orginale anzeigen.

In beiden Fällen nicht vergessen die Bilder zu entsorgen (Image.flush()) und an java.awt.Toolkit.sync() denken.

Wenn ich dann das Image img_von_g_Fade_In habe, dann kann ich
doch irgendwie mit dem PixelGrabber jedes einzelne Pixel in ein
int[][] überführen.

Das würd ich nicht tun. Beim graben werden die Bildinformationen in das java-interne 3x-int-Format übersetzt. Beim malen müssten sie zurückübersetzt werden… das frisst viel CPU-Leistung, vor allem bei X-basierten System (Unix/Linux/MacOS/…)

Wenn alles fertig ist, kommt das eigentliche Graphics g
dran, und die Buttons etc. werden aktiv und anklickbar.

Der Satz zeigt mir dass du einen kleinen Denkfehler drin hast:
Graphics-Objecte werden immer von der JVM erzeugt. Man kann sie nicht austauschen. Der Programmierer tauscht Image’s oder paint-Methoden aus, aber nie Graphics.

Gehts so?

Wenn nicht, frag nochmal… oder kuck mal auf http://www.durius.com/ ob nicht schon was passendes exisitiert. Ist aber nicht ganz gratis.

cu

Servus Pumpkin,

Was mach ich da falsch? Er soll eigentlich nur (in einem ersten Schritt) einmal das ganze Bild img_komplett in der Appletfläche ausgeben.

Danke!


public class X extends Applet implements Runnable {
private final Color farbeBackground = new Color(0, 128, 128);
Image img_komplett = this.createImage(this.getWidth(), this.getHeight());
public void init() {
Panel panel = new Panel();
Button myButton = new Button(„Hallo“);
panel.add(myButton);
Graphics g = img_komplett.getGraphics();
panel.paint(g); //*
}
public void paint(Graphics g) {
g.drawImage(img_komplett, 0, 0, this);
}
public void start() {
}
public void stop() {
}
public void run() {
}
}

Moin

Was mach ich da falsch? Er soll eigentlich nur (in einem
ersten Schritt) einmal das ganze Bild img_komplett in der
Appletfläche ausgeben.

Verdammt, daran hab ich nicht gedacht. Alles was in java.AWT steht (+JFrame) sind heavyweight-Elemente, d.h. sie werden nicht von java sondern vom OS gemalt. paint(g) gibt dann nur den Befehlt an das OS weiter und mit g wird nicht gearbeitet. Lightweight-Elemente arbeiten direkt mit g. (JButton.paint(g) würde also gehen)

Kanns du auf swing umsteigen oder bist du auf’s AWT festgelegt ?

Kannst du ein Bild der GUI machen (per psp oder gimp …) und im Applet laden (und dass dann „erscheinen“ lassen) ?

cu

Hallo Pumpkin,

tut mir leid, hat länger gedauert.

Swing wäre schon eine Möglichkeit. Ist es recht schwer, den awt-basierten Code auf swing zu transferieren?

Ist swing so weit verbreitet, so daß auch nahezu jeder im Inet das applet anschauen kann?

Ist swing langsamer/größere class-Dateien?

Werde mich dann mal damit beschäftigen…

Danke!
Servus,
Gustav

Moin

Swing wäre schon eine Möglichkeit. Ist es recht schwer, den
awt-basierten Code auf swing zu transferieren?

Eigentlich nicht. Man muss eben die Klassen austauschenm also aus allen Button’s JButton’s machen usw … Nur JFrame ist nicht ganz Code-kompatibel. (JFrame.add() get nicht, man muss JFrame.getContentPane().add() benutzen)

Ist swing so weit verbreitet, so daß auch nahezu jeder im Inet
das applet anschauen kann?

Swing gibts ab version 1.2. Richtig gut gehts ab 1.3. Aktuell ist 1.5 Beta irgendwas.

Applets funktionieren im Netz generell schlecht, dank der JVM von MS (1.1.8) die zeitweise bei verschiedenen Windows-Systemen dabei war, aber nicht mehr ist. Die JVM ist (wie immer bei MS) ein bisschen inkompatibel zum Orginal und hat jede Menge Sicherheitsprobleme.

Ist swing langsamer/größere class-Dateien?

5% langsamer, gleichgrosse Class-Dateien. Dafür siehts dann auf jedem Rechner exakt gleich aus.

cu