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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2419555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:22:09  来源:igfitidea点击:

how to obtain mouse click coordinates outside my window in Java

javaswingmousemouseclick-event

提问by cd1

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.

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

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.

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

采纳答案by Keilly

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.

为焦点事件添加 AWTEventListener。只要您的应用在单击按钮之前获得焦点,您就会收到焦点丢失事件。然后查询指针位置。

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.

第二点在应用程序之外。

回答by Chris

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

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

回答by camickr

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

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

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

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

回答by stacker

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.

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

You need to include a native lib

您需要包含本机库

回答by SyntaxT3rr0r

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

忘记了GlassPane,还有另一种 100% 原生 Java 方式可以在 OS X 和 Windows 上运行。

Java has alwayssupported 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).

Java一直支持 OS X 上的窗口半透明,Java 现在也支持 Windows 上的窗口半透明(因为 Java 1.6.0_10 左右,需要检查)。

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.

所以诀窍是:单击“选择颜色”工具后,您将创建一个几乎透明的无边框 Java 窗口,覆盖整个屏幕。您将其 alpha 设置为 10(alpha 从 0 到 255)。alpha 太低了,用户不会注意到有一个非常薄的“几乎透明但只有非常非常非常半透明”的无边框窗口覆盖整个屏幕。

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

现在,当用户单击覆盖整个屏幕的“alpha 设置为 10 半透明无边框窗口”时,您将获得 (x,y)。

Discard the borderless Java window.

丢弃无边框 Java 窗口。

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

使用Robot'sgetRgb(x,y)就完成了。

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.

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

EDITI 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) orupon 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.

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

回答by Keilly

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.

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

  • 使用 GlassPane 填充整个屏幕:GlassPanes 必须包含在一个 Window 中。

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

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.

替代解决方案:如果您使用的是 Java 6u10 或更高版本,则对屏幕填充窗口的改进是使窗口完全透明。将此窗口放在所有其他窗口的前面并监听鼠标点击。它仍然有缺点,例如没有光标更改,但这取决于您想要做什么。

回答by selami

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

每次点击之间的位置 (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());
        }
    }
}

回答by Chris

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.

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

回答by fuemf5

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

基于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()
    }
}

回答by Stefan Reich

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.

这是可能的一个小技巧。应该是 100% 跨平台的(在 Linux 和 Windows 上测试)。基本上,您创建一个小的 JWindow,使其“始终在顶部”并使用计时器用鼠标移动它。

For details, see my answer here.

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