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

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

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

11 ответов


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

добавьте 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 без границ, охватывающее все экран. Вы устанавливаете его альфа 10 (Альфа идет от 0 до 255). Эта Альфа настолько низкая, что пользователь не заметит, что есть очень тонкий "почти прозрачный, но только очень очень очень прозрачный" окно без полей, охватывающее весь экран.

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

отбросьте окно Java без границ.

использовать Robot ' s getRgb(x,y) и ты сделанный.

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

редактировать я только что понял, что вам нужно выбрать несколько цветов, это сложнее, но все еще можно сделать с помощью 100% Java. Либо вы можете жить с "немного" цвета (зависит от "почти прозрачный" "невидимый" слой) или после получения щелчка вы должны удалить слой, получить правильный цвет пикселя и снова поместить "почти прозрачный" слой. Теперь, конечно, это чертовски взломать, но это можно сделать на 100% Java.


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

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

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

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


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

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


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

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

вам нужно включить родной lib


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


местоположение (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());
        }
    }
}

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

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

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

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

альтернативное решение: Уточнение окна заполнения экрана, если вы используете 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()
    }
}

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

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


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

вот код:

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

        }
    }
}