Container

KalleM

Aktives Mitglied
Hallo,
muss gerade ein Applet schreiben und habe mich für ein JApplet entschieden.
Jetzt habe ich eine Klasse Ball, und eine eine Klasse BallApplet.
In der init()-Methode (BallApplet) habe ich dann drei Ballobjekte hinzugefügt (add(new Ball("Name", 0, 10))).
Die Klasse Ball habe ich mit JComponent erweiter und somit müssten die Ballobjecte jetzt doch jeweils in einem eigenem Container sein?
Weiter ist es so, dass nun ein Object über dem anderen liegt. Wie bekomme ich es hin, dass sich die Objecte nicht überlagern? Und zu einem späteren Zeitpunkt möchte ich die BallObjecte animieren.
Danke vorab.
 

Marco13

Top Contributor
Das Applet ist schon ein Container. Und da liegen die Bälle drin. Allerdings ist es "Aufgeräumter", wenn man die Bälle in ein JPanel legt, und nur DAS dann ins Applet. (Das Applet ist - wie ein JFrame - die "oberste Entität", und da sollte man seine eigenen, spezifischen Sachen eher REINlegen, statt sie direkt da drin zu machen).

Damit sich die Bälle nicht überlagern, dürfen sie nicht "Opak" sein, d.h. der Hintergrund darf nicht gefüllt werden. IMHO ist es aber Besser, einen "Sprite" (wie den Ball) NICHT von JComponent erben zu lassen.
 

KalleM

Aktives Mitglied
Danke erst mal.
Wenn ich dich bzw. es richtig verstanden haben, sollte die Klasse Ball von JPanel erben?
und die Ballobjekte in dem Appletconatiner platziert werden?
 

Marco13

Top Contributor
Der Hinweis "...NICHT von JComponent erben..." sollte nicht heißen, dass er von JPanel erben sollte ;) Sondern u.U. von "überhauptnichts".

Ein JPanel (oder auch eine JComponent) ist ein SEHR komplexes Objekt, mit SEHR vielen Eigenschaften und Methoden. Ein Ball ist (in diesem Fall) etwas sehr einfaches. Der hat eine Position. Vielleicht noch eine Farbe. Vielleicht noch einen Radius.... aber eben keinen LayoutManager oder VetoableChangeSupport oder PropertyChangeListener - was man eben von JComponent so alles erben würde.

Es gibt da teilweise unterschiedliche Ansichten. Für Anfänger könnte es "erstmal" einfacher sein, Ball von JComponent oder JPanel erben zu lassen, und den eigentlichen Kreis dann in der paintComponent-Methode zu zeichnen. Sowas wie das Setzen der Position und MouseListener für den Ball usw. kreigt man dann "gratis". Aber es ist strukturell eben IMHO sehr unschön, wenn man "mal schnell von irgendwas erbt, weil das (zufällig) ein paar Sachen hat, die man gerade gut gebrauchen kann". Vererbung ist eine IST-EIN-Beziehung. Und ein Ball ist keine Component.

Das mit dem JPanel bezog sich darauf, dass es Vorteile haben kann, die Struktur etwa so zu machen:
Java:
class BallPanel extends JPanel // Nicht JApplet!
{
    ...
}

class BallApplet extends JApplet
{
    private BallPanel ballPanel;

    public void initialisiereAlles()
    {
        // BallPanel ins Applet legen. Das Applet ist nur
        // die "Startumgebung" für das eigentliche 
        // Programm. Die größten Teile des Programms
        // liegen in Klassen, die nicht von JApplet erben...
        ballPanel = new BallPanel();
        add(ballPanel); 
    }

}

Der offensichtlichste Vorteil: Wenn das später mal kein Applet mehr sein muss, sondern eine Normale Application, muss man FAST nur das "...extends JApplet" in "...extends JFrame" ändern, und sonst ändert sich KAUM(!) etwas.

Du kannst dir auch mal Malen in Swing Teil 1: der grundlegende Mechanismus - Byte-Welt Wiki ansehen, als Einstieg.

Das eigentliche Zeichnen der Bälle könnte dann GANZ grob so sein wie
Java:
class Ball // extends gar nichts....
{
    private int positionX, positionY; // usw...

    public void maleBall(Graphics g)
    {
        g.drawOval(....);
    }
}


class BallPanel extends JPanel
{

    // Hierfür noch add/remove-Methoden 
    private List<Ball> bälle = new ArrayList<Ball>();

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        // Male alle Bälle in dieses Panel
        for (Ball ball : bälle) ball.maleBall(g);
    }
}

Aber man muss vorher schon noch genauer überlegen, was man damit am Ende alles machen können will...
 

André Uhres

Top Contributor
ein Ball ist keine Component
Wie schon oft hier im Forum erklärt wurde, unterscheiden wir bei Swing Programmen gewöhnlich zwischen Modell und graphischer Darstellung. Die Klasse Ball z.B. könnte das Modell eines Balls sein und alle Attribute und logischen Zusammenhängen beschreiben, die für die Funktionen des Balls innerhalb der Anwendung erforderlich sind. Die graphische Darstellung hingegen ist der Bereich einer Swing Oberflächenkomponente. Im Fall eines Balls könnten wir diese Komponente etwa "BallComponent" nennen. Wir können sie von JComponent ableiten und die callback Methode "paintComponent(..)" überschreiben um dort die graphische Darstellung des Balls zu verwirklichen.
 

eRaaaa

Top Contributor
Wie schon oft hier im Forum erklärt wurde, unterscheiden wir bei Swing Programmen gewöhnlich zwischen Modell und graphischer Darstellung. Die Klasse Ball z.B. könnte das Modell eines Balls sein und alle Attribute und logischen Zusammenhängen beschreiben, die für die Funktionen des Balls innerhalb der Anwendung erforderlich sind. Die graphische Darstellung hingegen ist der Bereich einer Swing Oberflächenkomponente. Im Fall eines Balls könnten wir diese Komponente etwa "BallComponent" nennen. Wir können sie von JComponent ableiten und die callback Methode "paintComponent(..)" überschreiben um dort die graphische Darstellung des Balls zu verwirklichen.

Hi,
also so wie ich Marco13 verstehe, sagt er ja nicht, dass es diese Trennung zwischen Modell und grafischer Trennung nicht geben soll, sondern nur dass es halt in vielen Fällen ungünstig ist JComponent zu erweitern, weils eben auch viel mitschleppt was man evtl. gar nicht braucht.
Trennen kann man ja dennoch - kann ja dennoch eine graphische Klasse zu meinem Ball haben, welche eben halt dann nur nicht unbedingt von JComponent erbt.
In irgend einem Tutorial (glaube es ging um Interfaces) wurde ein Interface Drawable erstellt welches dann jede Klasse die gezeichnet werden soll implementiert.Genau das wäre dann meiner Meinung diese Klasse, die für die graphische Darstellung des Balles verantwortlich ist. Dann gibt es eine Stelle,eine paintComponent, die sich um das Zeichnen dieser Objekte kümmert....
Hier wirds ja eig. auch so gemacht, wobei es hier sogar direkt in der Modell-Klasse implementiert wird wenn man es so will.
Generell ist das ein interessantes Theme wie ich finde, vllt könnte ein Mod daraus ja auch einen neuen Thread erstellen, es sei denn es will eh niemand mehr darüber diskutieren :(
 

Marco13

Top Contributor
Die Klasse Ball z.B. könnte das Modell eines Balls sein [...] Die graphische Darstellung hingegen ist der Bereich einer Swing Oberflächenkomponente. Im Fall eines Balls könnten wir diese Komponente etwa "BallComponent" nennen. Wir können sie von JComponent ableiten [...]

Ja, das kann man so machen. Es ging nicht darum, dass es grundsätzlich "falsch" ist, für eine Modell-Entität einen Sprite in Form einer JComponent zu erstellen. Nur bisher schien es so, als ob die (von Component abgeleitete Klasse) hier das Modell sein sollte, die auch später animiert werden sollen - wenn das dann noch in einem eigenen Thread passieren soll, und vielleicht noch auf Basis der "Component-Modelle" Kollisionserkennung gemacht werden soll oder so, landet man in einer "invokeLater-Hölle" :autsch:

Selbst wenn man die beschriebene Lösung verwendet, sollte man sich noch die Frage stellen, ob eine 1:1-Beziehung zwischen den Instanzen der Modellklasse und den Instanzen der "BallComponent"-Klasse bestehen sollte. Die Mechanismen, die in Swing verwendet werden, wenn "viele Daten-Einheiten" gezeichnet werden sollen haben sicher auch ihre Rechtfertigung - ich meine speziell das *CellRenderer-Konzept, bei dem EINE Component als "Stempel" zum Zeichnen vieler Datenelemente verwendet wird. Wann das wirklich "kritisch" wird, läßt sich schwer sagen, aber spätestens wenn man 1000 Bälle hat, und dafür 1000 Components (auf dem EDT, aber "synchron" zur Bewegung der Modell-Instanzen) in jedem Schitt neupositionieren und neuzeichnen muss, könnte das ... unschön werden....
 

André Uhres

Top Contributor
also so wie ich Marco13 verstehe, sagt er ja nicht, dass es diese Trennung zwischen Modell und grafischer Darstellung nicht geben soll

Das würde ich dem Autor eines MVC Tutorials auch niemals unterstellen :D . Man kann natürlich sagen, das ganze JPanel gehört zur Darstellung des Balls. Aber man will dort vielleicht noch andere Entitäten darstellen, wie z.B. ein Tennisschläger. Dann wäre eine eigene Komponente wohl doch sauberer und sinnvoller.

Dass "eben auch viel mitschleppt was man evtl. gar nicht braucht" ist eigentlich hier kein Argument. Es wird ja nichts "geschleppt", es "ruhen" höchsten überflüssige Attribute im Heap ohne wirklich lästig zu sein. Es ist ja wohl eher die Regel, dass man viele der angebotene Funktionen überhaupt nicht nutzt, egal welche Standardklasse eingesetzt wird.

Man kann jedoch argumentieren, dass das JPanel das Spiel darstellt und die Darstellung des Balls gehört halt dazu, ohne eine eigene Komponente zu haben. Das ist sicherlich legitim, setzt aber mehr Wissen über die Zusammenhänge der Malmechanismen voraus. Diese Mechanismen werden von manchen Entwicklern nicht gut verstanden, so dass sie Malcode schreiben, der nicht so leistungsfähig ist als bei der Nutzung der Standard Swing Komponenten.
 

Marco13

Top Contributor
Dass "eben auch viel mitschleppt was man evtl. gar nicht braucht" ist eigentlich hier kein Argument. Es wird ja nichts "geschleppt", es "ruhen" höchsten überflüssige Attribute im Heap ohne wirklich lästig zu sein. Es ist ja wohl eher die Regel, dass man viele der angebotene Funktionen überhaupt nicht nutzt, egal welche Standardklasse eingesetzt wird.

Naja, natürlich könnte man sagen: "Warum von Object erben, wenn ich keinen hashCode" brauche? Aber konsequent weitergedacht würde das ja heißen, dass man ALLE Fields und ALLE Methods, die in einem Programm (egal, wie groß es ist) in eine Klasse packen könnte, und dann einfach davon erbt und nur aufgrund des Klassennamens entscheidet, welche Dinge für die erbende Klasse interessant sind :D
Es stimmt aber: Es ist in diesem speziellen Fall kein gutes Argument, weil bestimmte Dinge eben vom Framework (Swing) vorgegeben sind, und man z.B. eben keine Zeichenfläche definieren kann, die nicht von Component erbt. Aber wenn es um so etwas einfaches geht, wie einen Kreis zu zeichnen, sollte etwas leichtgewichtigeres und auf's wesentliche reduzierte, wie z.B. einer "BallPainter"-Klasse die eben nicht von Component eben muss, zumindest eine Überlegung wert sein.
 

André Uhres

Top Contributor
Aber wenn es um so etwas einfaches geht, wie einen Kreis zu zeichnen, sollte etwas leichtgewichtigeres und auf's wesentliche reduzierte, wie z.B. einer "BallPainter"-Klasse die eben nicht von Component eben muss, zumindest eine Überlegung wert sein.

Wie du richtig sagst, wird schließlich trotz allem irgendwo von Component geerbt werden müssen um überhaupt etwas auf den Bildschirm zu bekommen. Gerade wenn es um einfache Dinge geht, sind sie sicherlich keine Überlegungen wert, die nur das Ziel verfolgen, die Anzahl der Components zu reduzieren.
 

Marco13

Top Contributor
Ich denke, dass es GERADE bei einfachen Sprites ein Überlegung wert ist: Vermutlich geht es hier nur um 10-100 Bälle, aber bei 1000 oder 10000 einfachen Sprites wäre es IMHO ein Overkill, da für jede eine JComponent zu erstellen. Aber da kann man wohl einfach unterschiedliche Ansichten haben ;)
 

André Uhres

Top Contributor
Ich denke, dass es GERADE bei einfachen Sprites ein Überlegung wert ist: Vermutlich geht es hier nur um 10-100 Bälle, aber bei 1000 oder 10000 einfachen Sprites wäre es IMHO ein Overkill, da für jede eine JComponent zu erstellen. Aber da kann man wohl einfach unterschiedliche Ansichten haben ;)

10000 ist schon relativ viel, aber das werden moderne Maschinen sicher noch verkraften. Drüber wird's wahrscheinlich zunehmend kritischer, egal ob mit oder ohne Components.
 

Marco13

Top Contributor
OK, das bezieht sich jetzt nur auf's Zeichnen. Aber IMHO sollte man auch nicht vernachlässigen, was zum Beispiel(!) ein unscheinbares "setBounds" für einen Rattenschwanz an Dirty Rectangle Detections, Repaints und sonstigen Events nach sich zieht... Vielleicht können wir uns darauf einigen: Mit JComponents wird es zumindest (u.U. deutlich) früher kritisch, als bei einem Objekt, das nur 2 ints und eine "händisch" aufgerufene paint-Methode enthält... ;)
 

André Uhres

Top Contributor
Mit JComponents wird es zumindest (u.U. deutlich) früher kritisch, als bei einem Objekt, das nur 2 ints und eine "händisch" aufgerufene paint-Methode enthält...
Swing ist darauf getrimmt, die Leistung der Malprozesse zu maximieren. Ob das "händisch" besser gelingt, wage ich zu bezweifeln. Der Entwickler würde jedenfalls vor eine Aufgabe gestellt, die der Neuerfindung des Rades in etwa gleich käme.
 

Marco13

Top Contributor
Naja ... langsam nähern wir uns dem Punkt, wo man auch sagen könnte, dass es auf den konkreten Anwendungsfall ankommt. Vielleicht haben wir auch nur unterschiedliche Bilder vor Augen, also unterschiedliche Szenarien im Hinterkopf.

Aber ich stelle mir bei der Component-Lösung für die Animation jetzt grob sowas vor:
Java:
void doAnimationStep()
{
    for (Ball ball : ball)
    {
        final Ball currentB = ball;
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                currentBall.setBounds(...new position...);
            }
        });
    }
}
Ggf. mit unterschiedlicher "Granularität" der SwingUtilities. Man könnte erst alle neuen Positionen in einer Liste speichern, und dann auf die Modell-Instanzen anwenden, und dann alle auf einmal in EINEM invokeLater an die Components weiterreichen - aber böswillig formuliert hat man da die Wahl, ob man dem EDT 10000 kleine Tasks geben, oder ihn mit 10000 Positionsänderungen ausbremsen will.

Unabhängig davon würde jeder dieser setBounds-Aufrufe bei Component#reshape landen, und wenn man sich diese Methode mal ansieht: Die ist ziemlich kompliziert...: synchronization, evtl. invalidate, notifyNewBounds, repaintParentIfNeeded mit PaintEvent und allem drum und dran - und am Ende würden die (zugegeben: cleveren) Swing-Mechanismen festellen, dass wegen der vielen Bälle praktisch das ganze Fenster neu gezeichnet werden muss.

Im Vergleich dazu sieht sowas wie
Java:
void doAnimationStep()
{
    for (Ball ball : ball)
    {
        ball.setNewPosition(...new position...);
    }
    ballComponent.repaint();
}
IMHO schön überschaubar aus...

Ich werd' vielleicht mal ein Beispiel basteln, was beides vergleicht. Aber erst würde ich gerne wissen, ob du bei den Components an irgendwas anderes gedacht hast, und ich das vielleicht nur falsch verstanden habe.. ???:L
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Z Random Butten erstellen ohne Container AWT, Swing, JavaFX & SWT 15
P JavaFX Zugriff auf Fenster/Layout-Container in eigenen Klassen AWT, Swing, JavaFX & SWT 5
H Aus Array Container Panel an Tabbedpane zuweisen AWT, Swing, JavaFX & SWT 29
W JavaFX Tabelle zeilenweise mit Werten füllen und an Container anpassen AWT, Swing, JavaFX & SWT 23
B Swing KeyListener auf Container? AWT, Swing, JavaFX & SWT 1
I CSS - backgroundImage - Größe automatisch an den Container anpassen AWT, Swing, JavaFX & SWT 1
A Swing Externe Klassen aufrufen und in einem bereits vorhandenen Container einfügen AWT, Swing, JavaFX & SWT 0
C Componente in Container (inkl. "Untercontainer") suchen und zurückgeben AWT, Swing, JavaFX & SWT 3
B JTextArea Größe an Container anpassen AWT, Swing, JavaFX & SWT 2
Z Swing JPanel soll größer werden als Parent Container (überlappen) AWT, Swing, JavaFX & SWT 5
H Drag-Evente nach Container wechsel AWT, Swing, JavaFX & SWT 2
J Fehlermeldung adding a window to a container AWT, Swing, JavaFX & SWT 9
S JPanel in den Container hinzufügen AWT, Swing, JavaFX & SWT 3
xehpuk Swing Erst Components, dann Container zeichnen AWT, Swing, JavaFX & SWT 2
K JFrame-Größe an inneren Container anpassen AWT, Swing, JavaFX & SWT 2
J Swing Container innerhalb eines JPanels erfragen AWT, Swing, JavaFX & SWT 3
W setEnabled in Container Objekten (JScrollPane) AWT, Swing, JavaFX & SWT 5
X Instanzieren und Zuweisen vom BorderLayout an Container nicht notwendig ? AWT, Swing, JavaFX & SWT 4
B JPG in einem Container anzeigen lassen AWT, Swing, JavaFX & SWT 3
S this-Zugriff auf Container höherer Ebene AWT, Swing, JavaFX & SWT 2
P DragAndDrop zw Component und Container AWT, Swing, JavaFX & SWT 4
S SWT Lösen mit Shell, Container oder Group? AWT, Swing, JavaFX & SWT 5
D Container des JFrame zeichnet sich nicht bei Aufruf von paintAll AWT, Swing, JavaFX & SWT 9
T Exception: Adding a window to a container AWT, Swing, JavaFX & SWT 14
D Container vor Fullscreen AWT, Swing, JavaFX & SWT 5
R Container Size Problem AWT, Swing, JavaFX & SWT 5
hdi Verständnisfrage: Container vs. Component AWT, Swing, JavaFX & SWT 3
I Container AWT, Swing, JavaFX & SWT 6
G MouseEvents an Container weiterleiten AWT, Swing, JavaFX & SWT 8
H Benachrichtigt werden wann ein Container repainted wird? AWT, Swing, JavaFX & SWT 5
G Graphics Objekte in AWT Container einfügen AWT, Swing, JavaFX & SWT 2
A MouseEvent auf Container bzw. Frame weiterleiten AWT, Swing, JavaFX & SWT 5
S Mehrere Container AWT, Swing, JavaFX & SWT 10
T Canvas gegen Container austauschen --> GUI fehlt AWT, Swing, JavaFX & SWT 4
M Container in Frame über Button einfügen? AWT, Swing, JavaFX & SWT 4
A Container AWT, Swing, JavaFX & SWT 8
G Durchsichtiger verschiebbarer Container gesucht AWT, Swing, JavaFX & SWT 6
G problem mit anzeigen eines geänderten Container AWT, Swing, JavaFX & SWT 2
S Kann JSP mit BI nicht zum Container hinzufügen AWT, Swing, JavaFX & SWT 7
G hintergrund von JFrame/Container transparent machen AWT, Swing, JavaFX & SWT 2
C JPanel oder Container in JPanel AWT, Swing, JavaFX & SWT 2
X Container aus FocusCycle entfernen AWT, Swing, JavaFX & SWT 2
B Container aus einen andere Klasse hinbekommen ? AWT, Swing, JavaFX & SWT 5
R Component aus Container entfernen bzw. austauschen. AWT, Swing, JavaFX & SWT 6
I Hintergrundbild bei awt container AWT, Swing, JavaFX & SWT 9

Ähnliche Java Themen


Oben