Eu tenho um JPanel ao qual gostaria de adicionar imagens JPEG e PNG que eu gere em tempo real.
Todos os exemplos que eu vi até agora nos tutoriais do Swing , especialmente nos exemplos do Swing, usam ImageIcon
s.
Estou gerando essas imagens como matrizes de bytes e geralmente são maiores que o ícone comum usado nos exemplos, em 640x480.
- Existe algum problema (desempenho ou outro) no uso da classe ImageIcon para exibir uma imagem desse tamanho em um JPanel?
- Qual é a maneira usual de fazer isso?
- Como adicionar uma imagem a um JPanel sem usar a classe ImageIcon?
Editar : um exame mais cuidadoso dos tutoriais e da API mostra que você não pode adicionar um ImageIcon diretamente a um JPanel. Em vez disso, eles atingem o mesmo efeito configurando a imagem como um ícone de um JLabel. Isso simplesmente não parece certo ...
MemoryImageSource
do que convertê-las para o formato JPEG ou PNG e ler com aImageIO
maioria das respostas. Você pode obter umImage
deMemoryImageSource
seus dados de imagem usandocreateImage
e exibir conforme sugerido em uma das respostas.Respostas:
Aqui está como eu faço isso (com um pouco mais de informações sobre como carregar uma imagem):
fonte
Principle of Encapsulation
métodos enquanto primordial da classe Super, o especificador de acesso dopaintComponent(...)
método éprotected
e nãopublic
:-)Principle of Encapsulation
. Lembre-se de que durante a programação, o que deve estar oculto no restante do código, precisa ser mantido dessa maneira, em vez de ser visível para tudo no código. Parece que é algo que vem com a experiência, como se aprende a cada dia. Qualquer livro pode dar uma idéia básica do que é encapsulamento, mas é como implementamos nosso código que decide o quanto aderimos ao conceito.Se você estiver usando o JPanels, provavelmente está trabalhando com o Swing. Tente o seguinte:
A imagem agora é um componente de oscilação. Torna-se sujeito a condições de layout como qualquer outro componente.
fonte
O jeito de Fred Haslam funciona bem. No entanto, tive problemas com o caminho do arquivo, pois quero fazer referência a uma imagem dentro do meu jar. Para fazer isso, eu usei:
Como só tenho um número finito (cerca de 10) de imagens que preciso carregar usando esse método, ele funciona muito bem. Ele obtém o arquivo sem ter que ter o caminho de arquivo relativo correto.
fonte
BufferedImage previewImage = ImageIO.read(new URL(imageURL));
para obter minhas imagens de um servidor.Eu acho que não há necessidade de subclasse de nada. Basta usar um Jlabel. Você pode definir uma imagem em um Jlabel. Então, redimensione o Jlabel e preencha-o com uma imagem. Está certo. É assim que eu faço.
fonte
Você pode evitar a rolagem de sua própria subclasse Component completamente usando a classe JXImagePanel das bibliotecas gratuitas SwingX .
Baixar
fonte
fonte
Você pode subclassificar o JPanel - aqui está um extrato do meu ImagePanel, que coloca uma imagem em qualquer um dos 5 locais: superior / esquerdo, superior / direito, meio / meio, inferior / esquerdo ou inferior / direito:
fonte
ImageIcon
s. Para uma única imagem, eu pensaria em criar uma subclasse personalizadaJPanel
e substituir seupaintComponent
método para desenhar a imagem.fonte
JPanel
quase sempre é a classe errada para subclasse. Por que você não subclasseJComponent
?Há um pequeno problema com o
ImageIcon
fato de o construtor bloquear a leitura da imagem. Não é realmente um problema ao carregar a partir do jar do aplicativo, mas talvez se você estiver lendo potencialmente em uma conexão de rede. Há uma abundância de exemplos AWT-era de usarMediaTracker
,ImageObserver
e amigos, mesmo nos demos JDK.fonte
Estou fazendo algo muito semelhante em um projeto particular em que estou trabalhando. Até agora, eu gerei imagens de até 1024x1024 sem problemas (exceto memória) e posso exibi-las muito rapidamente e sem problemas de desempenho.
A substituição do método de pintura da subclasse JPanel é um exagero e requer mais trabalho do que você precisa.
O jeito que eu faço é:
OU
O código que você usa para gerar a imagem estará nesta classe. Eu uso um BufferedImage para chamar então quando o paintIcon () é chamado, use g.drawImvge (bufferedImage); Isso reduz a quantidade de flashes efetuados enquanto você gera suas imagens, e você pode encadear.
Em seguida, estendo o JLabel:
Isso ocorre porque eu quero colocar minha imagem em um painel de rolagem, ou seja, exibir parte da imagem e fazer com que o usuário role conforme necessário.
Então, eu uso um JScrollPane para armazenar o MapLabel, que contém apenas o MapIcon.
Mas para o seu cenário (apenas mostre toda a imagem). Você precisa adicionar o MapLabel ao JPanel superior e dimensioná-los todos para o tamanho total da imagem (substituindo GetPreferredSize ()).
fonte
Crie uma pasta de origem no diretório do seu projeto, neste caso eu chamei de Imagens.
fonte
Você pode evitar usar a própria
Component
biblioteca eImageIO
classe SwingX :fonte
Esta resposta é um complemento para a resposta de @ shawalli ...
Eu também queria fazer referência a uma imagem dentro do meu jar, mas em vez de ter uma BufferedImage, fiz isso simplesmente:
fonte
Eu posso ver muitas respostas, não abordando realmente as três perguntas do OP.
1) Uma palavra sobre desempenho: é provável que as matrizes de bytes sejam ineficientes, a menos que você possa usar uma ordem exata de bytes de pixel que corresponda aos seus adaptadores de vídeo na resolução e profundidade de cores atuais.
Para obter o melhor desempenho de desenho, basta converter sua imagem em uma BufferedImage que é gerada com um tipo correspondente à sua configuração gráfica atual. Consulte createCompatibleImage em https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
Essas imagens serão armazenadas em cache automaticamente na memória da placa de vídeo depois de desenhar algumas vezes sem nenhum esforço de programação (isso é padrão no Swing desde Java 6) e, portanto, o desenho real levará um tempo insignificante - se você não alterar a imagem .
A alteração da imagem vem com uma transferência de memória adicional entre a memória principal e a memória da GPU - que é lenta. Evite "redesenhar" a imagem em um BufferedImage, portanto, evite getPixel e setPixel de todas as formas.
Por exemplo, se você estiver desenvolvendo um jogo, em vez de desenhar todos os atores do jogo para uma BufferedImage e depois para um JPanel, é muito mais rápido carregar todos os atores como BufferedImages menores e desenhá-los um a um no seu código JPanel em sua posição correta - dessa forma, não há transferência de dados adicional entre a memória principal e a memória da GPU, exceto a transferência inicial das imagens para armazenamento em cache.
O ImageIcon usará uma BufferedImage sob o capô - mas basicamente a alocação de uma BufferedImage com o modo gráfico adequado é a chave, e não há esforço para fazer isso corretamente.
2) A maneira usual de fazer isso é desenhar uma BufferedImage em um método paintComponent substituído do JPanel. Embora o Java suporte uma boa quantidade de itens adicionais, como cadeias de buffer que controlam o VolatileImages armazenadas em cache na memória da GPU, não há necessidade de usá-las, pois o Java 6 faz um trabalho razoavelmente bom sem expor todos esses detalhes da aceleração da GPU.
Observe que a aceleração da GPU pode não funcionar em determinadas operações, como esticar imagens translúcidas.
3) Não adicione. Basta pintá-lo como mencionado acima:
"Adicionar" faz sentido se a imagem fizer parte do layout. Se você precisar disso como uma imagem de plano de fundo ou primeiro plano preenchendo o JPanel, basta desenhar o paintComponent. Se você preferir criar um componente Swing genérico que possa mostrar sua imagem, é a mesma história (você pode usar um JComponent e substituir seu método paintComponent) - e depois adicioná- lo ao seu layout de componentes da GUI.
4) Como converter a matriz em uma imagem em buffer
Converter suas matrizes de bytes em PNG e carregá-las consome bastante recursos. Uma maneira melhor é converter sua matriz de bytes existente em uma BufferedImage.
Para isso: não use para loops e copie pixels. Isso é muito, muito lento. Em vez de:
fonte