[英]Mouse exited on inner component hover
我用包含不同組件的 JPanel 創建了一個 JFrame,例如,當鼠標位於 JPanel 的邊界內時,我希望 JPanel 具有可見邊框和可見圖像。 我的問題是,一旦鼠標懸停在 JPanel 內的“可交互”組件上,它就會在鼠標退出 JPanel 時注冊。 只要它在 JPanel 的邊界內,我就希望它繪制這些東西,並且當鼠標退出 JPanel 的邊界時,邊界和圖像“消失”。 有什么辦法可以做到這一點?
這是一個小演示:
public class Test {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new TestFrame();
}
static class TestFrame extends JFrame{
JPanel panel;
JButton hoverButton;
JButton appearingButton;
public TestFrame() {
super();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
panel.setBackground(Color.red);
hoverButton = new JButton("Hover me!");
appearingButton = new JButton("I appeared!");
appearingButton.setVisible(false);
panel.add(hoverButton);
panel.add(appearingButton);
panel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
System.out.println("Entered!");
appearingButton.setVisible(true);
}
public void mouseExited(java.awt.event.MouseEvent evt) {
System.out.println("Exited!");
appearingButton.setVisible(false);
}
});
add(panel);
setSize(new Dimension(200, 200));
setVisible(true);
}
}
}
將鼠標放在 JPanel 中(覆蓋整個 JFrame)時,將出現第二個按鈕。 然而,將鼠標懸停在第一個按鈕上會使第二個按鈕消失。 只要您在 JPanel 的邊界內,我就希望顯示第二個按鈕。
這實際上聽起來要困難得多。 您需要能夠監視容器的子組件的所有鼠標事件。 不幸的是,您要么獲得了要么全部解決要么沒有解決方案。 也就是說,您要么遇到了當前的問題,即一旦另一個組件開始捕獲它們, MouseListener
停止報告鼠標事件(這是鼠標偵聽器API的工作方式),或者您可以看到系統正在處理的所有鼠標事件。
這使您無需提供某種篩選過程,因此可以篩選出您不感興趣的事件,例如...
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
Object source = event.getSource();
if (source instanceof JComponent) {
JComponent comp = (JComponent) source;
if (SwingUtilities.isDescendingFrom(parent, comp)) {
// The mouse is in the house...
}
}
}
}, AWTEvent.MOUSE_MOTION_EVENT_MASK);
(父母是您的主要容器)
這基本上將AWTEventListener
附加到主事件處理框架中,該框架將告訴您所有已處理的特定類型的事件。 然后,在采取適當的措施之前,您需要檢查相關事件是否確實發生在您感興趣的環境中(您自己或其中一個孩子)。
自從我寫了原始答案以來,事件機制的工作方式似乎已經發生了一些變化(並且我也犯了一些小錯誤🙄😓)
為了使AWTListener
生成事件,所有“感興趣的”組件都需要注冊鼠標事件
我做了一個非常基本的測試,創建了一個普通的舊JPanel
(和一個按鈕),並將它們添加到父容器中並使用了...
panel.addMouseListener(new MouseAdapter() {});
panel.addMouseMotionListener(new MouseAdapter() {});
add(panel);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
Object source = event.getSource();
if (source instanceof JComponent) {
JComponent comp = (JComponent) source;
System.out.println(comp);
if (SwingUtilities.isDescendingFrom(comp, TestPane.this)) {
// The mouse is in the house...
System.out.println("Mouse in the house");
}
}
}
}, AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
這會同時為按鈕和面板生成事件
一種解決方案是向JPanel中的每個子組件添加一個鼠標偵聽器。
使用您的代碼,這是一種方法:
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class HoverTest {
/**
* @param args
* the command line arguments
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
HoverTest hoverTest = new HoverTest();
hoverTest.new TestFrame();
}
});
}
public class TestFrame extends JFrame {
private static final long serialVersionUID = 6304847277329579360L;
JPanel panel;
JButton hoverButton;
JButton appearingButton;
public TestFrame() {
super();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
panel.setBackground(Color.red);
hoverButton = new JButton("Hover me!");
appearingButton = new JButton("I appeared!");
appearingButton.setVisible(false);
ButtonListener listener = new ButtonListener(appearingButton);
panel.add(hoverButton);
panel.add(appearingButton);
panel.addMouseListener(listener);
hoverButton.addMouseListener(listener);
appearingButton.addMouseListener(listener);
add(panel);
setSize(new Dimension(200, 200));
setVisible(true);
}
}
private class ButtonListener extends MouseAdapter {
private JButton appearingButton;
public ButtonListener(JButton appearingButton) {
this.appearingButton = appearingButton;
}
@Override
public void mouseEntered(java.awt.event.MouseEvent evt) {
System.out.println("Entered!");
appearingButton.setVisible(true);
}
@Override
public void mouseExited(java.awt.event.MouseEvent evt) {
System.out.println("Exited!");
appearingButton.setVisible(false);
}
}
}
實際上,這比您想象的要容易得多:
panel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
System.out.println("Entered!");
appearingButton.setVisible(true);
}
public void mouseExited(java.awt.event.MouseEvent evt) {
if( ! panel.contains( evt.getPoint() ) ){
System.out.println("Exited!");
appearingButton.setVisible(false);
}
}
});
if語句將過濾掉鼠標仍在面板內時發生的所有mouseExited事件。
結果是,您最終將收到多個mouseEntered事件,而在它們之間沒有mouseExited ,但是可以輕松避免由此引起的任何問題。
當編輯單元格時,我發現自己處於與JTable
類似的情況。
JTable
有一個鼠標偵聽器,它正在跟蹤鼠標位置,但是一旦開始編輯單元格,表格就不會收到mouseExited
/ MOUSE_EXITED
事件。 起初我選擇檢查指針是否在表邊界內,例如
@Override
public void mouseExited(MouseEvent e) {
var lastestLocation = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(location, component);
if (table.contains(latestLocation)) return; // bail out
// do something with the table row
}
當收到鼠標退出事件時它正在工作,但我發現有時當指針移動有點不同時,通常太快,然后鼠標退出事件沒有被觸發,即使指針實際上移出了JTable
。
通過嘗試MadProgrammer的解決方案,問題消失了。 這里有一個小的修改,它使用邊界而不是遍歷組件樹來執行檢查。 我還想發出與表相關的事件,而不是實際的源。
Toolkit.getDefaultToolkit().addAWTEventListener(awtEvent -> {
var source = awtEvent.getSource();
if (source instanceof JComponent) {
var comp = (JComponent) source;
// The actual received event may come from a different component than the table
var tableMouseEvent = SwingUtilities.convertMouseEvent(
comp,
(MouseEvent) awtEvent,
interactiveTable
);
if (interactiveTable.contains(tableMouseEvent.getPoint())) {
// The mouse is in the house...
listeners.forEach(l -> l.mouseMoveWithin(tableMouseEvent));
} else {
// Mouse is outside
listeners.forEach(l -> l.mouseOut(tableMouseEvent));
}
}
}, AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
11.0.17+8-LTS bsd-aarch64 macOs 13.1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.