(Java) Aparecendo / Disappearing JLabel em um JPanel única desaparece em redimensionar
Pergunta
Eu estou trabalhando em Java, e eu tenho um JPanel em um JFrame. Nesse JPanel, entre outras coisas, eu tenho um JLabel que eu quero fazer aparecer e desaparecer à vontade. Eu tentei configurar a visibilidade para true / false, adicionando e removendo-o do JFrame e JPanel, e, tendo parecia on-line, eu tentei validate () ing e revalidate () ing ad infinitum. O que pode ser feito aqui para resolver este problema?
Solução
Em geral, chamando o método setVisible
é suficiente para fazer um componente Swing para ser mostrado ou oculto.
Só para ter certeza de que ele funciona, eu tentei o seguinte:
public class Visibility {
private void makeGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel l = new JLabel("Hello");
final JButton b = new JButton("Hide Label");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
l.setVisible(false);
}
});
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(l, BorderLayout.CENTER);
f.getContentPane().add(b, BorderLayout.SOUTH);
f.setSize(200, 200);
f.setLocation(200, 200);
f.validate();
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Visibility().makeGUI();
}
});
}
}
O programa acima é capaz de afetar a visibilidade ao clicar em um JButton
.
Poderia ser um problema de segmentação?
Meu próximo suspeita era de que talvez um Thread
que não está no segmento de eventos expedição (EDT) não pode estar afetando a exibição imediatamente, então eu adicionei o seguinte depois de inicializar o JLabel
e JButton
.
Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
b.setVisible(!b.isVisible());
try {
Thread.sleep(100);
} catch (InterruptedException e) { /* Handle exception /* }
}
}
});
t.start();
Com o novo Thread
execução, ele mudou o alternado a visibilidade do JLabel
cada 100 ms, e isso também funcionou sem problema.
Chamar um componente Swing fora do segmento de eventos expedição (EDT ) é uma coisa ruim, como balanço não é thread-safe. Eu estava um pouco surpreso que funcionou, e o fato de que ele funciona pode ser apenas um acaso .
repintar o JPanel
?
Se a visibilidade do JLabel
única está sendo afetado em redimensionamento, isso provavelmente significa que o JLabel
está sendo desenhado somente quando o JPanel
está sendo redesenhada.
Uma coisa é tentar chamar do JPanel
repaint
método para ver se a visibilidade do JLabel
vai mudar.
Mas este método parece ser apenas um band-aid para uma situação, se a principal causa é devido a um fio fora do EDT está tentando fazer alterações no GUI. (Assim como uma nota, o método repaint
é thread-safe, para que ele possa ser chamado por tópicos off-EDT, mas contando com repaint
é uma solução do que uma solução.)
Tente usar SwingUtilities.invokeLater
Finalmente, provavelmente a coisa que eu tentaria é o SwingUtilities.invokeLater
método, que pode ser chamado (e só deve ser chamado) a partir de um fio condutor separado do EDT, se quiser afetar a GUI.
Assim, o exemplo Thread
anteriormente deve ser escrita como:
Thread t = new Thread(new Runnable() {
public void run() {
while (true) {
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
b.setVisible(!b.isVisible());
}
});
} catch (Exception e1) { /* Handle exception */ }
try {
Thread.sleep(100);
} catch (InterruptedException e) { /* Handle exception */ }
}
}
});
t.start();
Se a mudança para o GUI realmente está acontecendo em um segmento separado, então eu recomendo a leitura Lição: simultaneidade no swing de O Java Tutoriais , a fim de saber mais informações sobre como escrever bem comportando código de multi-threaded usando swing.
Outras dicas
setVisible () ou removê-lo deve funcionar bem, certifique-se que você está fazendo isso a partir do segmento de eventos expedição embora. Existem métodos de utilidade pública em EventQueue para a execução de blocos em que fio.
http: / /helpdesk.objects.com.au/java/how-do-i-update-my-gui-from-any-thread
Você precisa chamar revalidate () nos JPanel pais se você precisar de seus componentes para ser re-definidos.
Se você pode postar um exemplo que demonstra o problema que eu possa ter um olhar para isso por você.