当鼠标已经在按钮上时,鼠标监听器如何在一定时间后激活



我正试图在计时器结束后在react按钮上显示一个边框。除非我把鼠标从触发按钮上移开,然后再放回它上,否则我似乎不可能做到这一点。有没有一种方法可以激活鼠标监听器,而不需要把鼠标移开,然后在计时器后再放回触发按钮?请不要说:当定时器结束时设置边界,因为这不是我想要的。此外,也可以随意指出我的代码中的其他错误或坏习惯。我是Java编码的新手。

import java.util.Timer;
import java.util.TimerTask;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ButtonTester{
public static final Border PANEL_BORDER = new LineBorder(Color.red, 12);
public static JPanel panel;
public static JButton trigger;
public static JButton react;
public static JLabel msg;
public static void main(String [] args){
JFrame frame = new JFrame();
frame.setSize(new Dimension(500,200)); 
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setBorder(PANEL_BORDER);
frame.getContentPane().add(panel);
JButton trigger = new JButton("Trigger");
JButton react = new JButton("React");
JLabel msg = new JLabel();
react.setPreferredSize(new Dimension(200, 60));
trigger.setPreferredSize(new Dimension(200, 60));
panel.add(trigger); 
panel.add(react);
panel.add(msg);
panel.setVisible(true);
frame.setVisible(true);
MouseListener mL = new MouseAdapter(){
@Override public void mouseEntered(MouseEvent evt) {
react.setBorder(PANEL_BORDER);
}
@Override public void mouseExited(MouseEvent evt) {
react.setBorder(javax.swing.BorderFactory.createEmptyBorder());
}
};
countDown(msg, trigger, mL);
}
public static void countDown(JLabel msg, JButton trigger, MouseListener mL){
Timer timer = new Timer();
TimerTask task = new TimerTask(){
short seconds = 4; 
public void run(){
if(seconds == 0){
timer.cancel(); 
trigger.addMouseListener(mL); 
return;
}
seconds--;
msg.setText("Attempting to add listener in : "+seconds);
}
};
timer.scheduleAtFixedRate(task, 1000, 1000);
}
}

好的,这个例子设置了两个状态变量,一个用于确定鼠标是否已进入或退出按钮,另一个用于决定计时器是否已完成。

如果这两个条件是true,则设置边界。

这意味着,如果计时器用完时鼠标未在trigger按钮上,则react按钮的边框将不会更改,但如果用户移回按钮,则会更改边框。当鼠标在trigger按钮上并且计时器用完时,它也会发生变化

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public static final Border PANEL_BORDER = new LineBorder(Color.red, 12);
private boolean mouseInTheHouse = false;
private boolean timedOut = false;
private JButton react;
private JButton trigger;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.ipadx = 200;
gbc.ipady = 60;
gbc.gridwidth = GridBagConstraints.REMAINDER;
react = new JButton("React");
trigger = new JButton("Trigger");
add(react, gbc);
add(trigger, gbc);
trigger.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
mouseInTheHouse = true;
stateChanged();
}
@Override
public void mouseExited(MouseEvent e) {
mouseInTheHouse = false;
}
});
Timer timer = new Timer(4000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timedOut = true;
System.out.println("!!");
stateChanged();
}
});
timer.start();
}
protected void stateChanged() {
if (mouseInTheHouse && timedOut) {
react.setBorder(PANEL_BORDER);
}
}
}
}

请注意,我还没有为鼠标离开trigger按钮时应该发生的情况设置条件,但我认为您已经重置了边界。

我明白了。我还有一个问题。如果我有10个触发按钮(面板顶部)和10个反应按钮(面板底部)呢?条件是:如果我把鼠标放在其中一个触发按钮上,那么同一位置的相应反应按钮加上该反应按钮右侧的反应按钮将有边界。如何在不循环浏览按钮列表和检测mouseInHouse的情况下检测到它?

基本上,将想法提炼到最常见的级别。您有两个按钮,一个TimerMouseListener和两个状态变量。将这些封装到一个公共类中,然后可以重用。

public class ButtonStateManager {
private boolean mouseInTheHouse = false;
private boolean timedOut = false;
private JButton trigger;
private JButton react;
private Timer timer;
public ButtonStateManager(JButton trigger, JButton react, int timeOut) {
this.trigger = trigger;
this.react = react;
trigger.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
mouseInTheHouse = true;
stateChanged();
}
@Override
public void mouseExited(MouseEvent e) {
mouseInTheHouse = false;
}
});
Timer timer = new Timer(timeOut, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
timedOut = true;
stateChanged();
}
});
}
protected void stateChanged() {
if (mouseInTheHouse && timedOut) {
react.setBorder(TestPane.PANEL_BORDER);
}
}
}

现在,假设这两个按钮之间存在关系。

如果您的鼠标在trigger按钮上,然后MouseListener被添加到该按钮上,则它无法捕获之前发生的进入trigger按钮区域的事件。

如果你坚持当你的鼠标在trigger按钮上时显示边界,而没有下车和再次打开它,你应该在添加mouseListener后手动调用mouseEnter方法:

(在此之前,您应该将final JFrame frame传递给您的countDown方法)

if(seconds == 0){
timer.cancel(); 
trigger.addMouseListener(mL);
Point mousePosition = MouseInfo.getPointerInfo().getLocation();
Rectangle triggerRect = trigger.getBounds();
Rectangle frameRect = frame.getBounds();
Rectangle newRect = new Rectangle(triggerRect.x + frameRect.x, triggerRect.y + frameRect.y, triggerRect.width, triggerRect.height);
if(newRect.contains(mousePosition)) {
mL.mouseEntered(new MouseEvent(trigger, 0, System.currentTimeMillis(), 1, 0, 0, 0, false));
}
return;
}

但正如MadProgrammer提到的那样,你的问题并不清楚,他说"我正试图在计时器结束后让反应按钮出现一个边框">

希望这能有所帮助!

最新更新