Pergunta

Eu implementei um ouvinte simples do mouse, onde a cor do plano de fundo muda sempre que o mouse entra no componente (um jpanel) e reverte para trás sempre que o mouse sai. Isso tem alguns problemas:

  • Às vezes o mouse se move tão rápido que o Mouseexit evento não é demitido
  • Se meu componente tem filhos, quando o mouse se move para as crianças, ele desencadeia o Mouseexit
  • Se eu mover o mouse para as crianças rapidamente, o MouseEnter evento não é demitido

Acho que é fácil para veteranos de swing. Alguma sugestão sobre como consertar isto? Eu adoraria não usar temporizadores e tal ...

Foi útil?

Solução

Se eu mover o mouse para as crianças rapidamente, o evento MouseEnter não será demitido

Eu nunca vi isso acontecer, mas se for um problema, você pode lidar com o MouseMoved para redefinir o plano de fundo.

Se meu componente tiver filhos, quando o mouse se move para as crianças, ele desencadeia o Mouseexit

Use o teste a seguir e o código só será executado quando você deixar os limites dos componentes:

public void mouseExited(MouseEvent e) 
{
    if (! getVisibleRect().contains(e.getPoint()) )
    {
        setBackground(...);
    }
}

Outras dicas

Existem várias soluções:

  • Adicione os ouvintes do mouse aos componentes filhos. Também ouvintes de contêineres, para adicionar e remover os ouvintes à medida que os componentes são adicionados e removidos. Infelizmente, a adição de ouvintes do mouse perturbou a borbulhamento de eventos de mouse (design hediondo).
  • Adicione um painel de vidro por cima. Isso é poderoso e feio, e o encaminhamento de eventos sempre causa problemas.
  • Adicione um AWTEventListener para o padrão Toolkit e filtrar para os eventos em que você está interessado. Infelizmente, isso requer uma permissão de segurança.
  • Empurre um costume EventQueue e eventos de filtro. Isso requer uma permissão de segurança, os aplicativos Coloque Applets e Webstart/JNLP obtêm essa permissão de qualquer maneira.

Depois de tentar várias abordagens em um recipiente, sem sucesso, acabei usando um Cronômetro. Não ajudou que meu contêiner contivesse elementos que já precisavam dos ouvintes do mouse neles.

A abordagem do timer também significava que eu poderia adiar a alteração por um curto período de tempo. (No meu caso, mostro botões adicionais em um nó de árvore (um contêiner), além de alterar o plano de fundo.)

Com um mouseEntered () no recipiente, um Cronômetro é criado (se já não está lá) que se repete a cada 260 milissegundos. Em cada chamada do timer, ele determina se o mouse está dentro do recipiente. Nesse caso, na primeira vez, sinaliza o mouse-over. Caso contrário, sinaliza que não é de mouse e interrompe o temporizador.

Em Scala, este é o seguinte, onde o método chama para EntryExit () codifica se o mouse acabou ou não (onde várias chamadas com o mesmo valor não têm efeito):

abstract class MouseInterpreter(component: JComponent) extends MouseAdapter {
  ...
  private var mouseOverAction: () => Unit   = () => {}
  private var mouseOverTimer: Option[Timer] = None
  ...
  def entryExit(entered: Boolean) // this is an abstract method

  override def mouseEntered(e: MouseEvent) {
    if (mouseOverTimer.isEmpty) {
      val aTimer = new Timer(260, new ActionListener {
        def actionPerformed(e: ActionEvent) {
          mouseOverAction()
        }
      })
      mouseOverTimer = Some(aTimer)
      mouseOverAction = () => {
        mouseOverAction = () => {
          val point = MouseInfo.getPointerInfo.getLocation
          SwingUtilities.convertPointFromScreen(point, component)
          if (component.getVisibleRect.contains(point))
            entryExit(entered = true)
          else {
            entryExit(entered = false)
            aTimer.stop()
            mouseOverTimer = None
            mouseOverAction = () => {}
          }
        }
      }
      aTimer.setRepeats(true)
      aTimer.start()
    }
  }
...
}

Não posso reproduzir esse comportamento. Edite sua pergunta para fornecer uma amostra de código curto que demonstre o problema.

Quando crio um JPanel e coloco algo nele, o JPanel não fica com o Mouseexit quando o mouse se move sobre um componente filho do JPanel. Acho que você adicionou mouselisteners às crianças.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top