JPanel com JButton não é sobreposto por outro JPanel! (Desconfiamos de outro BUG NO JAVA)

Pessoal, alguém sabe como fazer um objeto JPanel que tem um JButton inserido conseguir adicionar um outro objeto JPanel sem que os componentes adicionados no primeiro JPanel apareçam sobre o segundo JPanel? :shock: Isso tudo usando SpringLayout?
Calma, vou tentar explicar melhor, não desista de ler! Rode o código seguinte para conseguir o primeiro sintoma:

   import javax.swing.*;   
   import java.awt.event.*;   
   import java.awt.*;   
  
   public class Janela extends JFrame  {
   
      private JPanel painelPrincipal;
      private JPanel painelSecundario;
      private JButton botaoPainelPrincipal;
   
      public Janela() {
         super("Testando sobreposição de JPanel`s");
         setDefaultCloseOperation(EXIT_ON_CLOSE);
         setSize(500,500);
         exibir();
      }
   		
      public void exibir() {
      
         SpringLayout layout = new SpringLayout();
      
         painelPrincipal = new JPanel(layout);
         painelPrincipal.setPreferredSize(new Dimension(400,400));
         painelPrincipal.setBackground(Color.BLACK);
      				
         painelSecundario = new JPanel();
         painelSecundario.setPreferredSize(new Dimension(200,200));
         painelSecundario.setBackground(Color.BLUE);
      
         botaoPainelPrincipal = new JButton("OK");
         botaoPainelPrincipal.addActionListener(
               new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                     painelPrincipal.remove(painelSecundario);
                     painelPrincipal.repaint();
                  }
               });
      
         painelPrincipal.add(botaoPainelPrincipal);
         painelPrincipal.add(painelSecundario);
         add(painelPrincipal);
      	
         setVisible(true);
      	
      }
   	
      public static void main(String args[]) {
         SwingUtilities.invokeLater(
               new Runnable() {
                  public void run() {
                     new Janela();
                  }
               });
      }
   }

Bom, você já deve ter notado que o botão (botão OK) que está adicionado no painel principal (painel em preto) é exibido como se estivesse adicionado ao painel secundário (painel azul), o que está errado. O correto seria o painel azul estar se sobrepondo à este botão, evitando que ele estivesse sendo exibido, assim como fez com parte do painel preto, porém é clara a prioridade do JButton sobre um JPanel. Muito bem, até aí, pesquisando e analisando a documentação do JPanel existe um método no qual você organiza a ordem dos componentes em um painel no qual sempre os primeiros componentes desta lista ganham a preferência sobre os últimos componentes na hora de pintá-los (mesmo sabendo que a solicitação para adicionar (add) o botão foi escrita no código primeiro que a do segundo painel, mas como Java é multithreading, justifica-se). Este método é o setComponentZOrder(Component c, int pos); Veja este novo código abaixo:

   import javax.swing.*;   
   import java.awt.event.*;   
   import java.awt.*;   
  
   public class Janela extends JFrame  {
   
      private JPanel painelPrincipal;
      private JPanel painelSecundario;
      private JButton botaoPainelPrincipal;
   
      public Janela() {
         super("Testando sobreposição de JPanel`s");
         setDefaultCloseOperation(EXIT_ON_CLOSE);
         setSize(500,500);
         exibir();
      }
   		
      public void exibir() {
      
         SpringLayout layout = new SpringLayout();
      
         painelPrincipal = new JPanel(layout);
         painelPrincipal.setPreferredSize(new Dimension(400,400));
         painelPrincipal.setBackground(Color.BLACK);
      				
         painelSecundario = new JPanel();
         painelSecundario.setPreferredSize(new Dimension(200,200));
         painelSecundario.setBackground(Color.BLUE);
      
         botaoPainelPrincipal = new JButton("OK");
         botaoPainelPrincipal.addActionListener(
               new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                     painelPrincipal.remove(painelSecundario);
                     painelPrincipal.repaint();
                  }
               });
      
         painelPrincipal.add(botaoPainelPrincipal);
         painelPrincipal.add(painelSecundario);
         add(painelPrincipal);
      	
         painelPrincipal.setComponentZOrder(painelSecundario, 0); // O método aplicado.
      	     	
         setVisible(true);
      	
      }
   	
      public static void main(String args[]) {
         SwingUtilities.invokeLater(
               new Runnable() {
                  public void run() {
                     new Janela();
                  }
               });
      }
   }

Agora sim, parece perfeito! Só parece, não é… Repare que se você passar o mouse lá no canto superior esquerdo do painel azul o botão que está inserido (e escondido) por trás vai aparecer, provocando um efeito parecido com esta imagem postada em outro tópico neste mesmo fórum:

:arrow: [size=14]E agora? BUG eu sei que não é… Parece ser uma briga por um mesmo espaço, o que vai contra as leis básicas de Física mas… existe alguma solução para que este botão não apareça enquanto o painel azul não for removido?
Não tenha pressa em responder! Só de estar desprendendo do seu tempo em ler e chegar até aqui neste momento, para mim, é mais do que qualquer resposta. Sou muito grato!
Ótimo 2012 para todos, com muita paz![/size] :smiley:

como vc vai tirar o painel sem o botão?
vc quer que ele fique invisivel mas se ao clicar onde ele está seja removido o painel?

BOA yhhik! Detalhe que deixei de escrever no tópico: o botão e a ação do botão não importam para nada no momento em que o painel azul estiver sobre ele. Simplesmente quero que ele não apareça sempre que o painel azul estiver por cima dele.
b OBS[/b]: Se você substituir o JButton por um JTextField, repare que o problema persiste de uma forma mais visível! Segue código:

   import javax.swing.*;   
   import java.awt.event.*;   
   import java.awt.*;   
  
   public class Janela extends JFrame  {
   
      private JPanel painelPrincipal;
      private JPanel painelSecundario;
      private JTextField textoPainelPrincipal;
   
      public Janela() {
         super("Testando sobreposição de JPanel`s");
         setDefaultCloseOperation(EXIT_ON_CLOSE);
         setSize(500,500);
         exibir();
      }
   		
      public void exibir() {
      
         SpringLayout layout = new SpringLayout();
      
         painelPrincipal = new JPanel(layout);
         painelPrincipal.setPreferredSize(new Dimension(400,400));
         painelPrincipal.setBackground(Color.BLACK);
      				
         painelSecundario = new JPanel();
         painelSecundario.setPreferredSize(new Dimension(200,200));
         painelSecundario.setBackground(Color.BLUE);
      
         textoPainelPrincipal = new JTextField(20);
         textoPainelPrincipal.addActionListener(
               new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                     painelPrincipal.remove(painelSecundario);
                     painelPrincipal.repaint();
                  }
               });
      
         painelPrincipal.add(textoPainelPrincipal);
         painelPrincipal.add(painelSecundario);
         add(painelPrincipal);
			
			painelPrincipal.setComponentZOrder(painelSecundario, 0);			      	
         setVisible(true);
      	
      }
   	
      public static void main(String args[]) {
         SwingUtilities.invokeLater(
               new Runnable() {
                  public void run() {
                     new Janela();
                  }
               });
      }
   }

a primeira vista a solução que eu vejo é vc dar um setVisible(false) no jbutton ou em qualquer outro componente…
para tirar o painel azul um evento terá que acontecer correto!?
quando esse evento ocorrer vc da um setVisible(true) no button.

Fala yhhik, realmente foi a única solução também que havia encontrado. :slight_smile:

Mas será que não existe mais nada que faça o JPanel se sobrepor aos demais componentes sem que eu precise mexer nos componentes que ali já estão?

Vou dar uma idéia do que gostaria que ocorresse: conhece o JToolTip não? Quando você passa o mouse sobre o botão, o ToolTip aparece e após determinado tempo, desaparece. Ele se sobrepõe ao JButtom e qualquer outro componente abaixo, mesmo o componente abaixo se mexendo como no caso de ficar passando o mouse sobre o botão com o ToolTip aparecendo. Ele continua lá visível, até o tempo estourar e desaparecer. Como ele faz isso? Na verdade, ele usa um Window combinado com um Popup, o que não é o nosso caso, mas é o nosso sonhado resultado que aconteça com os JPanel`s. Sacou a ideia?

Obrigado por estar aí firme ajudando, forte abraço!

Após mexer no painel, você chamou invalidate() nele para que ele saiba que tem que ser redesenhado, como manda a documentação? (Não sei se vai funcionar, pq não costumo a trabalhar com SpringLayout).

achei uma solução cara…
da uma olhada:[code]package snippet;

import javax.swing.*;

import java.awt.event.;
import java.awt.
;

public class Janela extends JFrame
{

private JPanel painelPrincipal;
private JPanel painelSecundario;
private JButton botaoPainelPrincipal;

public Janela() {
super(“Testando sobreposição de JPanel`s”);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500,500);
exibir();
}

public void exibir() {

  SpringLayout layout = new SpringLayout();  
 
  painelPrincipal = new JPanel(layout);  
  painelPrincipal.setPreferredSize(new Dimension(400,400));  
  painelPrincipal.setBackground(Color.BLACK);  
              
  painelSecundario = new JPanel();  
  painelSecundario.setPreferredSize(new Dimension(200,200));  
  painelSecundario.setBackground(Color.BLUE);  

 
  botaoPainelPrincipal = new JButton("OK");  
  botaoPainelPrincipal.addActionListener(  
        new ActionListener() {  
           public void actionPerformed(ActionEvent e) {  
              painelPrincipal.remove(painelSecundario);  
              painelPrincipal.repaint();  
           }  
        });  
  painelSecundario.setFocusable(true);

  
  painelSecundario.addMouseListener(new MouseListener() {   
      
      public void mouseReleased(MouseEvent e) {   
          // TODO Auto-generated method stub   
             
      }   
         
      public void mousePressed(MouseEvent e) {   
          // TODO Auto-generated method stub   
             
      }   
         
      public void mouseExited(MouseEvent e) {   
          // TODO Auto-generated method stub   
             
      }   
         
      public void mouseEntered(MouseEvent e) {   
    	   painelSecundario.setFocusable(true);  
             
      }   
         
      public void mouseClicked(MouseEvent e) {   
          // TODO Auto-generated method stub   
             
      }   
  });   
          


  painelPrincipal.add(botaoPainelPrincipal);  
  painelPrincipal.add(painelSecundario);  
 
  add(painelPrincipal);  
  painelPrincipal.setComponentZOrder(painelSecundario, 0); // O método aplicado.        
  setVisible(true);  

}

public static void main(String args[]) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
new Janela();
}
});
}

} [/code]

se vc dar um setFocusable(true); o botão some, porem se vc passar o mause em cima do botão ele aparece.
entao o que eu fiz…eu add um MouseListener no painelSecundario anulando isso…enquanto o cursor do mause estiver encima do painelsecundario ele vai dar focu para o painelSecundario deixando ele por cima.

é até simples… :lol: fiquei um tempão tentando fazer isso com thead até pensar no MouseListener…
flw vou dormir.

Uma dica. É uma má prática chamar setVisible no construtor.

Essa é uma das 15 coisas que você deveria saber ao trabalhar com Swing:
http://www.guj.com.br/java/104644-novo-em-swing#565211

Fala Vinny, bom dia! Sim, fiz o invalidate() e o validate(). A documentação também manda usar o revalidate(). Mas, infelizmente, nada…
Difícil realmente… não consigo ver solução nesse caso. Tentei coisa absurdas como adicionar um JToolTip no JPanel e ver se algo que levasse ao objetivo final acontecia… porém nada!

Abração.

Fala Yhhik, bom dia! Valew mesmo pelo esforço de ficar até tarde pensando como resolver, de fato, sua ideia resolve!

Só que tem um detalhe muito interessante que, agora, me leva a impressão de ser um novo BUG no Java! Veja só…
Fiz uma modificação simples na sua solução, observe abaixo:

   import javax.swing.*;     
   import java.awt.event.*;     
   import java.awt.*;     

  
   public class Janela  extends JFrame  
   {  
   
      private JPanel painelPrincipal;  
      private JPanel painelSecundario;  
      private JButton botaoPainelPrincipal;  
   
      public Janela() {  
         super("Testando sobreposição de JPanel`s");  
         setDefaultCloseOperation(EXIT_ON_CLOSE);  
         setSize(500,500);  
      }  
          
      public void exibir() {  
      
         SpringLayout layout = new SpringLayout();  
      
         painelPrincipal = new JPanel(layout);  
         painelPrincipal.setPreferredSize(new Dimension(400,400));  
         painelPrincipal.setBackground(Color.BLACK);  
                  
         painelSecundario = new JPanel();  
         painelSecundario.setPreferredSize(new Dimension(200,200));  
         painelSecundario.setBackground(Color.BLUE);  
      
      
         botaoPainelPrincipal = new JButton("OK");  
         botaoPainelPrincipal.addActionListener(  
               new ActionListener() {  
                  public void actionPerformed(ActionEvent e) {  
                     painelPrincipal.remove(painelSecundario);  
                     painelPrincipal.repaint();
                  }  
               });  
        // painelSecundario.setFocusable(true);					
      
         painelSecundario.addMouseListener(
               new MouseListener() {   
               
                  public void mouseReleased(MouseEvent e) {   
                  // TODO Auto-generated method stub   
                  
                  }   
               
                  public void mousePressed(MouseEvent e) {   
                  // TODO Auto-generated method stub   
                  
                  }   
               
                  public void mouseExited(MouseEvent e) {   
                  // TODO Auto-generated method stub   
                  
                  }   
               
                  public void mouseEntered(MouseEvent e) {   
                    // painelSecundario.setFocusable(true);  
                  
                  }   
               
                  public void mouseClicked(MouseEvent e) {   
                  // TODO Auto-generated method stub   
                  
                  }   
               });  
     
         painelPrincipal.add(botaoPainelPrincipal);  
         painelPrincipal.add(painelSecundario);  
      
         add(painelPrincipal);  
         painelPrincipal.setComponentZOrder(painelSecundario, 0); // O método aplicado.        
         setVisible(true);  
      
      }  
      
      public static void main(String args[]) {  
         SwingUtilities.invokeLater(  
               new Runnable() {  
                  public void run() {  
                     Janela jan = new Janela();
                     jan.exibir(); // Seguindo orientação de VinnyGodoy, retirado do construtor!
                  }  
               });  
      }
   }

O que eu fiz? Somente deixei o MouseListener aplicado ao painel. Repare que tudo que mexia com foco eu coloquei as barras de comentário e mesmo assim chegamos ao objetivo final proposto.
Tem explicação? Não seria um novo BUG?

Volto a agradecer pelo seu esforço até altas horas e parabéns, de fato, resolve o problema.
Muito sucesso! :wink:

aqui se deixar o setFocusable da linha 40 comentado igual vc fez não funciona o button aparece.
mas se deixar só o da linha 61 comentado ele não aparece.
kkk
realmente parece ser um bug.

[quote=yhhik]aqui se deixar o setFocusable da linha 40 comentado igual vc fez não funciona o button aparece.
mas se deixar só o da linha 61 comentado ele não aparece.
kkk
realmente parece ser um bug.[/quote]

Rapaz, é exatamente esse meu medo! kkkkk… se o mesmo código tem comportamentos distintos… qual a versão da sua JDK? É a 1.7?
Legal seria se mais pessoas que estão lendo ou acompanhando este tópico também realizassem o mesmo teste para ver como segue o comportamento em outras máquinas!

Será que realmente temos mais um BUG NO JAVA?
Abraço!

eu utilizo a 1.6

boa sorte ae com seu projeto Pedro.
abraço.

Obrigado rapaz, consegui o efeito que falou sobre a linha 40… fiz uma seqüência de testes e sem a setFocusable(true); nela realmente o botão surge ao clicar em um outra janela qualquer. :shock:
Abraço, sucesso! Obrigado pela força. :smiley: