如何在Java中获取窗口外的鼠标点击坐标
我需要使用Swing实现一个类,它可以在用户单击屏幕上的任何位置时获取鼠标坐标。如果我想在自己的窗口内获取鼠标坐标,我会使用如何在Java中获取窗口外的鼠标点击坐标,java,swing,mouse,mouseclick-event,Java,Swing,Mouse,Mouseclick Event,我需要使用Swing实现一个类,它可以在用户单击屏幕上的任何位置时获取鼠标坐标。如果我想在自己的窗口内获取鼠标坐标,我会使用鼠标侦听器,但我希望它即使在用户在我的程序外单击时也能工作 我希望我的类的行为就像:用户点击下拉按钮,他可以点击屏幕上的任何地方来获得该点的颜色。但是我不知道使用纯Java是否可以做到这一点。我自己也没有尝试过,但也许你可以创建一个全屏、透明的面板/框架/等等,并在其中添加鼠标听筒 我不知道这是否可能 纯Java 使用纯Java是不可能的,因为Java只知道属于Java的W
鼠标侦听器
,但我希望它即使在用户在我的程序外单击时也能工作
我希望我的类的行为就像:用户点击下拉按钮,他可以点击屏幕上的任何地方来获得该点的颜色。但是我不知道使用纯Java是否可以做到这一点。我自己也没有尝试过,但也许你可以创建一个全屏、透明的面板/框架/等等,并在其中添加鼠标听筒 我不知道这是否可能 纯Java
使用纯Java是不可能的,因为Java只知道属于Java的Windows上的鼠标事件。这是可能的,尽管有限: 为焦点事件添加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, ...
第二点在应用程序之外。这些事件被定向到具有焦点的窗口,从桌面上的所有事件中,您只能获得鼠标位置 正如Keilly已经展示的,只可能获得鼠标位置
您需要包括一个忘记
玻璃窗格
,另外还有一种100%纯Java的方法可以在OS X和Windows上实现
Java一直支持OS X上windows的半透明性,现在Java也支持windows上windows的半透明性(因为Java 1.6.0_10左右需要检查)
因此,诀窍是:单击“选择颜色”工具后,创建一个几乎透明的无边界Java窗口,覆盖整个屏幕。将其alpha设置为10(alpha从0到255)。alpha非常低,用户不会注意到整个屏幕上有一个非常薄的“几乎透明但只有非常非常半透明”的无边界窗口
现在,当用户单击覆盖整个屏幕的“alpha设置为10半透明无边框窗口”时,您将获得(x,y)
放弃无边界Java窗口
使用Robot
的getRgb(x,y)
就完成了
为什么要将alpha设置为10而不是0?因为Java不会截获点击,而是直接进入操作系统(至少在OSX上是这样)。有一个treshold,我知道它没有设置为“1”,也没有设置为“2”,大约是10左右
编辑我刚刚意识到你需要选择几种颜色,这比较棘手,但仍然可以使用100%Java完成。您可以使用“稍微不亮”的颜色(受“近乎透明”的“不可见”层的影响),或者在单击后必须删除该层,获得正确的像素颜色,然后再次放置“近乎透明”层。当然,这是一个骇客,但它可以在100%Java中完成。我还没有足够的代表留下评论,但以下是我对其他技术的评论:
- 使用本机库:将起作用,但有明显的分发限制
- 使用玻璃窗格填充整个屏幕:玻璃窗格必须包含在窗口中
- 创建一个包含桌面图片的窗口并填充整个屏幕:可以工作,但会突然使桌面静止。光标将不再改变,其他窗口或桌面上的任何动画或视频将变得异常静态
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()
}
}
这是可能的一个小技巧。应为100%跨平台(在Linux和Windows上测试)。基本上,您可以创建一个小JWindow,使其成为“alwaysOnTop”,并使用计时器用鼠标移动它
有关详细信息,请参阅我的答案。看,我知道我晚了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);
}
}
}
JNativeHook:Java的全局键盘和鼠标侦听器。这实际上相当聪明,但它当然只会报告应用程序外部的第一次单击,即导致焦点丢失的单击。之后,除非应用程序重新获得焦点,否则不会报告其他单击。现在,我想知道是否有可能对FOCUS_LOST事件做出反应,请求FOCUS。。。?!我不这么认为,focus请求或window.toFront()请求不能保证会影响VM之外的事情。在OSX上测试时,我发现这不起作用。另一个缺点是,您无法区分由于在窗口外单击和其他类型(例如,CTRL键切换到另一个正在运行的应用程序)而导致的焦点丢失。我已根据自己的情况调整了此解决方案,现在它满足了我的需要:-)@Chris:这是可能的,但确实存在
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()
}
}
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);
}
}
}