我需要实现一个类,使用Swing,它可以在用户点击屏幕任意位置时获取鼠标坐标。如果我想在自己的窗口中获取鼠标坐标,我会使用 a MouseListener
,但我希望它即使在用户在我的程序外部单击时也能工作。
我希望我的班级表现得像KColorChooser一样:用户单击下拉按钮,他可以单击屏幕上的任意位置以获取该点的颜色。但我不知道这是否可以使用纯Java。
我需要实现一个类,使用Swing,它可以在用户点击屏幕任意位置时获取鼠标坐标。如果我想在自己的窗口中获取鼠标坐标,我会使用 a 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 太低了,用户不会注意到有一个非常薄的“几乎透明但只有非常非常非常半透明”的无边框窗口覆盖了整个屏幕。
现在,当用户单击覆盖整个屏幕的“alpha 设置为 10 半透明无边框窗口”时,您将获得 (x,y)。
放弃无边界 Java 窗口。
使用Robot
'sgetRgb(x,y)
就完成了。
为什么将 alpha 设置为 10 而不是 0?因为否则点击不会被 Java 拦截,而是直接进入操作系统(至少对于 OS X 上的事实来说,它是这样工作的)。有一个门槛,我知道它没有设置为“1”,也没有设置为“2”,大约是 10 左右。
编辑我刚刚意识到你知道需要选择几种颜色,这比较棘手,但仍然可以使用 100% Java 来完成。您可以使用“略微关闭”的颜色(受“几乎透明”“不可见”图层的影响),或者在单击时必须删除该图层,获得正确的像素颜色,然后再次放置“几乎透明”图层。现在当然这是一个 hack,但它可以在 100% Java 中完成。
采用
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
PointerInfo inf = MouseInfo.getPointerInfo();
Point p = inf.getLocation();
px 和 py 会给你窗口外的坐标。
我不知道这是否可以使用纯Java。
使用纯 Java 是不可能的,因为 Java 只知道 Windows 上属于 Java 的 MouseEvents。
我自己没有尝试过,但也许你可以创建一个全屏、透明的面板/框架/等,并在其中添加一个 MouseListener。
有一个小技巧是可能的。应该是 100% 跨平台的(在 Linux 和 Windows 上测试)。基本上,您创建一个小的 JWindow,将其设置为“alwaysOnTop”,然后使用计时器用鼠标移动它。
有关详细信息,请在此处查看我的答案。
通过命令行参数提供每次单击之间的位置 (x,y) 和时间间隔 (d)。这是程序
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());
}
}
}
我还没有足够的代表发表评论,但这里是我对其他技术的评论:
使用本机库:可以,但有明显的分发限制
使用 GlassPane 填充整个屏幕:GlassPanes 必须包含在 Window 中。
创建一个包含桌面图片的窗口并填满整个屏幕:可以,但它会突然使桌面静止。光标将不再变化,其他窗口或桌面中的任何动画或视频都将变得异常静止。
替代解决方案:屏幕填充窗口的细化,如果您使用 Java 6u10 或更高版本,则使窗口完全透明。将此窗口放在所有其他窗口的前面,并听取鼠标点击。它仍然有缺点,例如没有光标更改,但这取决于您要做什么。
根据SyntaxT3rr0r的回答,我在 groovy 中创建了一个示例颜色选择器,它显示了它是如何工作的。
import java.awt.*
import java.awt.datatransfer.*
//import com.sun.awt.AWTUtilities;
import javax.swing.WindowConstants as WC;
import javax.swing.SwingConstants as SWC
import groovy.swing.SwingBuilder
class ColorPicker {
SwingBuilder swb = new SwingBuilder()
def window;
def overlayWindow
def mainPanel;
def mainLabel;
def menu;
def transparent = new Color(0, 0, 0, 0);
def nearlyTransparent = new Color(0, 0, 0, 26);
Color color = new Color(150, 150, 255);
def colorHex = { col ->
col = col?: color;
"#"+Integer.toHexString(col.getRGB())[2..-1]
}
def getTextColor = { baseColor ->
baseColor = baseColor?: color;
(baseColor.red*1.5 + baseColor.green*1.5 + baseColor.blue > 400) ? Color.BLACK : Color.WHITE;
}
def setDisplayColor = {newColor ->
mainPanel.background = newColor
mainLabel.foreground = getTextColor(newColor)
mainLabel.text = colorHex(newColor)
}
def show(){
menu = swb.popupMenu { // invoker: mainPanel
menuItem(text: "Pick Color", actionPerformed: capturePixelColor)
menuItem(text: "Copy to Clipboard", actionPerformed: {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(colorHex()), null);
})
separator()
menuItem(text: "Close", actionPerformed: {dispose()})
}
window = swb.frame(
title: "Color Picker",
location:[50,50],
size:[60, 60],
resizable: false,
undecorated: true,
alwaysOnTop: true,
defaultCloseOperation:WC.EXIT_ON_CLOSE
){
def textColor = getTextColor()
mainPanel = panel( constraints: BorderLayout.CENTER,
border: lineBorder(color: Color.BLACK),
componentPopupMenu: menu){
borderLayout()
mainLabel = label(text: "--",
constraints: BorderLayout.CENTER,
horizontalAlignment: SWC.CENTER)
}
}
setDisplayColor(color);
window.show();
}
def capturePixelColor = {
def screenSize = Toolkit.getDefaultToolkit().screenSize
overlayWindow = swb.frame(
location:[0,0],
size: screenSize,
resizable: false,
undecorated: true,
alwaysOnTop: true,
defaultCloseOperation:WC.DISPOSE_ON_CLOSE,
show: true,
background: nearlyTransparent, // AWTUtilities.setWindowOpacity(overlayWindow, 0.1f);
cursor: Cursor.CROSSHAIR_CURSOR,
mouseClicked: {event ->
int x = event.getXOnScreen() // or maybe getX() is enough
int y = event.getYOnScreen()
overlayWindow.dispose()
overlayWindow = null
color = new Robot().getPixelColor(x, y)
setDisplayColor(color)
}
)
}
public static void main(String...args){
println "Welcome to ColorPicker"
def picker = new ColorPicker()
picker.show()
}
}
看,我知道我迟到了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);
}
}
}
https://github.com/kwhat/jnativehook JNativeHook: Java 的全局键盘和鼠标监听器。