Java Swing:在鼠标悬停时更改背景颜色

Posted

技术标签:

【中文标题】Java Swing:在鼠标悬停时更改背景颜色【英文标题】:Java Swing: change background color on mouse over 【发布时间】:2010-12-25 07:41:28 【问题描述】:

我已经实现了一个简单的鼠标侦听器,只要鼠标进入组件(JPanel),背景颜色就会改变,并且只要鼠标离开,它就会恢复。这有一些问题:

有时鼠标移动得太快以至于 mouseExit 事件没有被触发 如果我的组件有子组件,当鼠标移动到子组件时会触发 mouseExit 如果我将鼠标快速移到子元素上,则不会触发 mouseEnter 事件

我猜这对于 Swing 退伍军人来说是一件容易的事。对于如何解决这个问题,有任何的建议吗?我不想使用计时器之类的......

【问题讨论】:

【参考方案1】:

有多种解决方案:

向子组件添加鼠标侦听器。还有容器侦听器,用于在添加和删除组件时添加和删除侦听器。不幸的是,添加鼠标监听器会扰乱鼠标事件的冒泡(丑陋的设计)。 在顶部添加一个玻璃窗格。这非常丑陋,并且转发事件总是会导致问题。 将AWTEventListener 添加到默认Toolkit 并过滤您感兴趣的事件。不幸的是,这需要安全权限。 推送自定义EventQueue 并过滤事件。这需要安全权限,put applet 和 WebStart/JNLP 应用程序无论如何都会获得该权限。

【讨论】:

我尝试了玻璃窗格,但无济于事。我可以将玻璃窗格应用于简单的 JPanel 吗?我以为您只能将其应用于 JFrames。由于我有多个 JPanel,我真的需要将玻璃窗格应用于每个 JPanel。【参考方案2】:

我无法重现此行为。请编辑您的问题以提供演示问题的简短代码示例。

当我创建一个 JPanel 并在其中放入一些东西时,当鼠标移到 JPanel 的子组件上时,JPanel 不会获得 mouseExit。我猜你已经为孩子们添加了 MouseListeners。

【讨论】:

是的,你是对的。我尝试为孩子们添加鼠标监听器。【参考方案3】:

如果我将鼠标移到孩子身上 很快,mouseEnter 事件不是 开除

我从未见过这种情况发生,但如果这是一个问题,那么您可以处理 mouseMoved 来重置背景。

如果我的组件有子组件,当 鼠标移动到它触发的孩子 鼠标退出

使用下面的测试,代码只会在你离开组件边界时执行:

public void mouseExited(MouseEvent e) 

    if (! getVisibleRect().contains(e.getPoint()) )
    
        setBackground(...);
    

【讨论】:

如果将指针从外部移动到包含的子项(带有鼠标侦听器),则不会触发父容器上的鼠标侦听器。将其缓慢移动到边界区域上即可。 我使用了你的技术和 Tom Hawtin 的混合技术。不幸的是,只有你们中的一个人能得到正确的答案。谢谢大家。【参考方案4】:

在容器上尝试了各种方法后,没有成功,我最终使用了 Timer。我的容器包含已经需要鼠标侦听器的元素,这无济于事。

计时器方法还意味着我可以将更改延迟一小段时间。 (在我的例子中,我在树节点(容器)中显示了其他按钮,以及更改背景。)

在容器上的 mouseEntered() 上,会创建一个 Timer(如果还没有的话),它每 260 毫秒重复一次。在每次调用 Timer 时,它会确定鼠标是否在容器内。如果是这样,它会在第一次发出鼠标悬停信号。如果不是,它会发出非鼠标悬停信号并停止计时器。

在 Scala 中,如下所示,其中对 entryExit() 的方法调用对鼠标是否悬停进行编码(其中多次调用相同值没有影响):

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()
    
  
...

【讨论】:

以上是关于Java Swing:在鼠标悬停时更改背景颜色的主要内容,如果未能解决你的问题,请参考以下文章

在鼠标悬停时更改背景颜色并在鼠标悬停后将其删除

如何在 Material ui 数据表中悬停或鼠标悬停时更改表格行背景颜色

WinUI 3.0 桌面:文本框的背景颜色在鼠标悬停时更改

更改嵌套 div 内鼠标悬停时的图层颜色

将鼠标悬停在列表上时如何更改锚点颜色

Eclipse,将鼠标悬停在关键字上时更改弹出文本背景颜色