Applet in Alternative umschreiben

Hallo Leute,

ich bin OCP und kann in Java programmieren nur mit Applets und Grafikgeschichten hatte ich noch nichts zu tun.
Ich habe die .class und .java Files von Applets einer WebSite. Da Applets schwer bis gar nicht mehr zum Laufen zu bringen sind möchte ich den Appletcode umschreiben zu einer Applikation oder einer einfachen lauffähigen Alternative zu Applets.

Gibt es dahingehend Beispiele oder Tutorials.

Beispielapplet (unter Applets Dodekaeder): www.jjam.de

Vielen Dank für Eure hilfe und viele Grüße,
Spliffer

Nun, Applets waren lange die einzige Möglichkeit, Programme ins Web zu bringen. Und Java ist ja eine „einfache“ Sprache. Und es gibt viele schlechte Applets, die von anderen kopiert und zu noch schlechteren Applets umgebaut wurden. Kurz: Es gibt viel Mist da draußen. Und dieses „Dodekaeder“-Applet enthält einige Sachen, die man so nicht machen sollte.

An sich kann die Portierung von einem Applet zu einer Swing-Anwendung recht mechanisch ablaufen. Das Applet selbst wird ein JPanel, die init-Methode wird im Konstruktor aufgerufen, statt paint überschreibt man paintComponent, das händische double-buffering fällt weg, und Animationen laufen in einem eigenen Thread (kein sleep während des Zeichnens :frowning: ).

Hab’ das hier mal am Beispiel durchexerziert, aber auch da gibt es einiges, was man, wenn man es neu schreiben würde, so nicht machen würde. Das ist quasi die Variante, bei der nur die notwendigsten (und einige der schmerzhaftesten) Dinge geändert sind:

package bytewelt;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

// From http://www.jjam.de/Java/Applets/3D_Effekte/Dodekaeder.html
// Ported to Swing for 
// https://forum.byte-welt.net/t/applet-in-alternative-umschreiben/20222

public class Dodekaeder {

    
    public static void main(String args[])
    {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
    
    private static void createAndShowGui()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(new DodekaederPanel());
        f.setSize(500,500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}


class DodekaederPanel extends JPanel
{
    // 20 Eckpunkte 1-20
    // mit je 3 Koordinaten 1,2,3
    double p[][] = new double[21][4];

    int x=1, y=2, z=3;

    DodekaederPanel()
    {
        init();
        startAnimation();
    }
    
    private void init()
    {
        setBackground(new Color(255,255,255));

        // Halbe Seitenlänge des eingeschriebenen Würfels
        double s = 100;

        // Höhe einer Dodekaeder-Kante über dem Würfel
        double h = s*0.5*(Math.sqrt(5)-1);

        // 20 Eckpunkte im lokalen Dodekaeder-Koordinatensystem
        // Nullpunkt = Mittelpunkt
        p[1][x] =    0;        p[1][y] =   -h;        p[1][z] = -(s+h);
        p[2][x] =    0;        p[2][y] =    h;        p[2][z] = -(s+h);
        p[3][x] =    s;        p[3][y] =   -s;        p[3][z] =  -s;
        p[4][x] =    s;        p[4][y] =    s;        p[4][z] =  -s;
        p[5][x] =   -s;        p[5][y] =    s;        p[5][z] =  -s;
        p[6][x] =   -s;        p[6][y] =   -s;        p[6][z] =  -s;
        p[7][x] =    s+h;      p[7][y] =    0;        p[7][z] =  -h;
        p[8][x] =  -(s+h);     p[8][y] =    0;        p[8][z] =  -h;
        p[9][x] =    h;        p[9][y] =    h+s;      p[9][z] =   0;
        p[10][x] =  -h;        p[10][y] =   h+s;      p[10][z] =  0;
        p[11][x] =  -h;        p[11][y] = -(s+h);     p[11][z] =  0;
        p[12][x] =   h;        p[12][y] = -(s+h);     p[12][z] =  0;
        p[13][x] =   s+h;      p[13][y] =   0;        p[13][z] =  h;
        p[14][x] = -(s+h);     p[14][y] =   0;        p[14][z] =  h;
        p[15][x] =   s;        p[15][y] =  -s;        p[15][z] =  s;
        p[16][x] =   s;        p[16][y] =   s;        p[16][z] =  s;
        p[17][x] =  -s;        p[17][y] =   s;        p[17][z] =  s;
        p[18][x] =  -s;        p[18][y] =  -s;        p[18][z] =  s;
        p[19][x] =   0;        p[19][y] =  -h;        p[19][z] =  s+h;
        p[20][x] =   0;        p[20][y] =   h;        p[20][z] =  s+h;
        
    }

    // Rotationswinkel in rad
    double ax = 0.01;
    double ay = 0.0075;
    double az = 0.005;

    int w = 200; // -> Weltkoordinaten
    double px, py, pz;

    @Override
    protected void paintComponent(Graphics gr) {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.BLACK);

        // Antialiasing
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        // Dodekaeder-Eckpunkte verbinden
        drawLine(g, 1,2);       drawLine(g, 2,4);        drawLine(g, 4,7);
        drawLine(g, 7,3);       drawLine(g, 3,1);        drawLine(g, 2,5);
        drawLine(g, 5,8);       drawLine(g, 8,6);        drawLine(g, 6,1);
        drawLine(g, 4,9);       drawLine(g, 9,10);       drawLine(g, 10,5);
        drawLine(g, 6,11);      drawLine(g, 11,12);      drawLine(g, 12,3);
        drawLine(g, 7,13);      drawLine(g, 8,14);       drawLine(g, 9,16);
        drawLine(g, 10,17);     drawLine(g, 11,18);      drawLine(g, 12,15);
        drawLine(g, 13,16);     drawLine(g, 16,20);      drawLine(g, 20,19);
        drawLine(g, 19,15);     drawLine(g, 15,13);      drawLine(g, 20,17);
        drawLine(g, 17,14);     drawLine(g, 14,18);      drawLine(g, 18,19);
    }

    public void drawLine(Graphics2D g, int i, int j) {
        g.drawLine(
            (int)(p**[x])+w,(int)(p**[y])+w,
            (int)(p[j][x])+w,(int)(p[j][y])+w);
    }
    
    private void startAnimation()
    {
        Thread t = new Thread(() -> 
        {
            while (true)
            {
                animationStep();
            }
        });
        t.setDaemon(true);
        t.start();
    }
    
    private void animationStep()
    {
        // Verzögerung
        try {Thread.sleep(20);}
        catch (InterruptedException e) {}

        for (int i=1;i<21;i++) {

            px = p**[x];
            py = p**[y];
            pz = p**[z];

            // Rotation um x-Achse
            p**[y] = py*Math.cos(ax)-pz*Math.sin(ax);
            p**[z] = py*Math.sin(ax)+pz*Math.cos(ax);

            py = p**[y];
            pz = p**[z];

            // Rotation um y-Achse
            p**[x] = px*Math.cos(ay)+pz*Math.sin(ay);
            p**[z] =-px*Math.sin(ay)+pz*Math.cos(ay);

            px = p**[x];

            // Rotation um z-Achse
            p**[x] = px*Math.cos(az)-py*Math.sin(az);
            p**[y] = py*Math.cos(az)+px*Math.sin(az);
        }
        repaint();
    }
    
}
1 Like

Vielen Dank Marco.

Viele Grüße und vielen Dank für Deine nette und kompetente Hilfe,
Spliffer

@Marco13: Finde ich gut, darf ich einige Passagen deines Textes mit in einen passenden Wiki-Artikel übernehmen?

Sicher. Vielleicht wäre es aber besser, einiges davon ausführlicher zu schreiben. Bisher sind da nur sehr stichpunktartig die wichtigsten Änderungen aufgezählt.

Eine „Anleitungsseite“: „Wie man ein Applet in eine (Swing)-Anwendung verwandelt“ wäre vielleicht nicht verkehrt.

Einfach wird das aber vermutlich nicht. Viele Applets sind wohl wirklich Applets (und keine JApplets), d.h. sie verwenden noch AWT. Wie viel man bei sowas zur „AWT-nach-Swing“-Frage sagen sollte, ist schwer einzuschätzen. Aber zum Glück dürften bei den meisten Applets, wenn überhaupt, nur einfach components vorkommen, und man könnte das vielleicht auch mit einem Abschnitt abhandeln: „Schreib’ einfach überall J davor“ :smiley:

Das stimmt, ich habe lange Zeit nur AWT-Applets geschrieben. Ich denke, es spricht doch nichts dagegen, wenn man die Applets, die nur AWT-Komponenten benutzen, in eine AWT-Applikation überführt. Wäre zumindest mein erster Gedanke…

Hmja, … ich fand da dann das update/buffer/paint-Gefrickel etwas lästig, weil es eben kein double-buffering gibt. Das dann für Swing zu ändern macht es ggf. erforderlich, mehr umzustruktutieren. (Im Beispiel oben: Das Graphics muss an drawLine übergeben werden usw).

Man könnte sicher auch überlegen, ob man sinnvoll abstufen kann:

  • Applet nach AWT
  • Applet nach Swing
  • JApplet nach Swing

Der Teufel steckt dann vermutlich im Detail. Wieder zum Beispiel oben: Dort stand halt sleep in der paint-Methode *autsch* :confused: Je „schöner“ es am Ende sein soll, um so aufwändiger sind ggf. die Umstrukturierungen. Aber ich denke, 90% der Portierung kann recht allgemein beschrieben sein.

BTW: Wenn du so eine Wiki-Seite anlegst, sag’ bescheid. Vielleicht können wir “top down” die grobe Struktur festlegen und dann jeder einen Abschnitt füllen oder so (im Moment kann ich nur schwer verbindliche Zusagen machen, aber das eine oder andere könnte ich vielleicht beitragen)

Da Spliffer, ja auch mal geäussert hat, das ganze nach HTML5, CSS3 und JS zu portieren, hab ich mich mal daran versucht das ganze eben mal mit HTML und JS umzusetzen.

Ein paar rauhe Ecken sind noch vorhanden, aber es lässt sich doch recht gut portieren und läuft dann auch ohne Plugins im Browser.

https://jsfiddle.net/8u29Ljh3/3/

Wollen wir uns noch auf einen Titel einigen? Was würde in Suchmaschinen am besten aussehen?

Ziemlich cool, @ionutbaiu. Kannst du auch gleich einen Teil des Artikels übernehmen. :wink:

Da müßte man mal einen SEO-Experten fragen.
Warte mal, ich kenn’ da jemanden … ma…la…@ja…fo…org :clown_face:

Aber mal in Ernst: Ich denke, was knackiges wie „Applets in Anwendungen umwandeln“ oder so könnte schon OK sein. (Oder „verwandeln“? Oder formaler „umschreiben“?) Wenn jemand noch treffendere Stichworte wüßte, die jemand mit diesem Ziel in Google eintippen könnte: Nur her damit :slight_smile: (Ich denke, viel vom Suchrang hängt dann auch von Inhalt und vor allem Verlinkung ab)

@ionutbaiu Schönes fiddle. Aber die Sprache … :frowning: ( :wink: )

Der Artikel ist angelegt: https://wiki.byte-welt.net/wiki/Java-Applet_zu_Java-Applikation_umschreiben

Ich werd’ mal zusehen, ob ich am Wochenende da einen ersten Draft/Grobstruktur/Stichpunkte (was wie beschrieben werden kann) einfügen kann (falls er bis dahin nicht schon existiert :wink: ). Je nachdem, wie ausführlich das wird, kann ja dann hier (oder in einem eigenen Thread) darüber diskutiert werden.

1 Like

Hab’ mal einen ersten Entwurf angefangen, mit Grobstruktur, ein paar Stichpunkten, und Fragen.

Ich könnte mir vorstellen, dass man ein “ganz dummes” Mini-Applet zeigt (wie den Dodekaeder, nur eben einfacher, ohne Animation, und mit weniger komplexen Elementen), und dann sagt, dass man das in eine Art “Template” für eine Anwendung einfügen kann…

...
frame.getContentPane().add(new ExampleApplet());
...

Die anderen Teile entsprechend: Zeichenfunktionen werden in eine JComponent#paintComponent gepackt. Animationen in einen Thread. Bedienkomponenten getrennt vom Applet selbst, also z.B. in einem “Control Panel”, das im BorderLayout.EAST liegt, während im CENTER die JComponent liegt, mit der gezeichnet wird.

Vermutlich wäre es auch sinnvoll, mal eine “Triage” von existierenden Applets zu machen, um zu sehen, welche Muster (oder Anti-Patterns) da auftreten, und wie man damit umgehen könnte.

Bezüglich “Triage”

Zu den ganzen “trivialen” Sachen, gibt es auch noch jede Menge Zeug, dass man mit Applets machen kann, die hier beschrieben sind.

https://docs.oracle.com/javase/tutorial/deployment/applet/doingMoreWithApplets.html

Da gehört zum Beispiel auch dazu, die Interaktion mit HTML/DOM und JavaScript.

Im einfachsten Fall erweitert man die Anwendung dahingehend, dass man dies dann integriert. Zusätzliche HTML-Formular-Felder in Swing oder AWT integrieren.

Wenn tatsächlich HTML benötigt wird, auf das einbinden einer WebView verweisen.

Hmja, die Spanne ist da sehr groß. Angefangen vom

class MyApplet extends Applet {
    public void paint(Graphics g) { g.drawString("Hello", 10, 10); }
}

bis hin zu einem Applet, das über den DOM mit der Außenwelt kommuniziert. Aber solche „großen, funktionsreichen“ Applets sind IMHO recht selten. (Wenn jemand sowas als Anwendung haben will: machMirEinAngebot@marco-hutter.de :wink: … ansonsten wird sowas heute ja tendenziell als „Web Application“ neu geschrieben :nauseated_face: ). Aber zumindest der Punkt mit dem Laden von Dateien (Bildern) ist wohl wichtig. Da gibt es zwar schon einen Wiki-Eintrag, aber wie man das getCodebase wegbekommt, würde auch gut in diesen Artikel passen.