J'ai un JPanel auquel j'aimerais ajouter des images JPEG et PNG que je génère à la volée.
Tous les exemples que j'ai vus jusqu'à présent dans les didacticiels Swing , spécialement dans les exemples Swing, utilisent ImageIcon
s.
Je génère ces images sous forme de tableaux d'octets, et elles sont généralement plus grandes que l'icône commune qu'elles utilisent dans les exemples, à 640x480.
- Existe-t-il un problème (de performance ou autre) dans l'utilisation de la classe ImageIcon pour afficher une image de cette taille dans un JPanel?
- Quelle est la manière habituelle de procéder?
- Comment ajouter une image à un JPanel sans utiliser la classe ImageIcon?
Edit : Un examen plus attentif des didacticiels et de l'API montre que vous ne pouvez pas ajouter un ImageIcon directement à un JPanel. Au lieu de cela, ils obtiennent le même effet en définissant l'image comme une icône d'un JLabel. Cela ne me semble pas juste ...
MemoryImageSource
que de les convertir au format JPEG ou PNG, puis de les lireImageIO
comme le suggèrent la plupart des réponses. Vous pouvez obtenir un àImage
partir d'unMemoryImageSource
construit avec vos données d'image en utilisantcreateImage
et afficher comme suggéré dans l'une des réponses.Réponses:
Voici comment je le fais (avec un peu plus d'informations sur la façon de charger une image):
la source
Principle of Encapsulation
méthodes depaintComponent(...)
protected
public
Principle of Encapsulation
. N'oubliez pas que pendant la programmation, ce qui doit être caché du reste du code doit être conservé de cette façon, au lieu d'être visible par tout dans le code. On dirait que c'est une chose qui vient avec l'expérience, comme on apprend chaque jour. N'importe quel livre peut donner une idée de base de ce qu'est l'encapsulation, mais c'est la façon dont nous mettons en œuvre notre code qui décide de notre adhésion au concept.Si vous utilisez JPanels, vous travaillez probablement avec Swing. Essaye ça:
L'image est maintenant un composant swing. Il devient soumis à des conditions de mise en page comme tout autre composant.
la source
La manière de Fred Haslam fonctionne bien. J'ai cependant eu des problèmes avec le chemin du fichier, car je veux référencer une image dans mon pot. Pour ce faire, j'ai utilisé:
Étant donné que je n'ai qu'un nombre fini (environ 10) d'images que je dois charger à l'aide de cette méthode, cela fonctionne très bien. Il obtient le fichier sans avoir à avoir le chemin de fichier relatif correct.
la source
BufferedImage previewImage = ImageIO.read(new URL(imageURL));
pour récupérer mes images depuis un serveur.Je pense qu'il n'est pas nécessaire de sous-classer quoi que ce soit. Utilisez simplement un Jlabel. Vous pouvez définir une image dans un Jlabel. Donc, redimensionnez le Jlabel puis remplissez-le avec une image. C'est bon. C'est ma façon de faire.
la source
Vous pouvez éviter de rouler complètement votre propre sous-classe Component en utilisant la classe JXImagePanel des bibliothèques SwingX gratuites .
Télécharger
la source
la source
Vous pouvez sous-classer JPanel - voici un extrait de mon ImagePanel, qui met une image dans l'un des 5 emplacements, haut / gauche, haut / droite, milieu / milieu, bas / gauche ou bas / droite:
la source
ImageIcon
. Pour une seule image, je penserais à créer une sous-classe personnaliséeJPanel
et à remplacer sapaintComponent
méthode pour dessiner l'image.la source
JPanel
est presque toujours la mauvaise classe à sous-classer. Pourquoi ne sousJComponent
- classeriez-vous pas ?Il y a un léger problème avec le fait
ImageIcon
que le constructeur bloque la lecture de l'image. Pas vraiment un problème lors du chargement à partir du pot d'application, mais peut-être si vous lisez potentiellement sur une connexion réseau. Il existe de nombreux exemples d'utilisation de l'ère AWTMediaTracker
,ImageObserver
et des amis, même dans les démos JDK.la source
Je fais quelque chose de très similaire dans un projet privé sur lequel je travaille. Jusqu'à présent, j'ai généré des images jusqu'à 1024x1024 sans aucun problème (sauf la mémoire) et je peux les afficher très rapidement et sans aucun problème de performances.
Remplacer la méthode de peinture de la sous-classe JPanel est exagéré et nécessite plus de travail que vous n'en avez besoin.
Ma façon de procéder est:
OU
Le code que vous utilisez pour générer l'image sera dans cette classe. J'utilise un BufferedImage pour dessiner puis lorsque le paintIcon () est appelé, utilisez g.drawImvge (bufferedImage); Cela réduit la quantité de clignotement effectuée pendant que vous générez vos images et vous pouvez les enfiler.
J'étends ensuite JLabel:
C'est parce que je veux mettre mon image dans un volet de défilement, c'est-à-dire afficher une partie de l'image et faire défiler l'utilisateur au besoin.
Alors j'utilise un JScrollPane pour contenir le MapLabel, qui ne contient que le MapIcon.
Mais pour votre scénario (montrez l'image entière à chaque fois). Vous devez ajouter le MapLabel au JPanel supérieur et assurez-vous de les redimensionner tous à la taille complète de l'image (en remplaçant GetPreferredSize ()).
la source
Créez un dossier source dans votre répertoire de projet, dans ce cas je l'ai appelé Images.
la source
Vous pouvez éviter d'utiliser sa propre
Component
bibliothèque etImageIO
classe s et SwingX :la source
Cette réponse est un complément à la réponse de @ shawalli ...
Je voulais aussi référencer une image dans mon pot, mais au lieu d'avoir une BufferedImage, j'ai simplement fait ceci:
la source
Je peux voir beaucoup de réponses, ne répondant pas vraiment aux trois questions du PO.
1) Un mot sur les performances: les tableaux d'octets sont probablement inefficaces, sauf si vous pouvez utiliser un ordre d'octets de pixels exact qui correspond à la résolution actuelle et à la profondeur de couleur de vos cartes graphiques.
Pour obtenir les meilleures performances de dessin, il vous suffit de convertir votre image en une BufferedImage qui est générée avec un type correspondant à votre configuration graphique actuelle. Voir createCompatibleImage sur https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
Ces images seront automatiquement mises en cache sur la mémoire de la carte graphique après avoir dessiné plusieurs fois sans aucun effort de programmation (ceci est standard dans Swing depuis Java 6), et donc le dessin réel prendra un temps négligeable - si vous n'avez pas changé l'image .
La modification de l'image entraînera un transfert de mémoire supplémentaire entre la mémoire principale et la mémoire GPU - ce qui est lent. Évitez de "redessiner" l'image en une BufferedImage, évitez donc de faire getPixel et setPixel par tous les moyens.
Par exemple, si vous développez un jeu, au lieu de dessiner tous les acteurs du jeu sur une BufferedImage puis sur un JPanel, il est beaucoup plus rapide de charger tous les acteurs sous forme de BufferedImages plus petits et de les dessiner un par un dans votre code JPanel à leur position correcte - de cette façon, il n'y a pas de transfert de données supplémentaires entre la mémoire principale et la mémoire GPU, à l'exception du transfert initial des images pour la mise en cache.
ImageIcon utilisera une BufferedImage sous le capot - mais en gros, allouer une BufferedImage avec le bon mode graphique est la clé, et il n'y a aucun effort pour le faire correctement.
2) La manière habituelle de procéder est de dessiner une BufferedImage dans une méthode paintComponent surchargée de JPanel. Bien que Java prenne en charge une grande quantité de fonctionnalités supplémentaires telles que les chaînes de tampons contrôlant les images volatiles mises en cache dans la mémoire du GPU, il n'est pas nécessaire d'utiliser ces éléments depuis Java 6 qui fait un travail raisonnablement bon sans exposer tous ces détails de l'accélération du GPU.
Notez que l'accélération GPU peut ne pas fonctionner pour certaines opérations, telles que l'étirement d'images translucides.
3) N'ajoutez pas. Il suffit de le peindre comme mentionné ci-dessus:
"Ajouter" est logique si l'image fait partie de la mise en page. Si vous en avez besoin en tant qu'image d'arrière-plan ou de premier plan remplissant le JPanel, dessinez simplement paintComponent. Si vous préférez brasser un composant Swing générique qui peut montrer votre image, il est alors la même histoire (vous pouvez utiliser un JComponent et remplacer la méthode de paintComponent) - puis ajoutez ce à votre disposition des composants GUI.
4) Comment convertir le tableau en une image tampon
La conversion de vos tableaux d'octets en PNG, puis leur chargement nécessitent beaucoup de ressources. Une meilleure façon est de convertir votre tableau d'octets existant en BufferedImage.
Pour cela: ne pas utiliser pour les boucles et copier les pixels. C'est très très lent. Au lieu:
la source