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:在鼠标悬停时更改背景颜色的主要内容,如果未能解决你的问题,请参考以下文章