如何在Java中获取窗口外的鼠标点击坐标

发布于 2024-08-24 05:51:20 字数 296 浏览 8 评论 0原文

我需要使用 Swing 实现一个类,当用户单击屏幕上的任意位置时,它可以获取鼠标坐标。如果我想获取自己窗口内的鼠标坐标,我会使用 MouseListener,但我希望它即使在用户在程序外部单击时也能工作。

我希望我的类的行为就像 KColorChooser 一样:用户单击下拉按钮,然后他可以点击屏幕上的任意位置来获取该点的颜色。但我不知道使用纯Java是否可以。

I need to implement a class, using Swing, which can obtain the mouse coordinates when the user clicks anywhere on the screen. if I wanted to obtain the mouse coordinates inside my own window, I'd use a MouseListener, but I want it to work even when the user clicks outside my program.

I want my class to behave just like KColorChooser: the user clicks on the drop button and he can click anywhere on the screen to obtain the color of that spot. but I don't know if that's possible using pure Java.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

骄傲 2024-08-31 05:51:20

尽管有限,但还是可能的:

为焦点事件添加 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, ...

第二个点在应用程序外部。

It is possible though limited:

Add an AWTEventListener for focus events. As long as your app has focus before the button is clicked you'll receive a focus lost event. Then query for the pointer position.

The limitation is that, of course, your app loses focus. So depending on what you are ultimately trying to achieve this might not be useful.

If you don't want to lose focus then you will have to temporarily take a screenshot of the whole screen and display that in a screen filling window which listens for a mouse click as usual.

Proof of first method:

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);
        }
    }
}

Clicking outside of the app produced:

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, ...

The second point is outside of the app.

护你周全 2024-08-31 05:51:20

忘掉 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 窗口。

使用 RobotgetRgb(x,y) 即可完成。

为什么将 alpha 设置为 10 而不是 0?因为否则点击不会被 Java 拦截,而是直接进入操作系统(至少在 OS X 上事实是这样的)。有一个阈值,我知道它没有设置为“1”,也没有设置为“2”,它大约是 10 左右。

编辑我刚刚意识到你知道需要选择几种颜色,这比较棘手,但仍然可以使用 100% Java 来完成。您可以接受“稍微偏离”的颜色(受“几乎透明”的“不可见”层的影响)或者在单击时必须删除该层,获取正确的像素颜色,然后再次放置“几乎透明”的层。当然,这确实是一种黑客行为,但它可以用 100% Java 来完成。

Forget about GlassPane, there's another 100% native Java way to do it that works both on OS X and on Windows.

Java has always supported translucency for its windows on OS X and Java now supports translucency for its windows on Windows too (since Java 1.6.0_10 or so, needs to be checked).

So the trick is: upon clicking on the "pick a color" tool, you create a nearly transparent borderless Java window covering the entire screen. You set its alpha to 10 (alpha goes from 0 to 255). That alpha is so low the user won't notice that there's a very thin "nearly transparent but only very very very translucent" borderless window covering the entire screen.

Now when the user clicks on your "alpha set to 10 translucent borderless window" covering the entire screen, you get your (x,y).

Discard the borderless Java window.

Use Robot's getRgb(x,y) and you're done.

Why set the alpha to 10 and not 0? Because otherwise clicks aren't intercepted by Java but go directly to the OS (at least that's how it works for a fact on OS X). There's a treshold and I know it's not set at '1', nor '2', it's around 10 or so.

EDIT I just realized you know need to pick several colors, this is trickier but can still be done using 100% Java. Either you can live with "slightly off" colors (affected by the "nearly transparent" 'invisible' layer) or upon getting a click you must remove the layer, get the correct pixel color, and put again a "nearly transparent" layer. Now of course that is one heck of a hack but it can be done in 100% Java.

你的他你的她 2024-08-31 05:51:20

使用

import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;

PointerInfo inf = MouseInfo.getPointerInfo();
Point p = inf.getLocation();

px 和 py 将为您提供窗口外的坐标。

Use

import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;

PointerInfo inf = MouseInfo.getPointerInfo();
Point p = inf.getLocation();

p.x and p.y will give you co-ordinates outside your window.

九歌凝 2024-08-31 05:51:20

我不知道是否可以使用
纯Java。

使用纯 Java 是不可能的,因为 Java 只知道 Windows 上属于 Java 的 MouseEvents。

I don't know if that's possible using
pure Java.

Its not possible using pure Java, since Java is only aware of MouseEvents on Windows belonging to Java.

沒落の蓅哖 2024-08-31 05:51:20

这些事件定向到具有焦点的窗口,从桌面上的所有事件中您只能获取鼠标位置。

正如 Keilly 已经表明的那样,只能获取鼠标位置。

您需要包含 本机库

These events are directed to the window which has the focus, from all events on the desktop you can only get the mouse position.

As already shown by Keilly it's only possible to get the mouse postion.

You need to include a native lib

雪花飘飘的天空 2024-08-31 05:51:20

我自己还没有尝试过,但也许您可以创建一个全屏、透明面板/框架/等,并向其添加一个 MouseListener。

I haven't tried this myself, but maybe you could create a full-screen, transparent panel/frame/etc, and add a MouseListener to that.

惜醉颜 2024-08-31 05:51:20

通过一点小技巧就可以实现。应该是 100% 跨平台的(在 Linux 和 Windows 上测试)。基本上,您创建一个小的 JWindow,将其设置为“alwaysOnTop”,并使用计时器用鼠标移动它。

有关详细信息,请参阅我的回答此处

It is possible with a little trick. Should be 100% cross-platform (tested on Linux & Windows). Basically, you create a small JWindow, make it "alwaysOnTop" and move it around with the mouse using a timer.

For details, see my answer here.

东北女汉子 2024-08-31 05:51:20

位置 (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());
        }
    }
}

The location (x,y) and the time interval
(d) between each click is supplied thru command line arguments. Here is the
program

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());
        }
    }
}
好听的两个字的网名 2024-08-31 05:51:20

看,我知道我迟到了 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);

        }
    }
}

Look, I understand I am 7 years late...

This is a re-make of Keilly's answer, which allows to get when the mouse button is clicked, anywhere. The main problem is that fullscreen games are always unfocused, and it becomes annoying to handle.

Here is the code:

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);

        }
    }
}
凉月流沐 2024-08-31 05:51:20

https://github.com/kwhat/jnativehook JNativeHook:全局键盘以及 Java 的鼠标监听器。

https://github.com/kwhat/jnativehook JNativeHook: Global keyboard and mouse listeners for Java.

柒夜笙歌凉 2024-08-31 05:51:20

我还没有足够的代表来发表评论,但以下是我对其他技术的评论:

  • 使用本机库:可以工作,但有明显的分发限制

  • 使用 GlassPane 填充整个屏幕:GlassPanes 必须包含在窗口内。

  • 创建一个包含桌面图片的窗口并填充整个屏幕:可以,但它会突然使桌面静态。光标将不再改变,其他窗口或桌面中的任何动画或视频都将变得诡异地静态。

替代解决方案:
如果您使用的是 Java 6u10 或更高版本,则对屏幕填充窗口的改进是使窗口

I don't have enough rep yet to leave comments, but here are my comments on the other techniques:

  • Use a native lib: will work, but has obvious distribution limitations

  • Use GlassPane to fill entire screen: GlassPanes must be contained within a Window.

  • Create a Window containing a picture of the desktop and fill the entire screen: Will work, but it will suddenly make the desktop static. The cursor will no longer change, any animations or video in other windows or desktop will become eerily static.

Alternative solution:
A refinement of the screen filling window, if you are using Java 6u10 or later is to make the window completely transparent. Put this window in front of all others and listen for mouse clicks. It still has shortcomings, such as no cursor changes, but it depends on what you want to do.

嗼ふ静 2024-08-31 05:51:20

根据 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()
    }
}

Based on SyntaxT3rr0r's answer I created a sample color picker in groovy which shows how it can work.

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()
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文