2012-04-09 13 views
5

Ich habe gerade begonnen, Videospiele zu programmieren, und ich habe gehört, dass das Zeichnen auf einem JPanel und das Anfügen dieses Panels an einen JFrame besser ist, als einfach auf den JFrame zu zeichnen. Ich habe mich nur gefragt, warum ist das besser?Warum wird ein JPanel besser angehängt?

+3

Was ist Ihre Quelle? – mre

+0

@mre Es ist etwas, das ich allgemein empfehle (oder nah dran - siehe meine Antwort), aber ich bin auch daran interessiert, die genaue Quelle des OPs zu dieser Information zu hören. Zu der Person, die die Frage stellt. Dies würde mit dieser kleinen zusätzlichen Informationsmenge zu einer "guten Frage" werden. –

+0

+1, eine der wenigen Java-Fragen, auf die ich die Antwort kenne. Einmal ein [Java RPG Game] erstellt (https://github.com/intermediate-hacker/Pro_RPG), hat es sehr genossen. :) – ApprenticeHacker

Antwort

9

Es ist besser, aus verschiedenen Gründen, einschließlich:

  • In den meisten Swing-Komponenten, individuelle Malerei durch Überschreiben der paintComponent(Graphics) Verfahren erreicht wird. Swing-Behälter der obersten Ebene (z. B. JFrame, JApplet, JWindow) haben nur paint(Graphics). Als Ergebnis der geläufigen Methode zum Malen vergessen Menschen, die antworten, oft diesen Unterschied zwischen herkömmlichen und Top-Level-Komponenten und schlagen daher dumme Ratschläge vor. ;)
  • A JComponent kann in einem JPanel oder ein JInternalFrame oder einem an ein JFrame oder ein JApplet oder ein JDialog oder einen Constraint eines Layouts hinzugefügt werden ..Gerade wenn Sie denken, dass Ihre GUI komplett ist, sagt der Client "Hey, wäre es nicht toll, in eine Werkzeugleiste zu werfen & bieten Sie es auch als Applet?" Der Ansatz JComponent passt sich leicht daran an.
  • Wie von Richante erklärt (komplett mit Code!), Ist es einfacher, die Koordinaten zu berechnen, die für die Bemalung der benutzerdefinierten Komponente erforderlich sind, und wenn sie eine bevorzugte Größe hat, die Größe JFrame auf "genau die richtige Größe" zu setzen um die GUI zu enthalten (unter Verwendung von pack()). Dies ist insbesondere dann der Fall, wenn andere Komponenten hinzugefügt werden.

nun zwei kleinere Unstimmigkeiten mit dem Rat angeboten.

Wenn die gesamte Komponente maßgefertigt ist, kann es besser sein, einfach eine BufferedImage in eine ImageIcon/JLabel Combo zu legen. Hier ist ein Beispiel für painting to an image.
Wenn es an der Zeit, sie aktualisieren kommt:

  1. Anruf getGraphics() für eine Graphics oder createGraphics() für eine Graphics2D
  2. Zeichnen Sie die benutzerdefinierte Malerei zu dieser Grafik Instanz
  3. Entsorgen Sie die Grafik Instanz
  4. Anruf repaint() auf das Etikett.
+1

Es gibt einige Vorteile beim Abrufen des UI-Delegaten des Panels. – trashgod

+0

@trashgod Danke für die Erinnerung an mich. Es gibt jedoch einige Dinge, die ich nicht verstehe. 1) Es scheint, dass die Benutzeroberfläche des Panels aus ['JPanel.getUI()'] (http://docs.oracle.com/javase/7/docs/api/javax/swing/JPanel.html#getUI%28) stammt % 29), ist das richtig? 2) Warum sollte eine 'JComponent' nicht einen eigenen UI-Delegaten haben (haben)? 3) Sollte ich meine eigenen Fragen zu diesen Fragen stellen? –

+0

Eine 'JComponent' hat keinen Delegaten selbst, aber sie stellt eine grundlegende Infrastruktur für Unterklassen bereit, die dies tun. [* Wie schreibe ich eine benutzerdefinierte Swing-Komponente *] (http://today.java.net/pub/a/today/2007/02/22/how-to-write-custom-swing-component.html) ist ein Beispiel. – trashgod

6

Es ist eine einfache Möglichkeit, Double Buffering zu tun.

Lassen Sie mich etwas näher ausführen. Um in Videospielen das durch Neuzeichnen verursachte Flimmern zu vermeiden und glattere Grafiken anzuzeigen, verwenden Leute normalerweise eine doppelte Pufferung. Sie erstellen eine Offscreen-Oberfläche, zeichnen alles darauf und zeigen dann die gesamte Off-Screen-Oberfläche auf dem Bildschirm auf einmal an.

Double Buffering

In Java2D und Swing, der einfachste Weg, dies zu tun, ist zu Ihrem Spiel Sprit Zeichnung auf einem JPanel einfach tun, und fügen Sie dann den JPanel zu einem JFrame.

Zweitens, indem Sie Dinge auf einem JPanel zeichnen, erlauben Sie, dass mehr GUI-Widgets und andere grafische Objekte auf dem JFrame angezeigt werden, ohne dass Sie sie manuell in der Spielschleife malen müssen. Zum Beispiel Buttons, Menüs, andere Panels, sogar andere Rendering JPanels.

Drittens ermöglicht es Ihnen, automatisch übersetzte Koordinaten für Ihr Spiel zu verwenden. Sie können alles von oben links nach unten rechts zeichnen, ohne sich um die Fenstermanager-spezifischen Dinge wie Fensterrahmenbreiten, Aufgabenbereiche, Titel usw. kümmern zu müssen!

translated co-ordinates

Darüber hinaus ist dies nicht nur eine Konvention nur von Game Programmierer in Java verwendet. Erstellen eines separaten Spiel Board, Rendern Panel oder Grafik Widget ist sehr beliebt bei der Programmierung von Spielen mit einer Bibliothek mit einer internen Hauptschleife wie ein GUI-Toolkit. Sie können ein Benutzerformular in Windows Forms und ein Zeichenbrett in GTK + verwenden.

+0

Ein Bild auf einem JPanel zu zeichnen und dann das JPanel zu dem JFrame hinzuzufügen, ist nicht, wie Doppelpufferung durchzuführen. Ich bin mir ziemlich sicher, dass Sie in einem JFrame doppelt puffern können. – Richante

+0

@Richante Ich weiß sehr gut, Sie können Puffer in einem JFrame doppelt, was ich sagte, war mit einem JPanel ist der _easiest_ Weg, nicht die _only_ Möglichkeit, Doppel-Pufferung mit Java2D und Swing. – ApprenticeHacker

+0

@Richante auch, warum ist es nicht eine Möglichkeit, Doppel-Pufferung zu tun? Es wird ziemlich oft für genau diesen Zweck verwendet. – ApprenticeHacker

5

Der JFrame enthält Dinge wie das Menü, Titelleiste und Rahmen. Wenn Sie also auf Koordinaten verweisen, müssen Sie diese berücksichtigen. Sie können auch entscheiden, dem Rahmen eine Menüleiste oder andere Komponenten hinzuzufügen. Wenn sich Ihr Bild in einem JPanel befindet, ändert sich nicht, wie Sie auf Koordinaten verweisen müssen.

Zum Beispiel versuchen:

public class Test extends JFrame { 

public Test() { 
    super(); 
    setVisible(true); 
    setBounds(100, 100, 200, 100); 
} 

@Override 
public void paint(Graphics g) { 
    g.fillRect(0, 0, 50, 50); 
} 

public static void main(String[] args) { 
    new Test(); 
} 

} 

und Sie werden sehen, dass das schwarze Quadrat nicht quadratisch ist! Denn (0, 0) ist die obere linke Ecke des gesamten Rahmens, nicht die Ecke des sichtbaren Bereichs.