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 conjuntos de bytes, y generalmente son más grandes que el icono común que usan en los ejemplos, a 640x480.
- ¿Hay algún problema (de 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?
Editar : un examen más cuidadoso de los tutoriales y la API muestra que no puede agregar un ImageIcon directamente a un JPanel. En cambio, logran el mismo efecto al configurar la imagen como un icono de un JLabel. Esto simplemente no se siente bien ...
MemoryImageSource
que convertirlos a formato JPEG o PNG y luego leer con laImageIO
mayoría de las respuestas. Puede obtener unaImage
de unaMemoryImageSource
construida con sus datos de imagen mediante el usocreateImage
y mostrar como se sugiere en una de las respuestas.Respuestas:
Así es como lo hago (con un poco más de información sobre cómo cargar una imagen):
fuente
Principle of Encapsulation
métodos de anulación de la Superclase, el Especificador de acceso delpaintComponent(...)
método esprotected
y nopublic
:-)Principle of Encapsulation
. Solo recuerde que durante la programación, lo que debe ocultarse del resto del código debe mantenerse de esa manera, en lugar de ser visible para todo el código. Parece que es una cosa que viene con la experiencia, ya que uno aprende cada día. Cualquier libro puede dar una idea básica de qué es la encapsulación, pero es cómo implementamos nuestro código lo que decide cuánto nos adherimos al concepto.Si está utilizando JPanels, probablemente esté trabajando con Swing. Prueba esto:
La imagen ahora es un componente de swing. Está sujeto a condiciones de diseño como cualquier otro componente.
fuente
El camino de Fred Haslam funciona bien. Sin embargo, tuve problemas con la ruta de archivo, ya que quiero hacer referencia a una imagen dentro de mi jar. Para hacer esto, usé:
Como solo tengo un número finito (aproximadamente 10) de imágenes que necesito cargar con este método, funciona bastante bien. Obtiene el archivo sin tener que tener la ruta de archivo relativa correcta.
fuente
BufferedImage previewImage = ImageIO.read(new URL(imageURL));
para obtener mis imágenes de un servidor.Creo que no hay necesidad de subclase de nada. Solo usa un Jlabel. Puede configurar una imagen en una Jlabel. Entonces, cambie el tamaño de Jlabel y luego llénelo con una imagen. Está bien. Así es como lo hago.
fuente
Puede evitar rodar su propia subclase de componentes por completo utilizando la clase JXImagePanel de las bibliotecas gratuitas de SwingX .
Descargar
fuente
fuente
Puede subclasificar JPanel: aquí hay un extracto de mi ImagePanel, que coloca una imagen en cualquiera de las 5 ubicaciones, arriba / izquierda, arriba / derecha, medio / medio, abajo / izquierda o abajo / derecha:
fuente
ImageIcon
s. Para una sola imagen, pensaría en hacer una subclase personalizadaJPanel
y anular supaintComponent
método para dibujar la imagen.fuente
JPanel
casi siempre es la clase incorrecta para subclase. ¿Por qué no subclaseJComponent
?Hay un pequeño problema con
ImageIcon
que 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 estás leyendo potencialmente a través de una conexión de red. Hay un montón de ejemplos de AWT de la era de la utilizaciónMediaTracker
,ImageObserver
y amigos, incluso en las demostraciones de JDK.fuente
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.
Anular el método de pintura de la subclase JPanel es excesivo y requiere más trabajo del que necesita hacer.
La forma en que lo hago es:
O
El código que use para generar la imagen estará en esta clase. Utilizo una BufferedImage para dibujar cuando se llama a paintIcon (), uso g.drawImvge (bufferedImage); Esto reduce la cantidad de flasheo realizado mientras genera sus imágenes y puede enhebrarlo.
A continuación extiendo JLabel:
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 contener MapLabel, que contiene solo MapIcon.
Pero para su escenario (solo muestre la imagen completa cada vez). Debe agregar MapLabel al JPanel superior y asegurarse de ajustarlos a todo el tamaño de la imagen (anulando GetPreferredSize ()).
fuente
Cree una carpeta de origen en el directorio de su proyecto, en este caso lo llamé Imágenes.
fuente
Puede evitar usar su propia
Component
biblioteca yImageIO
clase de SwingX :fuente
Esta respuesta es un complemento de la respuesta de @ shawalli ...
También quería hacer referencia a una imagen dentro de mi jar, pero en lugar de tener una BufferedImage, simplemente hice esto:
fuente
Puedo ver muchas respuestas, sin abordar realmente las tres preguntas del PO.
1) Una palabra sobre el rendimiento: las matrices de bytes son probablemente poco eficientes a menos que pueda usar un orden de bytes de píxeles exacto 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 en una Imagen Buffered que se genera con un tipo correspondiente a su configuración gráfica 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 varias 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 alteración de la imagen vendrá con 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 una BufferedImage, por lo tanto, evite hacer getPixel y setPixel por todos los medios.
Por ejemplo, si está desarrollando un juego, en lugar de atraer a todos los actores del juego a una 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 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 usará una BufferedImage debajo del capó, pero básicamente la asignación de una BufferedImage con el modo gráfico adecuado es la clave, y no hay ningún esfuerzo para hacerlo correctamente.
2) La forma habitual de hacer esto es dibujar una BufferedImage en un método anulado de paintComponent del JPanel. Aunque Java admite una buena cantidad de beneficios adicionales, como cadenas de búfer que controlan VolatileImages en caché en la memoria de la GPU, no hay necesidad de usar ninguno de estos, 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 GPU puede no funcionar para ciertas operaciones, como estirar imágenes translúcidas.
3) No agregar. Solo píntalo como se mencionó anteriormente:
"Agregar" tiene sentido si la imagen es parte del diseño. Si necesita esto como una imagen de fondo o primer plano que llena el JPanel, simplemente dibuje paintComponent. Si prefiere preparar 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 agregar esto a su diseño de componentes GUI.
4) Cómo convertir la matriz a una imagen almacenada en búfer
La conversión de sus conjuntos de bytes a PNG y luego su carga requieren muchos recursos. Una mejor manera es convertir su matriz de bytes existente a una imagen almacenada.
Para eso: no lo use para bucles ni copie píxeles. Eso es muy muy lento. En lugar:
fuente