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

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

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

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

【问题讨论】:

    标签: java swing mouse background mouseout


    【解决方案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()
        }
      }
    ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 1970-01-01
      • 2011-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      相关资源
      最近更新 更多