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

发布于 2024-08-14 10:08:52 字数 314 浏览 1 评论 0原文

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

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

我猜这对于 Swing 老手来说是一个简单的事件。关于如何解决这个问题有什么建议吗?我不想使用计时器之类的...

I've implemented a simple mouse listener where the background color changes whenever the mouse enters the component (a JPanel), and it reverts back whenever the mouse leaves. This has some problems:

  • Sometimes the mouse moves so quick that the mouseExit event is not fired
  • If my component has childs, when the mouse moves to the childs it triggers the mouseExit
  • If I move the mouse over to the childs quickly, the mouseEnter event is not fired

I'm guessing this is an easy one for Swing veterans. Any suggestions on how to fix this? I'd love not to use timers and such...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

千纸鹤带着心事 2024-08-21 10:08:52

如果我将鼠标移到孩子身上
很快,mouseEnter 事件就没有了
被解雇

,但如果这是一个问题,那么您可以处理 mouseMoved 来重置背景。

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

使用以下测试,代码仅在离开组件边界时才会执行:

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

If I move the mouse over to the childs
quickly, the mouseEnter event is not
fired

I've never seen this to happen, but if it is an issue then you can handle mouseMoved instead to reset the background.

If my component has childs, when the
mouse moves to the childs it triggers
the mouseExit

Use the following test and the code will only be executed when you leave the components bounds:

public void mouseExited(MouseEvent e) 
{
    if (! getVisibleRect().contains(e.getPoint()) )
    {
        setBackground(...);
    }
}
梦幻之岛 2024-08-21 10:08:52

有多种解决方案:

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

There are a number of solutions:

  • Add mouse listeners to the child components. Also container listeners, to add and remove listeners as components are added and removed. Unfortunately adding mouse listeners upset bubbling up of mouse events (hideous design).
  • Add a glass pane over the top. This is mighty ugly, and forwarding of events always causes problems.
  • Add an AWTEventListener to the default Toolkit and filter through for the events you are interested in. This unfortunately requires a security permission.
  • Push a custom EventQueue and filter events. This requires a security permission, put applets and WebStart/JNLP applications get that permission anyway.
一城柳絮吹成雪 2024-08-21 10:08:52

在容器上尝试了各种方法但没有成功后,我最终使用了计时器。我的容器包含已经需要鼠标侦听器的元素,这并没有帮助。

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

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

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

After trying various approaches on a container, without success, I ended up using a Timer. It didn't help that my container contained elements that already needed mouse listeners on them.

The timer approach also meant that I could delay the change for a short time. (In my case, I show additional buttons in a tree node (a container), as well as changing the background.)

On a mouseEntered() on the container, a Timer is created (if not there already) which repeats every 260 milliseconds. On each call of the Timer, it determines whether the mouse is inside the container. If so, on the first time it signals mouse-over. If not, it signals non-mouse-over and stops the timer.

In Scala, this is as follows, where the method call to entryExit() encodes whether the mouse is over or not (where multiple calls with the same value have no affect):

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()
    }
  }
...
}
っ左 2024-08-21 10:08:52

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

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

I can't reproduce this behavior. Please edit your question to provide a short code sample that demonstrates the problem.

When I create a JPanel, and put something in it, the JPanel does not get mouseExit when the mouse moves over a child component of the JPanel. I'm guessing that you've added MouseListeners to the children.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文