[Java Applet] Grafik Variable in ein anderes Objekt übergeben

V1tzl1

Lt. Junior Grade
Registriert
Sep. 2004
Beiträge
384
Moin, nach Stunden/Tagelangen gelese über Applets und Objekten hab ichs anscheinend immer noch nicht begriffen :freak: , da dachte ich, ich frag hier mal nach.
Wie bekomme ich die Graphics Variable in ein anderes Objekt, dass auch zeichnen soll
Folegenden Code hab ich schonmal gebastelt, aber mit der Graphicsvari hab ich schon alles versucht, ich hab keinen Plan, wie ich das anstellen soll.
Ich hab in mehrzeiligen Kommentaren (/* */) nochmal markiert, wo die Stellen sind.
Code:
import java.applet.Applet;
import java.awt.*;
import java.lang.Math.*;

public class Applets extends Applet
{
  Graphics Gr;
  public void paint ( Graphics gr ) /* Hier bekomme ich gr */
  { 
    Gr = gr;
    setBackground( Color.pink );
    Gr.drawString("CSF", 395, 20);
    
    Plane pl1 = new Plane(250,250,90);
   }
}

class Plane
{
  /*

  In diese Klasse soll die Variable gr (klein) mit dem Namen Gr (Groß-klein) verfügbar sein.
  Die Namen sind unterschiedlich, damit sie sich nicht überschneiden. Wenn man  die beide
  auch gleich schreiben kann, würd ich das sogar vorziehen.

  */
   // Daten
  int x,y,winkel,Fwinkel;
  double Fbetrag;
  
   // Kopnstruktoren
  Plane(int px, int py, int pwinkel)
  {
   x = px;
   y = py;
   winkel = pwinkel;
   draw(Color.blue);
  }
  
   // Methoden
  
  void draw(Color col)
  {
    double xFrom, yFrom, xTo, yTo;
    Gr.setColor( col );                                     /* Hier brauch ich zb Gr */
    
     // A -> B
    xFrom = x + (Math.cos(Math.toRadians(winkel))* 20);
    yFrom = y - (Math.sin(Math.toRadians(winkel))* 20);
    xTo = x + (Math.cos(Math.toRadians(winkel+160))* 15);
    yTo = y - (Math.sin(Math.toRadians(winkel+160))* 15);
    Gr.drawLine((int)xFrom, (int)yFrom, (int)xTo, (int)yTo);
    
     // B -> C
    xFrom = xTo;
    yFrom = yTo;
    xTo = x + (Math.cos(Math.toRadians(winkel+180))* 7);
    yTo = y - (Math.sin(Math.toRadians(winkel+180))* 7);
    Gr.drawLine((int)xFrom, (int)yFrom, (int)xTo, (int)yTo);
    
     // C -> D
    xFrom = xTo;
    yFrom = yTo;
    xTo = x + (Math.cos(Math.toRadians(winkel+200))* 15);
    yTo = y - (Math.sin(Math.toRadians(winkel+200))* 15);
    Gr.drawLine((int)xFrom, (int)yFrom, (int)xTo, (int)yTo);
    
     // D -> A
    xFrom = xTo;
    yFrom = yTo;
    xTo = x + (Math.cos(Math.toRadians(winkel))* 20);
    yTo = y - (Math.sin(Math.toRadians(winkel))* 20);
    Gr.drawLine((int)xFrom, (int)yFrom, (int)xTo, (int)yTo);
  }
  
}

Ich hoffe ien par von den "Java Gurus" hier können mir mal schnell unter die Arme greifen.
MfG V1tzl1

PS: Falls es wichtig sein sollte, ich nutze den J2 SE 5.0 (jdk 1.50) Compiler von Sun unter Windoof
 
Zuletzt bearbeitet: (Tja diese fiese deutsch Gramattik ;))
Naja du könntest zB in "Plane" ein Attribut "Graphics Gr" einführen und eine Set-Methode "public void setPlaneGraphics(Graphics g) {this.Gr = g }" einführen.

Dann brauchst du nur noch in der Klasse "Applets" in der "paint"-Methode folgende Zeile hinzufügen:

"pll.setPlaneGraphics(this.Gr)"

Damit kanns du nun auf "Gr" zugreifen.

Alternativ kanns du einen neuen "Plane"-Konstruktor hinzufügen:

"public Plane(int px, int py, int pwinkel, Graphics g){...}"


Du musst nun selbst wissen, was für deine Anwendung sinnvoll ist. Alternativ kannst du mal posten was deine Anwendung machen soll!
 
Hi,
wenn du die Klasse Plane nur einführst damit sie etwas zeichnest, dann kannst du sie von Panel ableiten, ebenfalls paint() überschreiben und eine Instanz in deinem Applet anzeigen.
Ansonsten hat Cleaner den Tip schon gegeben. Ist aber geschickter, das mit Vererbung zu machen, schliesslich programmierst du objektorientiert.

Übrigens werden bei Java die Variablennamen klein und Klassennamen groß geschrieben. Daran solltest du dich halten.

Gruß,
stengbiegel
 
Hi, ersteinmal vielen Dank an euch beide.

So, was mein Applet am Ende machen soll:
Das ganze soll ein kleines Spiel werden, in dem man mit einem Flieger 2Dimensional über den Bildschirm brettern kann. Dafü habe ich eine Klasse, Plane (Flieger), mit der ich den Flieger fliegen lassen will. Ein bestandteil davon ist natürlich, dass dieser Flieger auf dem Bildschirm sichtbar wird, bzw unsichtbar (in Hintergrundfarbe zeichnen lassen). Das mach ich mit der Methode draw() (Andere Methoden folgen noch).
Geplant sind allerdings noch eine Menge anderer Klassen, wie diverse Statusleisten und vor allem eine Landschaft. Alle diese Klassen werden auf dem Bildschirm "rumpinseln" müssen. Desshlab hatte ich vor, dass wie in C zumachen und den "Fensterhandle" in einer globalen Variable zu speichern, damit ich von überall drauf zugreifen kann.

Cleaner57, deine Lösungen sind ja prinzipiell in ordnung, aber dann müsste ich ja bei jedem Objekt zusehen, das ich die Parameter übergebe und ich wollte die Parameter in den Methoden eigentlich gering halten und eine eigene Methode würde ja bedeuten, dass ich gleich noch eine ganze Zeile hinter den Aufruf setzen muss.
Das mit den kleingeschriebenen Variablen Namen habe ich zur Kentniss genommen und werd mich von jetzt an dran halten.

stengbiegel, Wenn ich das ganze mit veerbung mache, habe ich ja in Plane alle Methoden von Applets und von Applet (wurde ja schon veerbt) da mit drin. Muss das wirklich sein, nur um eine Variable mit zu bekommen?

Gibt es denn eine möglichkeit globale Variablen zu definieren?

Nochmals danke an euch beiden
MfG V1tzl1
 
Ich weiss zwar nicht genau was du unter globalen Variablen verstehst, jedoch könntest du statische Variable benutzen, die auch zugänglich sind, wenn kein Objekt erzeugt wurde, es sind sozusagen Klassenvariablen. Du kannst dann durch KlasseX.variableY drauf zugreifen, wenn du in KlasseX die Variable variableY als "static <typ> variableY" deklarierst.

Es ist leider ein bisschen schwer zu verstehem was du dir genau wünschst, ein kleines Anforderungsdokument (mit einem UML-Diagramm und ein paar Zeilen Text) würde vielleicht weiterhelfen!
 
Hi,
erstmal zu deiner Frage, Plane erbt natürlich nicht von Applet sondern von z.B. Panel. Das Applet ist ja auch nur ein Panel, dem dann das Plane-Panel hinzugefügt wird. Siehe java.awt.Container. Durch das Überschreiben von paint() in Plane kannst du dann bestimmen, wie die Instanz von Plane gezeichnet wird.
Deinen Plan das Ganze C-ähnlich zu programmieren solltest du ganz schnell vergessen. Java ist objektorientiert und wenn du das nicht ausnutzt bzw. berücksichtigst erzeugt das unnötig Arbeit und ggf. Fehlerquellen.

Ich würde mir an deiner Stelle ein Modell überlegen aus dem folgendes hervorgeht :

Was können die einzelnen Teile im Spiel (Flieger kann geradeaus oder Kurve fliegen, Turbo zünden, unsichtbar werden, etc.) Welche Eigenschaften haben sie ? (Der Flieger hat eine Geschwindigkeit, Kurs, Höhe, Tank) Damit erhältst du z.B. eine Klasse Plane, die ebendiese Fähigkeiten als Methoden und Eigenschaften als Attribute besitzt. Die Methoden sind von aussen aufrufbar, die Attribute ggf. abfragbar.

Welche Abläufe gibt es im Spiel? Flieger fliegt gegen Berg, Sprit geht aus, Flieger soll Richtung ändern, etc. Dabei erhält man z.B. die Klasse Controller, die z.B. bei einer Eingabe berechnet, ob eine Kursänderung möglich ist oder ob da ein Baum steht. Entsprechend wird auf dem Fliegerobjekt die passende Methode aufgerufen.

Wie wird alles dargestellt? Möglich wäre eine Zeichenfläche auf der alle Objekte die eine Rolle spielen abgebildet sind. Diese soollen graphische Repräsentationen dieser Objekte sein. Subklassen von z.B. java.awt.Label. Wenn du deren Methoden geeignet überschreibst zeichnen sie sich selbst so, wie ihr aktueller Zustand ist. Also ein abgestürztes Flugzeug wird nicht wie ein neues gezeichnet sondern als Klumpen.

Klar soweit? Am besten setzt du dich mal mit dem MVC-Pattern (Model/View/Controller) auseinander und frischst deine Kenntnisse in objektorientierter Programmierung auf.

Von hier ist es nur noch ein kleiner Schritt indem du alles ausprogrammierst. Klingt nach viel Arbeit, ist es aber wert. Zum einen lernst du was, zum anderen wird so ein kleines Futzelprogramm schnell komplexer wenn man hier und da noch was einbauen will. Ein gutes Modell lässt sich ohne weiteres anpassen und eine gute Umsetzung auch (z.B. Ausgabe der Spielfläche als SVG-Animation auf einem Webserver, Spielstatistik als Excel-Tabelle, etc.)

So, und jetzt der kurze Weg. Zeichne in deinem Applet die einzelnen Figuren mit ein paar drawLine() Aufrufen. Das Applet hat eine Referenz auf den Flieger und kann beim Zeichnen dessen Eigenschaften abfragen (Position, Richtung, Farbe, etc.) und malt es einfach da hin.
Damit muss Plane überhaupt nix wissen von paint und Graphics.

Gruß,
stengbiegel
 
Hi, nochmals vielen Dnak für eure Hilfe, wenn auch ein wenig spät (sry)

Ich hab jetzt mla weiter gemacht. Meine Überlegungen, sind, dass alle "Objekte", die ich im Spiel brauche, zb ein Flugzeug, ein Buam usw alle unabhängig von einander etwas machen sollen (Das ist ja auch Sinn von Objekten, wenn ichd as richtig verstanden habe).
Daher kann ich ja meiner Meinung nach erstmal das Flugzeug vernünftig machen. Wenn das läuft dasnächste usw.
Also mein Flugzeug (atm ein Simples Dreieck) wird jezt unter Angabe eines Mittelpunktes und eines Winkels, auf jede beliebige Position des Bildschirms gepinselt. Immer wenn jetzt irgend eine Methode was an diesem Flugzeug ändert, ruf sie danach draw auf und das Flugzeug wird neu gezeichnet. Das klappt ja auch ganz gut, da ich die Grafikreferenz jetzt einfach an den Konstruktor übergebe.
Mein nächster Schritt sollte sein, dass sich der Flieger beim drücken der Taste "A" nach links herum dreht. Also hab ich mich zu Eventlistener schlau gelesen und bin auf folgenden Code gekommen (gekürzt)
Code:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.lang.Math.*;

public class SpaceFlyer extends Applet
{
  Graphics gr;
  
  public void paint ( Graphics g )
  { 
    setBackground( Color.white );
    gr = g;
    
    addKeyListener(new AppletAdapter());
  }
  public void msg()
  {
    gr.drawString("es wurde eine Taste gedrückt",10,50);
  }
}

class AppletAdapter implements KeyListener
{
  public void keyPressed(KeyEvent e)
  {
    SpaceFlyer f = (SpaceFlyer) e.getSource();
    f.msg();
  }
  public void keyReleased(KeyEvent e)
  {
  }
  public void keyTyped(KeyEvent e)
  {
  }
}
So erwarten tu ich von diesem Code jetzt, dass er mir, sobalt ich eine Taste herunterdrücke, dieses auch mitteilt. Doch leider bleibt der Screen leer, egal wie doll ich auf der Tastatur rumhämmere. Könnt ihr dort nen Fehler finden?
 
V1tzl1 schrieb:
... egal wie doll ich auf der Tastatur rumhämmere.
Gewalt ist keine Lösung. Auf den ersten Blick würd eich sagen, du solltest das Graphics-Objekt nicht ausserhalb von paint() ansprechen. Das Beispiel ist zwar mies, aber es ragiert auf die Tasten a, s und d (Vorher ins Dreieck klicken). Der Eventhandler erzwingt das neuzeichnen durch den Aufruf von repaint(). Vielleicht hilft dir das weiter.
Im übrigen sollte dein flyer nicht von Applet erben, da er nur als Container genutzt wird. Das heisst, er braucht nicht die Fähigkeiten und Eigenschaften eines Applets nur um ein bisschen was zu zeichnen. Das ist jetzt erstmal nicht so schlimm, macht aber einen schlankeren Code.

Gruß,
stengbiegel

Code:
public class Flyer extends Panel {
    
    protected boolean right = false;
    protected boolean left = false;
    protected boolean forward = false;
    
    public Flyer() {
        
        addKeyListener(new KeyListener(){
         
            public void keyPressed(KeyEvent e){
                
                if ('a' == e.getKeyChar())
                    
                    left = true;
                
                else if ('d' == e.getKeyChar())
                
                    right = true;
                
                else if ('s' == e.getKeyChar())
                    
                    forward = true;
                
                repaint();
                
            }
            
            public void keyReleased(KeyEvent e){
                
                if ('a' == e.getKeyChar())
                    
                    left = false;
                
                else if ('d' == e.getKeyChar())
                
                    right = false;
                
                else if ('s' == e.getKeyChar())
                    
                    forward = false;
                
                repaint();
                
            }
            
            public void keyTyped(KeyEvent e){
            }
            
        });
        
//        setBackground(Color.black);
        
    }
    
    public void paint(Graphics g){
     
        g.setColor(Color.gray);
        
        g.drawLine(0, 0, 10, 20);
        g.drawLine(1, 0, 10, 20);
        g.drawLine(19, 0, 10, 20);
        g.drawLine(0, 1, 20, 1);
        
        if (right){
            
            g.setColor(Color.red.darker());
            g.fillOval(0, 0, 6, 6);
        
        } else if (left){
            
            g.setColor(Color.green.darker());
            g.fillOval(14, 0, 6, 6);
        
        } else if (forward) {
        
            g.setColor(Color.white);
            g.fillOval(7, 14, 6, 6);
        
        }
        
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Frame f = new Frame();
        f.setSize(200, 200);
        
        f.addWindowListener(new WindowAdapter(){
        
            public void windowClosing(WindowEvent e){
                System.exit(0);
            }
            
        });
        
        Flyer flyer = new Flyer();
        flyer.setBounds(90, 90, 20, 20);
        
        f.setLayout(null);
        f.add(flyer);
        f.setBackground(Color.black);
        f.setVisible(true);
        
    }
    
}
 
stengbiegel schrieb:
Gewalt ist keine Lösung.
Ich denke du weißt, was ich damit meine ;)

Also ertseinmal vielen Dank für deine Lösung, ich werd sie mir mal durchsehen.
Das was ich so auf den ersten Blick erkenne, ist, dass du dort Frames nutzt, also das ganze als Application nutzt. Das erklärt auch, warum mein Flyer deiner Meinung nach nicht von Applet erben sollte. Die Klasse SpaceFlyer ist jedoch quasi die main Klasse und da das ganze ein Applet werden soll, erbt sie halt von Applet.
Der eigentliche Flieger (Die Klasse hab ich in dem Code oben rausgenommen, da sie nichts mit dem Prob zu tun hat) erbt überhaupt nichts, sondern bekommt ein Graphics Object mit in den Konstruktor.

Tjoah dann wer ich mal sehen, wie ich dass in nen Applet Code gebastelt bekomme. Nocheinmal vielen Dank
 
So dein Beispiel funktioniert wunderbar, nochmal vielen Dank dafür.
Allerdings hab ich noch einige Probleme, damit jetz zu arbeiten, da ich gerne in einem Objekt alle Tastatureingaben prüfen möchte und dann von dort aus die aufgaben verteilen.
Folgenden Code hab ich zur Zeit dabei rausbekommen
Code:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.lang.Math.*;

public class SpaceFlyer extends Applet // "Startklasse"
{
  Graphics gr; // Referenz auf den Grafikbereich
  Plane pl1;    // Referenz auf ein Flugzeug
  
  public void paint ( Graphics g )
  {
    setBackground( Color.white );
    gr = g;  // Grafikreferenz in der ganzen Klasse verfügbar machen
    
    pl1 = new Plane(gr,250,250,90);  // Einen neuen Flieger erstellen
    addKeyListener(new KeyListener()  // So jetzt gehts los mit der Überwachung
                        {
                          public void keyPressed(KeyEvent e)  {}  // Wird noch nicht benötigt
                          public void keyReleased(KeyEvent e)  {}  // Wird noch nicht benötigt
                          
                          public void keyTyped(KeyEvent e)
                          {
                           pl1.turn(180); // Soll die Methode turn des durch pl1 Referenzierten Fliegers aufrufen.
                            /*                                         */
                            /*      Hier ist das Problem        */
                            /*                                         */
                          }     
                        }
                   );
  }
}

class Plane
{
  Plane(...) // Konstruktor
  {
    ... // Der Übersichtshalber weggelassen
  }
  void turn()
  {
    // Diese Methode soll aufgerufen werden
  }
}
So mein Problem ist ja oben gekennzeichent. An dieser Codestelle kann ich zwar auf sämmtliche Variablen in der Klasse zugreifen und überschreiben, aber anscheinend kann ich dort keine Methoden aufrufen. weder welche aus der SpaceFlyer Klasse, noch aus der Flieger Klasse, oder deren Objekte. Wie bekomme ich es jetzt hin, dass von der gekennzeichneten Stelle auf eine Methode in einem Externen Objekt zugreifen kann?

MfG V1tzl1

PS: Kann man diese Listener Geschichte in eine andere Datei auslagern, also die verschiedenen Aktionen ,so dass in der Hauptdatei nur 1-2 Zeilen stehen bleiben, die den Listener dann von woi anders "hervorrufen"
 
Hi,
sorry für die späte Antwort.
Punkt 1:
Der Methodenaufruf funktioniert nicht, da du aus einem neuen Thread auf eine Variable deiner Klasse zugreifst. Java kann nicht wissen ob die Variable zur Laufzeit belegt ist oder es eine NPE geben wird und beschwert sich deshalb. Daher musst du entweder die Variable mit final zur Konstante machen, was hier ausfällt, da du ihr ja erstmal ein Objekt zuweisen willst. Plan B ist, aus dem EventListener heraus eine Methode aufzurufen, z.B. doTurn(), die du in SpaceFlyer implementierst. Das erstgenannte Problem fällt damit weg UND wenn du die Steuerung des Fliegers nicht nur über Tastatur sondern auch Maus, Telepathie oder sonstwie realisieren willst kannst du alle Listener die entsprechende Methode aufrufen lassen. Die Feinheiten (z.B. 180°) solltest du dann an dieser einen Stelle einbauen. Wenn sich dann etwas ändern sollte gibt es nur eine Stelle im Code, an der etwas angepasst werden muss.

Punkt 2:
Natürlich kannst (und solltest) du die Implementierung der Listener in extra Dateien packen. genauso kann deine Hauptklasse das Interface implementieren. Das ist sinnvoll, je nach Anwendung. Ich habe der Einfachheit halber eine anonyme Klasse genommen, da sich die Logik auf eine Wertzuweisung und deren Auswertung (repaint()) beschränkt.

Gruß,
stengbiegel
 
Hi stengbiegel, vielen Dnak für deine Hilfe, nur leider kann ich damit so gut wie gar nichts anfangen :(
Also zu Punkt 1 theoretisch hab ich das glaub ich verstanden nur hab ich noch Probleme das um zu setzen. Wenn er diese Methode implementieren soll, dann muss ich doch in der Klasse, die diese Methode mit verwenden soll einfach "implemnts keylistener" einfügen.
Dann meckert der Kompiler, dass er nur eine ganze Klasse und keine Methoden implementieren kann. Nehme ich jetzt aber die ganze Klasse, hat er auch einen Fehler, mit dem ich jedoch nichts anfangen kann
Plane [die Klasse die implementiert] ist not abstract and does not overwrite method keyReleased(java.awt.event.KeyEvent) ...
Das mit den 180° war auch nur nen Test. Ich wollte nur erstmal nen sichtbares Zeichen bekommen, dass er die erkannt hat, dass eine Taste gedrück wurde.

Bei Punkt 2 find ichs natürlich gut, dass das möglich ist, ist nur die Frage wie?

Ich hoffe ich geh dir nicht auf die nerven, aber mein Tutorial ist in Hinsicht Objekte echt ne katastrophe. unendliche Zeilen text, aber wirklich Inhalt kommt dabei nicht rüber :(

MfG V1tzl1
 
V1tzl1 schrieb:
Dann meckert der Kompiler, dass er nur eine ganze Klasse und keine Methoden implementieren kann. Nehme ich jetzt aber die ganze Klasse, hat er auch einen Fehler, mit dem ich jedoch nichts anfangen kann
??? Nimm's mir nicht übel aber der Compiler gibt eigentlich nur Fehlermedlungen aus mit denen man auch was anfangen kann. Entscheidend ist, dass du weisst was du da tust. Das scheint mir nicht so der Fall zu sein.

Wenn deine Klasse (egal ob eine schon existierende oder von dir neu angelegte) ein Interface implementieren soll, dann schreibst du
Code:
public class XYZ implements ABC {...}
und die Klasse XYZ muss alle Methoden aus ABC implementieren. Sonst hast du genau die Meldung, die du gepostet hast.

Ich weiss ja nicht, was für ein Tutorial du benutzt aber entweder ist es wirklich schlecht oder du hast es nicht richtig gelesen bzw. verstanden. Es ist alles ganz einfach. Man muss sich nur erstmal mit den Konzepten vertraut machen. Stichwort objektorientierte Programmierung. Hilft dir ungemein. Alles weiter ergibt sich dann von selbst.

Gruß,
stengbiegel
 

Ähnliche Themen

Zurück
Oben