как получить координаты щелчка мыши за пределами моего окна в Java

Мне нужно реализовать класс с использованием Swing, который может получать координаты мыши, когда пользователь щелкает в любом месте экрана. если бы я хотел получить координаты мыши внутри своего окна, я бы использовал MouseListener, но я хочу, чтобы он работал, даже когда пользователь щелкает мышью вне моей программы.

Я хочу, чтобы мой класс вел себя так же, как KColorChooser: пользователь нажимает кнопку перетаскивания, и он можно щелкнуть в любом месте экрана, чтобы получить цвет этого пятна. но я не знаю, возможно ли это с использованием чистой Java.


person cd1    schedule 10.03.2010    source источник


Ответы (12)


Возможны, хотя и ограниченные:

Добавьте 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, ...

Второй момент - вне приложения.

person Keilly    schedule 10.03.2010
comment
Это на самом деле довольно умно, но, конечно же, он будет сообщать только о первом щелчке вне приложения, который фактически вызывает потерю фокуса. После этого ни о каком другом щелчке не будет сообщено, если приложение снова не вернет фокус. Теперь мне интересно, можно ли отреагировать на событие FOCUS_LOST запросом фокуса ...?! - person Thomas; 11.03.2010
comment
Я так не думаю, запрос фокуса или запросы window.toFront () не имеют гарантии влияния на вещи за пределами виртуальной машины. Тестируя OSX, я вижу, что это не работает. - person Keilly; 11.03.2010
comment
Еще одним недостатком является то, что вы не сможете отличить потерю фокуса из-за щелчков вне окна и других типов, таких как, например, CTRL-Tabbing для другого запущенного приложения. - person Thomas; 11.03.2010
comment
Я адаптировал это решение для себя, и теперь оно делает то, что мне нужно :-) - person cd1; 29.03.2010

Забудьте о GlassPane, есть еще один 100% нативный способ Java сделать это, который работает как в OS X, так и в Windows.

Java всегда поддерживает полупрозрачность для своих окон в OS X, а Java теперь поддерживает полупрозрачность и для своих окон в Windows (начиная с версии Java 1.6.0_10 или около того, необходимо проверить).

Уловка такова: щелкнув инструмент «выбрать цвет», вы создадите почти прозрачное окно Java без полей, покрывающее весь экран. Вы устанавливаете его альфа на 10 (альфа изменяется от 0 до 255). Эта альфа настолько мала, что пользователь не заметит очень тонкого «почти прозрачного, но только очень-очень-полупрозрачного» окна без полей, покрывающего весь экран.

Теперь, когда пользователь щелкает по вашему «альфа-каналу с 10 полупрозрачным окном без полей», покрывающим весь экран, вы получаете (x, y).

Откажитесь от окна Java без полей.

Используйте getRgb(x,y) Robot, и все готово.

Почему установить альфа на 10, а не на 0? Потому что в противном случае щелчки не перехватываются Java, а идут непосредственно в ОС (по крайней мере, так это работает в OS X). Есть порог, и я знаю, что он не установлен ни на «1», ни на «2», а около 10 или около того.

РЕДАКТИРОВАТЬ. Я только что понял, что вы знаете, что нужно выбрать несколько цветов. Это сложнее, но все же можно сделать на 100% Java. Либо вы можете жить со слегка размытыми цветами (затронутыми «почти прозрачным», «невидимым» слоем) , либо, получив щелчок, вы должны удалить слой, получить правильный цвет пикселей и снова поставить «почти прозрачный» слой. Конечно, это чертовски крутой хакер, но это можно сделать на 100% Java.

person SyntaxT3rr0r    schedule 10.03.2010
comment
очень желательно, чтобы класс можно было запускать и в Linux. - person cd1; 29.03.2010

Использовать

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

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

p.x и p.y дадут вам координаты за вашим окном.

person Chris    schedule 18.05.2011
comment
Это абсолютно идеально! - person J Atkin; 30.06.2016
comment
Да, но он не показывает, когда произошел щелчок. - person Stefan Reich; 27.11.2016

Я не знаю, возможно ли это на чистой Java.

Это невозможно с использованием чистой Java, поскольку Java знает только о MouseEvents в Windows, принадлежащих Java.

person camickr    schedule 10.03.2010
comment
Возможно (см. Мой ответ). - person Stefan Reich; 27.11.2016

Эти события направляются в окно, которое находится в фокусе, из всех событий на рабочем столе вы можете получить только положение мыши.

Как уже показал Кейли, можно получить только позицию мыши.

Вам необходимо включить собственную библиотеку

person stacker    schedule 10.03.2010
comment
С разрешения Джотчи (первоначального автора Keyboard / Mouse Hook) я взял его библиотеку несколько лет назад и создал новую версию. Последнюю версию и примеры можно найти на GitHub. А также описание библиотеки в сообщении в блоге. - person Kristian Kraljic; 11.02.2016

Я сам этого не пробовал, но, возможно, вы могли бы создать полноэкранную прозрачную панель / фрейм / и т. Д. И добавить к этому MouseListener.

person Chris    schedule 10.03.2010
comment
@Chris: это возможно, но есть подводные камни (см. Мой ответ), потому что не каждая версия Windows поддерживает полностью прозрачный JFrame и т. Д. Другая проблема заключается в том, что в OS X действительно полностью прозрачный JFrame не перехватывает щелчок. - person SyntaxT3rr0r; 11.03.2010

Это возможно с небольшой хитростью. Должен быть на 100% кроссплатформенным (проверено в Linux и Windows). По сути, вы создаете маленькое окно JWindow, делаете его "alwaysOnTop" и перемещаете его с помощью мыши, используя таймер.

Подробнее см. Мой ответ здесь.

person Stefan Reich    schedule 27.11.2016

Местоположение (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());
        }
    }
}
person selami    schedule 12.02.2011

У меня пока недостаточно отзывов, чтобы оставлять комментарии, но вот мои комментарии по другим методам:

  • Используйте собственную библиотеку: будет работать, но имеет очевидные ограничения распространения

  • Используйте GlassPane для заполнения всего экрана: GlassPanes должны содержаться в Window.

  • Создайте окно, содержащее изображение рабочего стола, и заполните весь экран: будет работать, но он внезапно сделает рабочий стол статичным. Курсор больше не будет меняться, любые анимации или видео в других окнах или на рабочем столе станут устрашающе статичными.

Альтернативное решение: доработка окна заполнения экрана, если вы используете Java 6u10 или новее, заключается в том, чтобы сделать окно полностью прозрачный. Поместите это окно перед всеми остальными и слушайте щелчки мыши. У него все еще есть недостатки, такие как отсутствие смены курсора, но это зависит от того, что вы хотите сделать.

person Keilly    schedule 10.03.2010
comment
Похоже, WizardOfOdds имеет то же представление о полупрозрачных окнах. Просто помните, что их реализация зависит от платформы, каждая с различными ограничениями, как он демонстрирует на OSX, и на самом деле не гарантируется, что они будут работать на всех платформах. Тем не менее, похоже, мы нашли несколько разных техник, которые можно попробовать. - person Keilly; 11.03.2010

Основываясь на ответе 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()
    }
}
person fuemf5    schedule 09.01.2014

Послушайте, я так понимаю, что опоздала на 7 лет ...

Это переделка ответа Кейли, которая позволяет получить при нажатии кнопки мыши в любом месте. Основная проблема в том, что полноэкранные игры всегда не сфокусированы, и с ними становится неприятно работать.

Вот код:

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

        }
    }
}
person nathanfranke    schedule 12.06.2017

https://github.com/kwhat/jnativehook JNativeHook: глобальная клавиатура и слушатели мыши для Java.

person Profiterole    schedule 25.12.2020