Frage

Ich habe einen JPanel zu denen ich möchte JPEG und PNG-Bilder hinzufügen, die ich on the fly generieren.

Alle Beispiele, die ich bisher in der Swing-Tutorials , speziell in den Swing-Beispiele ImageIcons verwenden.

Ich bin zu erzeugen diese Bilder als Byte-Arrays, und sie sind in der Regel größer als das gemeinsame Symbol sie in den Beispielen verwendet werden, bei 640x480.

  1. Gibt es eine (Leistung oder anderes) Problem die ImageIcon Klasse bei der Verwendung ein Bild anzuzeigen, dass Größe in einem JPanel?
  2. Was ist die übliche Art und Weise, es zu tun?
  3. Wie ein Bild zu einem JPanel hinzuzufügen, ohne die ImageIcon-Klasse?

Bearbeiten : Eine sorgfältigere Prüfung der Übungen und die API zeigt, dass Sie nicht eine ImageIcon direkt zu einem JPanel hinzufügen können. Stattdessen erreichen sie die gleiche Wirkung durch das Bild als Symbol einer JLabel Einstellung. Das betrifft nicht nur das Gefühl, richtig ...

War es hilfreich?

Lösung

Hier ist, wie ich es tun (mit einem wenig mehr Informationen darüber, wie ein Bild laden):

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel{

    private BufferedImage image;

    public ImagePanel() {
       try {                
          image = ImageIO.read(new File("image name and path"));
       } catch (IOException ex) {
            // handle exception...
       }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this); // see javadoc for more info on the parameters            
    }

}

Andere Tipps

Wenn Sie JPanels verwenden, arbeiten dann wahrscheinlich mit Schaukel. Versuchen Sie folgendes:

BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);

Das Bild ist jetzt eine Swing-Komponente. Es wird unter Layout Bedingungen wie jede andere Komponente.

Fred Haslam Weg funktioniert gut. Ich hatte Probleme mit dem filepath obwohl, da ich ein Bild in meinem Glas verweisen möchten. Um dies zu tun, habe ich:

BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));

Da ich nur eine endliche Anzahl (etwa 10) Bilder, die ich brauche, diese Methode zu laden verwenden, funktioniert es ganz gut. Es wird Datei ohne den richtigen relativen Dateipfad müssen.

Ich denke, es ist nicht nötig, etwas zu Unterklasse. Verwenden Sie einfach ein JLabel. Sie können ein Bild in ein JLabel gesetzt. Also, die Größe des JLabel dann füllen Sie es mit einem Bild. Es ist in Ordnung. Dies ist die Art, wie ich tun.

Sie können verhindern, dass Ihre eigene Komponente Unterklasse rollt vollständig durch die JXImagePanel Klasse von den freien Verwendung SwingX Bibliotheken.

Herunterladen

JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));
  1. Es sollte nicht ein Problem (außer alle allgemeinen Probleme, die Sie mit sehr großen Bildern haben könnte).
  2. Wenn Sie sprechen mehrere Bilder zu einem einzigen Panel hinzufügen, würde ich ImageIcons verwenden. Für ein einzelnes Bild, würde ich darüber nachdenken, eine benutzerdefinierte Unterklasse von JPanel machen und überschreibt seine paintComponent Methode um das Bild zu zeichnen.
  3. (siehe 2)

Sie können JPanel Unterklasse - hier ist ein Auszug aus meinem ImagePanel, die ein Bild in einem der 5 Standorte versetzt, oben / links, oben / rechts, Mitte / Mitte, unten / links oder unten / rechts:

protected void paintComponent(Graphics gc) {
    super.paintComponent(gc);

    Dimension                           cs=getSize();                           // component size

    gc=gc.create();
    gc.clipRect(insets.left,insets.top,(cs.width-insets.left-insets.right),(cs.height-insets.top-insets.bottom));
    if(mmImage!=null) { gc.drawImage(mmImage,(((cs.width-mmSize.width)/2)       +mmHrzShift),(((cs.height-mmSize.height)/2)        +mmVrtShift),null); }
    if(tlImage!=null) { gc.drawImage(tlImage,(insets.left                       +tlHrzShift),(insets.top                           +tlVrtShift),null); }
    if(trImage!=null) { gc.drawImage(trImage,(cs.width-insets.right-trSize.width+trHrzShift),(insets.top                           +trVrtShift),null); }
    if(blImage!=null) { gc.drawImage(blImage,(insets.left                       +blHrzShift),(cs.height-insets.bottom-blSize.height+blVrtShift),null); }
    if(brImage!=null) { gc.drawImage(brImage,(cs.width-insets.right-brSize.width+brHrzShift),(cs.height-insets.bottom-brSize.height+brVrtShift),null); }
    }

JPanel ist fast immer die falsche Klasse, Unterklasse. Warum würden Sie nicht JComponent Unterklasse?

Es gibt ein kleines Problem mit ImageIcon dadurch, dass die Konstruktor Blöcken das Bild zu lesen. Nicht wirklich ein Problem beim Laden von der Anwendung Glas, aber vielleicht, wenn Sie lesen möglicherweise über eine Netzwerkverbindung. Es gibt viele AWT-Ära Beispiele für die Verwendung MediaTracker, ImageObserver und Freunde, auch in den JDK-Demos.

Ich mache etwas sehr ähnliches in einem privaten Projekt arbeite ich an. Bis jetzt habe ich Bilder erzeugt bis zu 1024x1024 ohne Probleme (außer Speicher) und kann sie sehr schnell und ohne Performance-Probleme anzuzeigen.

Überschreiben der paint-Methode von JPanel Unterklasse ist übertrieben und mehr erfordert Arbeit, als Sie tun müssen.

So wie ich es tun, ist:

Class MapIcon implements Icon {...}

oder

Class MapIcon extends ImageIcon {...}

Der Code, den Sie auf das Bild zu erzeugen verwenden, um in dieser Klasse sein. Ich benutze eine BufferedImage auf dann zu ziehen, wenn der paintIcon () aufgerufen wird, verwenden g.drawImvge (BufferedImage); Dies reduziert die Menge an getan blinkt, während Sie Ihre Bilder zu erzeugen, und Sie können es fädeln.

Als nächstes richte ich JLabel:

Class MapLabel extends Scrollable, MouseMotionListener {...}

Das ist, weil ich mein Bild setzen auf einem Bildlauffenster will, das heißt Anzeigeteil des Bildes und haben die Benutzer blättern um je nach Bedarf.

So dann verwende ich eine JScrollPane die MapLabel zu halten, die nur die MapIcon enthält.

MapIcon map = new MapIcon (); 
MapLabel mapLabel = new MapLabel (map);
JScrollPane scrollPane = new JScrollPane();

scrollPane.getViewport ().add (mapLabel);

Aber für Ihr Szenario (nur zeigen, das ganze Bild jedes Mal). Sie müssen die MapLabel nach oben JPanel hinzuzufügen, und stellen Sie sicher, sie alle auf die volle Größe des Bildes Größe (durch die GetPreferredSize zwingende ()).

Erstellen Sie einen Quellordner in Ihrem Projektverzeichnis, in diesem Fall habe ich es Bilder genannt.

JFrame snakeFrame = new JFrame();
snakeFrame.setBounds(100, 200, 800, 800);
snakeFrame.setVisible(true);
snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png")));
snakeFrame.pack();

Diese Antwort ist eine Ergänzung zu @ shawalli Antwort ...

Ich wollte auch ein Bild in meinem Glas verweisen, sondern stattdessen eine BufferedImage zu haben, ich einfach tat dies:

 JPanel jPanel = new JPanel();      
 jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));

Sie vermeiden können eigenen Components und SwingX Bibliothek und ImageIO-Klasse:

File f = new File("hello.jpg");
JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));

kann ich viele Antworten sehen, nicht wirklich die drei Fragen des OP-Adressierung.

1) Ein Wort auf die Leistung: Byte-Arrays sind wahrscheinlich unefficient, wenn Sie eine exakte Pixel Bytereihenfolge verwenden können, welche Adapter auf Ihrem Display die aktuelle Auflösung und Farbtiefe entspricht.

die beste Darstellungs-Performance zu erreichen, einfach Ihr Bild in eine BufferedImage konvertieren, die mit einer Art erzeugt wird, um Ihre aktuelle Grafikkonfiguration entspricht. Siehe createCompatibleImage unter https://docs.oracle.com/javase/tutorial /2d/images/drawonimage.html

werden diese Bilder automatisch auf der Speichergrafikkarte zwischengespeichert werden, nachdem ein paar Mal ohne Programmieraufwand Zeichnung (dies in Swing seit Java 6 Standard ist), und damit die tatsächliche Zeichnung vernachlässigbare Menge an Zeit in Anspruch nehmen - if Sie nicht das Bild ändern.

das Bild Ändern wird mit einem zusätzlichen Speichertransfer zwischen dem Hauptspeicher und GPU-Speicher kommen - was langsam ist. Vermeiden Sie „Nachziehen“ das Bild in ein BufferedImage daher vermeiden getPixel und setPixel auf allen Mitteln zu tun.

Zum Beispiel, wenn Sie ein Spiel entwickeln, statt zeichnen alle Spiel Akteure an einen BufferedImage und dann zu einem JPanel, ist es viel schneller alle Akteure als kleiner BufferedImages zu laden, und ziehen sie eins nach dem anderen in Ihrem JPanel Code in ihrer richtigen Position bringen. - so gibt es keine zusätzliche Datenübertragung zwischen dem Hauptspeicher und GPU-Speicher mit Ausnahme der anfänglichen Übertragung der Bilder für das Caching

ImageIcon eine BufferedImage unter der Haube verwenden -. Aber im Grunde eine BufferedImage mit dem korrekter Zuweisung Grafik-Modus ist der Schlüssel, und es gibt keine Mühe, dieses Recht zu tun

2) Der üblicher Weg, dies zu tun, ist ein BufferedImage in einer überschriebenen Methode paintcomponent des JPanel zu ziehen. Obwohl Java eine gute Menge an zusätzlichen Goodies wie Pufferketten unterstützt VolatileImages im Cache in dem GPU-Speicher zu steuern, gibt es keine Notwendigkeit, 6 eine dieser seit Java zu verwenden, die eine einigermaßen gute Arbeit leistet, ohne all diese Details von GPU-Beschleunigung ausgesetzt wird.

, dass die GPU-Beschleunigung Hinweis für bestimmte Operationen kann nicht funktionieren, wie Strecken durchscheinend Bilder.

3) nicht hinzufügen. malen Sie es einfach wie oben erwähnt:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image, 0, 0, this); 
}

„Hinzufügen“ macht Sinn, wenn das Bild Teil des Layouts ist. Wenn Sie dies als Hintergrund oder Vordergrundbild Füllen des JPanel benötigen, ziehen gerade in paintcomponent. Wenn Sie eine generische Swing-Komponente bevorzugen brauen, die Ihr Bild zeigen kann, dann ist es die gleiche Geschichte (Sie JComponent verwenden kann und seine paintcomponent-Methode überschreiben) - und fügen Sie dann diese in Ihr Layout von GUI-Komponenten .

4) Wie das Array zu einem BufferedImage konvertieren

Konvertieren Sie Ihre Byte-Arrays zu PNG, dann lade es ist ziemlich ressourcenintensiv. Ein besserer Weg ist Ihr bestehendes Byte-Array zu einem BufferedImage zu konvertieren.

Für das: nicht für Loops verwenden und kopieren Pixel. Das ist sehr, sehr langsam. Statt dessen:

  • erfahren die bevorzugte Byte Struktur des BufferedImage (heute ist es sicher RGB oder RGBA zu übernehmen, die 4 Bytes pro Pixel)
  • lernen, die Scanlinie und scansize im Einsatz (zB Sie könnten ein 142 Pixel breites Bild - aber im wirklichen Leben, die als 256 Pixel breit Byte-Array gespeichert werden, da es schneller ist, dass zu verarbeiten und maskieren die ungenutzten pixes durch die GPU Hardware)
  • dann, wenn Sie ein Array Build haben diese Grundsätze nach, kann die setRGB Array Methode des BufferedImage kopieren Sie Ihre Array auf die BufferedImage.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top