java - poner - ¿Cómo agregar una imagen a un JPanel?
poner imagen en jlabel java (14)
- No debería haber ningún problema (aparte de cualquier problema general que pueda tener con imágenes muy grandes).
- Si está hablando de agregar varias imágenes a un solo panel, usaría
ImageIcon
s. Para una sola imagen, me gustaría hacer una subclase personalizada deJPanel
y anular su métodopaintComponent
para dibujar la imagen. - (ver 2)
Tengo un JPanel al que me gustaría agregar imágenes JPEG y PNG que genero sobre la marcha.
Todos los ejemplos que he visto hasta ahora en los Tutoriales de Swing , especialmente en los ejemplos de Swing, usan ImageIcon
s.
Estoy generando estas imágenes como matrices de bytes, y suelen ser más grandes que el icono común que usan en los ejemplos, en 640x480.
- ¿Hay algún problema (rendimiento u otro) al usar la clase ImageIcon para mostrar una imagen de ese tamaño en un JPanel?
- ¿Cuál es la forma habitual de hacerlo?
- ¿Cómo agregar una imagen a un JPanel sin usar la clase ImageIcon?
Edición : un examen más cuidadoso de los tutoriales y la API muestra que no puede agregar un ImageIcon directamente a un JPanel. En su lugar, logran el mismo efecto al configurar la imagen como un icono de un JLabel. Esto simplemente no se siente bien ...
Así es como lo hago (con un poco más de información sobre cómo cargar una imagen):
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
}
}
Cree una carpeta de origen en el directorio de su proyecto, en este caso lo llamé Imágenes.
JFrame snakeFrame = new JFrame();
snakeFrame.setBounds(100, 200, 800, 800);
snakeFrame.setVisible(true);
snakeFrame.add(new JLabel(new ImageIcon("Images/Snake.png")));
snakeFrame.pack();
Creo que no hay necesidad de subclase de nada. Sólo tiene que utilizar un Jlabel. Puede establecer una imagen en un Jlabel. Entonces, cambia el tamaño del Jlabel y luego llénalo con una imagen. Está bien. Así es como lo hago yo.
El camino de Fred Haslam funciona bien. Sin embargo, tuve problemas con la ruta de acceso, ya que quiero hacer referencia a una imagen dentro de mi tarro. Para ello, utilicé:
BufferedImage wPic = ImageIO.read(this.getClass().getResource("snow.png"));
JLabel wIcon = new JLabel(new ImageIcon(wPic));
Dado que solo tengo un número finito (aproximadamente 10) de imágenes que necesito cargar usando este método, funciona bastante bien. Obtiene el archivo sin tener que tener la ruta de archivo relativa correcta.
Esta respuesta es un complemento a la respuesta de @shawalli ...
También quería hacer referencia a una imagen dentro de mi frasco, pero en lugar de tener una imagen almacenada, simplemente hice esto:
JPanel jPanel = new JPanel();
jPanel.add(new JLabel(new ImageIcon(getClass().getClassLoader().getResource("resource/images/polygon.jpg"))));
Estoy haciendo algo muy similar en un proyecto privado en el que estoy trabajando. Hasta ahora he generado imágenes de hasta 1024x1024 sin ningún problema (excepto la memoria) y puedo mostrarlas muy rápidamente y sin ningún problema de rendimiento.
La anulación del método de pintura de la subclase JPanel es una exageración y requiere más trabajo del que necesita hacer.
La forma en que lo hago es:
Class MapIcon implements Icon {...}
O
Class MapIcon extends ImageIcon {...}
El código que usas para generar la imagen estará en esta clase. Uso un BufferedImage para dibujar y luego, cuando se llama a paintIcon (), use g.drawImvge (bufferedImage); Esto reduce la cantidad de flasheo realizado mientras genera sus imágenes, y puede enhebrarlo.
A continuación extiendo JLabel:
Class MapLabel extends Scrollable, MouseMotionListener {...}
Esto se debe a que quiero poner mi imagen en un panel de desplazamiento, es decir, mostrar parte de la imagen y hacer que el usuario se desplace según sea necesario.
Entonces, uso un JScrollPane para guardar el MapLabel, que contiene solo el MapIcon.
MapIcon map = new MapIcon ();
MapLabel mapLabel = new MapLabel (map);
JScrollPane scrollPane = new JScrollPane();
scrollPane.getViewport ().add (mapLabel);
Pero para su escenario (solo muestre la imagen completa cada vez). Debe agregar el MapLabel al JPan superior y asegurarse de que el tamaño de la imagen sea completo (anulando GetPreferredSize ()).
Puede crear una subclase de JPanel: aquí hay un extracto de mi ImagePanel, que coloca una imagen en cualquiera de las 5 ubicaciones: superior / izquierda, superior / derecha, media / media, inferior / izquierda o inferior / derecha:
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); }
}
Puede evitar el uso de la propia biblioteca de Component
s y SwingX y la clase ImageIO:
File f = new File("hello.jpg");
JLabel imgLabel = new JLabel(new ImageIcon(file.getName()));
Puedo ver muchas respuestas, sin abordar realmente las tres preguntas del OP.
1) Una palabra sobre el rendimiento: es probable que las matrices de bytes no sean eficientes a menos que pueda usar un orden de bytes de píxeles que coincida con la resolución actual y la profundidad de color de sus adaptadores de pantalla.
Para lograr el mejor rendimiento de dibujo, simplemente convierta su imagen a una imagen almacenada que se genera con un tipo correspondiente a su configuración de gráficos actual. Consulte createCompatibleImage en https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
Estas imágenes se almacenarán en caché automáticamente en la memoria de la tarjeta de visualización después de dibujar unas cuantas veces sin ningún esfuerzo de programación (esto es estándar en Swing desde Java 6) y, por lo tanto, el dibujo real tomará una cantidad de tiempo insignificante, si no cambió la imagen .
La modificación de la imagen incluirá una transferencia de memoria adicional entre la memoria principal y la memoria de la GPU, que es lenta. Evite "volver a dibujar" la imagen en un BufferedImage, por lo tanto, evite hacer getPixel y setPixel de ninguna manera.
Por ejemplo, si está desarrollando un juego, en lugar de atraer a todos los actores del juego a un BufferedImage y luego a un JPanel, es mucho más rápido cargar a todos los actores como BufferedImages más pequeños, y dibujarlos uno por uno en su código de JPanel en su posición correcta: de esta manera no hay transferencia de datos adicional entre la memoria principal y la memoria de la GPU, excepto la transferencia inicial de las imágenes para el almacenamiento en caché.
ImageIcon utilizará una imagen almacenada debajo del capó, pero básicamente la asignación de una imagen almacenada con el modo de gráficos adecuado es la clave, y no hay ningún esfuerzo para hacerlo correctamente.
2) La forma habitual de hacer esto es dibujar una imagen almacenada en BufferedImage en un método paintComponent anulado de JPanel. Aunque Java admite una buena cantidad de recursos adicionales, como cadenas de búferes que controlan VolatileImages almacenadas en caché en la memoria de la GPU, no es necesario usar ninguna de estas aplicaciones, ya que Java 6 hace un trabajo razonablemente bueno sin exponer todos estos detalles de la aceleración de la GPU.
Tenga en cuenta que la aceleración de la GPU puede no funcionar para ciertas operaciones, como estirar imágenes translúcidas.
3) No añadir. Solo píntalo como se mencionó anteriormente:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
"Agregar" tiene sentido si la imagen es parte del diseño. Si necesita esto como imagen de fondo o de primer plano que llena el JPanel, simplemente dibuje en paintComponent. Si prefiere elaborar un componente Swing genérico que pueda mostrar su imagen, entonces es la misma historia (puede usar un JComponent y anular su método paintComponent) y luego agregarlo a su diseño de componentes GUI.
4) Cómo convertir la matriz a un Bufferedimage
Convertir sus arreglos de bytes a PNG, luego cargarlos requiere bastante recursos. Una mejor manera es convertir su matriz de bytes existente en una BufferedImage.
Para eso: no utilizar para bucles y copiar píxeles. Eso es muy muy lento. En lugar:
- aprenda la estructura de bytes preferida de BufferedImage (hoy en día es seguro asumir RGB o RGBA, que es de 4 bytes por píxel)
- aprenda la línea de escaneo y el tamaño de escaneo en uso (por ejemplo, puede tener una imagen de 142 píxeles de ancho, pero en la vida real se almacenará como una matriz de bytes de 256 píxeles de ancho, ya que es más rápido procesar eso y enmascarar los píxeles no utilizados por el hardware de la GPU )
- luego, una vez que tenga una construcción de matriz de acuerdo con estos principios, el método de matriz setRGB de BufferedImage puede copiar su matriz a BufferedImage.
Si está utilizando JPanels, entonces probablemente esté trabajando con Swing. Prueba esto:
BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
add(picLabel);
La imagen es ahora un componente de swing. Se vuelve sujeto a las condiciones de diseño como cualquier otro componente.
JPanel
es casi siempre la clase incorrecta de subclase. ¿Por qué no subclasificar JComponent
?
Hay un pequeño problema con ImageIcon
porque el constructor bloquea la lectura de la imagen. No es realmente un problema al cargar desde el archivo jar de la aplicación, pero tal vez si potencialmente estás leyendo sobre una conexión de red. Hay muchos ejemplos de la era AWT de usar MediaTracker
, ImageObserver
y amigos, incluso en las demostraciones de JDK.
JLabel imgLabel = new JLabel(new ImageIcon("path_to_image.png"));