我需要使用Swing实现一个类,用于在用户单击屏幕上任何位置时获取鼠标坐标。如果我想要获取自己窗口内的鼠标坐标,我会使用MouseListener
,但我希望它即使在用户单击程序外部也能起作用。
我希望我的类的行为就像KColorChooser:用户单击下拉按钮后,可以单击屏幕上任何位置以获取该点的颜色。但我不知道是否可以使用纯Java实现。
我需要使用Swing实现一个类,用于在用户单击屏幕上任何位置时获取鼠标坐标。如果我想要获取自己窗口内的鼠标坐标,我会使用MouseListener
,但我希望它即使在用户单击程序外部也能起作用。
我希望我的类的行为就像KColorChooser:用户单击下拉按钮后,可以单击屏幕上任何位置以获取该点的颜色。但我不知道是否可以使用纯Java实现。
虽然有限制,但是可以实现:
添加一个AWTEventListener来监听焦点事件。只要在按钮被点击前你的应用程序具有焦点,你就会接收到失去焦点事件。然后查询指针位置。
不过这种方法的限制在于,当然,你的应用程序会失去焦点。因此根据你最终想要实现的目标,这可能没有用。
如果你不想失去焦点,那么你将不得不暂时截取整个屏幕的截图,并在一个填充屏幕的窗口中显示它,该窗口像通常一样监听鼠标点击事件。
第一种方法的证明:
import java.awt.AWTEvent;
import java.awt.MouseInfo;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import javax.swing.JFrame;
public class Application1 {
public static void main(String[] args) {
Toolkit.getDefaultToolkit().addAWTEventListener(
new Listener(), AWTEvent.MOUSE_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static class Listener implements AWTEventListener {
public void eventDispatched(AWTEvent event) {
System.out.print(MouseInfo.getPointerInfo().getLocation() + " | ");
System.out.println(event);
}
}
}
点击应用程序外部会产生:
java.awt.Point[x=198,y=59] | java.awt.event.MouseEvent[MOUSE_EXITED, ...
java.awt.Point[x=976,y=503] | java.awt.FocusEvent[FOCUS_LOST, ...
第二点是应用程序之外的。
别再考虑使用GlassPane
了,有另一种100%本地化的Java方式可以在OS X和Windows系统上运行。
Java一直支持在OS X中为其窗口进行半透明处理,现在Java也支持在Windows系统上为其窗口进行半透明处理(自Java 1.6.0_10版本以来,需要检查版本)。
因此,关键就是:在单击“选择颜色”工具后,创建一个近乎透明的无边框Java窗口覆盖整个屏幕。将其Alpha设置为10(Alpha从0到255)。那个透明度非常低,用户不会注意到整个屏幕上有一个非常细的“几乎透明但只是非常非常非常透明”的无边框窗口。
现在当用户单击覆盖整个屏幕的“Alpha设置为10的透明无边框窗口”时,您就可以获得(x,y)坐标。
舍弃无边框Java窗口。
使用Robot
的getRgb(x,y)
方法即可。
为什么将Alpha值设置为10而不是0?因为否则,点击事件不会被Java拦截,而是直接传递给操作系统(至少在OS X上是这样的)。存在一个阈值,我知道它不是“1”或“2”,大概在10左右。
编辑:我刚意识到您需要选择多个颜色,这更加棘手,但仍然可以使用100%的Java来完成。您可以接受“略微偏离”的颜色(受“几乎透明”的“隐形”层影响),或者在获取单击后,必须删除该层,获取正确的像素颜色,然后再次放置一个“近乎透明”的层。现在当然这是一种非常巧妙的方法,但可以使用100%的Java来实现。
使用
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
PointerInfo inf = MouseInfo.getPointerInfo();
Point p = inf.getLocation();
p.x和p.y将给出窗口之外的坐标。
我不知道是否可以使用纯Java实现。
这是不可能的,因为Java只能识别属于Java的Windows上的MouseEvents。
我个人没有尝试过,但也许您可以创建一个全屏的、透明的面板/框架等,并向其添加MouseListener。
有一个小技巧可以实现。应该是100%跨平台的(在Linux和Windows上测试过)。基本上,您创建一个小的JWindow,使其“alwaysOnTop”并使用计时器移动鼠标。
详情请参见我的答案这里。
import java.awt.* ;
import java.util.* ;
public final class ClickMouse extends TimerTask {
public static int x, y, d ;
public static void main(String[] args) {
TimerTask clikMouse = new ClickMouse();
Timer t = new Timer();
/*
x = Integer.parseInt(args[0]) ;
y = Integer.parseInt(args[1]) ;
d = Integer.parseInt(ares[2]) ;
*/
x = 500;
y = 200;
d = 5;
t.schedule(clikMouse,1000,d*1000);
}
public void run() {
try
{
Robot bot = new Robot();
bot.mouseMove(x,y);
bot.mousePress(java.awt.event.InputEvent.BUTTON1_MASK );
bot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK);
}
catch (Exception e)
{
System.out.println("Exception occured :" + e.getMessage());
}
}
}
看,我知道我晚了7年...
这是Keilly答案的重新制作,它允许在任何地方获取鼠标按钮点击的时间。主要问题是全屏游戏总是没有焦点,处理起来很烦人。
以下是代码:
import java.awt.AWTEvent;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import javax.swing.JFrame;
public class Main {
public static JFrame frame = new JFrame();
public static void main(String[] args) {
Toolkit.getDefaultToolkit().addAWTEventListener(
new Listener(), AWTEvent.MOUSE_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setLocation(1, 1);
}
private static class Listener implements AWTEventListener {
public void eventDispatched(AWTEvent event) {
// We do not want the event to show twice,
// as it shows for focusing and unfocusing
if(event.getID() == 1004) {
Point p = MouseInfo.getPointerInfo().getLocation();
System.out.println("Mouse Clicked at " + p.x + ", " + p.y);
}
// The frame was just unfocused! To make
// sure we get the next mouse click, we
// need to focus it again!
frame.setVisible(true);
}
}
}