2010-03-10 49 views
17

Devo implementare una classe, utilizzando Swing, che può ottenere le coordinate del mouse quando l'utente fa clic in qualsiasi punto dello schermo. se volessi ottenere le coordinate del mouse all'interno della mia finestra, userei uno MouseListener, ma voglio che funzioni anche quando l'utente fa clic all'esterno del mio programma.come ottenere le coordinate del clic del mouse all'esterno della finestra in Java

Voglio che la mia classe si comporti proprio come KColorChooser: l'utente fa clic sul pulsante di rilascio e può fare clic in qualsiasi punto dello schermo per ottenere il colore di quel punto. ma non so se sia possibile usare puro Java.

risposta

23

E 'possibile, anche se limitato:

Aggiungi un AWTEventListener per eventi di attivazione. Finché la tua app è attiva prima che il pulsante venga cliccato, riceverai un evento perso. Quindi interrogare per la posizione del puntatore.

La limitazione è che, ovviamente, la tua app perde la concentrazione. Quindi, a seconda di ciò che alla fine stai cercando di ottenere, potrebbe non essere utile.

Se non si desidera perdere la messa a fuoco, è necessario eseguire temporaneamente uno screenshot dell'intero schermo e visualizzarlo in una finestra di riempimento dello schermo che ascolta normalmente un clic del mouse.

Prova primo metodo:

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

Cliccando all'esterno dell'app prodotto:

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

Il secondo punto è all'esterno dell'app.

+2

Questo è in realtà abbastanza intelligente, ma ovviamente segnalerà solo il primo clic all'esterno dell'applicazione, quello che effettivamente causa la perdita di concentrazione. Dopodiché, non verrà segnalato nessun altro clic, a meno che l'applicazione non riprenda nuovamente l'attenzione. Ora mi chiedo se è possibile reagire a un evento FOCUS_LOST con richiesta di messa a fuoco ...?! – Thomas

+0

Non penso, la richiesta di focus o le richieste window.toFront() non hanno alcuna garanzia di influenzare le cose al di fuori della VM. Test su OSX vedo che questo non funziona. – Keilly

+0

Un altro aspetto negativo è che non sarà possibile distinguere le perdite di messa a fuoco dovute a clic all'esterno della finestra e altri tipi, ad esempio CTRL-Tab su un'altra applicazione in esecuzione. – Thomas

2

Non l'ho provato da solo, ma forse potresti creare un pannello/frame/schermo trasparente a schermo intero e aggiungere un MouseListener.

+0

@ Chris: è possibile, ma ci sono trucchi (vedi la mia risposta), perché non tutte le versioni di supporto di Windows completamente trasparente JFrame ecc Poi l'altra questione è che su OS X un JFrame veramente "completamente trasparente" non intercetta il click. – SyntaxT3rr0r

4

Non so se è possibile utilizzare Java puro .

Non è possibile utilizzare Java puro, poiché Java è a conoscenza solo di MouseEvents su Windows che appartiene a Java.

+0

È possibile (vedi la mia risposta). –

4

Questi eventi sono indirizzati alla finestra che ha lo stato attivo, da tutti gli eventi sul desktop è possibile ottenere solo la posizione del mouse.

Come già indicato da Keilly è possibile solo ottenere la posizione del mouse.

è necessario includere una native lib

+0

Con la permissione di Jotschi (l'autore originale della tastiera/Mouse Hook), ho preso la sua libreria anni fa e ha creato una nuova versione. Si prega di trovare l'ultima versione ed esempi [su GitHub] (https://github.com/kristian/system-hook). Oltre a una descrizione della libreria su [il post del blog] (http://kra.lc/blog/2016/02/java-global-system-hook/). –

19

Dimenticate GlassPane, c'è un altro modo di Java nativo al 100% per farlo che funziona sia su OS X e Windows.

Java ha sempre traslucenza sostenuto per le sue finestre su OS X e Java ora supporta traslucenza per le sue finestre anche su Windows (dal momento che Java 1.6.0_10 o giù di lì, ha bisogno di essere controllato).

Quindi il trucco è: dopo aver fatto clic sullo strumento "scegli un colore", si crea una finestra Java senza bordi quasi trasparente che copre l'intero schermo. Si imposta il suo alfa su 10 (l'alfa va da 0 a 255).L'alfa è così basso che l'utente non si accorgerà che c'è una sottilissima "quasi trasparente ma solo molto molto molto traslucida" finestra senza bordi che copre l'intero schermo.

Ora quando l'utente fa clic su "alfa impostato su 10 finestre senza bordi traslucide" che coprono l'intero schermo, si ottiene il (x, y).

Scarta la finestra senza bordi Java.

Utilizzare Robot 's getRgb(x,y) e il gioco è fatto.

Perché impostare l'alfa su 10 e non su 0? Perché altrimenti i clic non vengono intercettati da Java ma vanno direttamente al sistema operativo (almeno questo è il modo in cui funziona per un fatto su OS X). C'è una soglia e so che non è impostata su "1", né "2", è circa 10 o giù di lì.

EDIT Ho appena realizzato che è necessario selezionare diversi colori, questo è più complicato ma può essere comunque eseguito utilizzando il 100% di Java. O puoi vivere con colori "leggermente spenti" (influenzati dal livello "invisibile" "quasi trasparente") o dopo aver ottenuto un clic devi rimuovere il livello, ottenere il colore corretto del pixel e rimettere un "quasi trasparente" strato. Ora, ovviamente, si tratta di un trucco, ma può essere fatto in Java al 100%.

+0

+1 per indicare i casi d'angolo – Chris

+0

è molto desiderabile che la classe possa essere eseguita anche su Linux. – cd1

0

Non ho abbastanza rep ancora lasciare commenti, ma qui sono i miei commenti sulle altre tecniche:

  • Utilizzare un lib origini: funzionerà, ma ha dei limiti evidenti di distribuzione

  • Usa GlassPane per riempire l'intero schermo: GlassPanes deve essere contenuto all'interno di una finestra.

  • Creare una finestra contenente un'immagine del desktop e riempire l'intero schermo: Funzionerà, ma improvvisamente renderà il desktop statico. Il cursore non cambierà più, eventuali animazioni o video in altre finestre o desktop diventeranno stranamente statici.

Soluzione alternativa: Un perfezionamento dello schermo finestra di riempimento, se si utilizza 6u10 Java o successivo è quello di rendere la finestra completely transparent. Metti questa finestra di fronte a tutti gli altri e ascolta i clic del mouse. Ha ancora difetti, come nessun cambiamento del cursore, ma dipende da cosa vuoi fare.

+0

Sembra che WizardOfOdds abbia la stessa idea delle finestre traslucide. Ricorda che l'implementazione di questi varia a seconda della piattaforma con diverse limitazioni, come dimostra su OSX, e infatti non è garantito il funzionamento su tutte le piattaforme. Tuttavia, sembra che abbiamo trovato alcune tecniche diverse da provare. – Keilly

1

La posizione (x, y) e l'intervallo di tempo (d) tra ogni clic sono forniti tramite gli argomenti della riga di comando. Ecco il programma

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

Usa

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

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

p.x e p.y vi darà coordinate fuori dalla finestra.

+0

Questo è assolutamente perfetto! –

+4

Sì ma non mostra quando si è verificato un clic. –

0

Basato su SyntaxT3rr0r Risposta di s Ho creato un selettore di colori di esempio in Groovy che mostra come può funzionare.

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() 
    } 
} 
0

È possibile con un piccolo trucco. Dovrebbe essere al 100% multipiattaforma (testato su Linux & Windows).Fondamentalmente, si crea una piccola JWindow, si rende "alwaysOnTop" e si sposta con il mouse usando un timer.

Per ulteriori dettagli, vedere la risposta here.

0

Guardate, ho capito io sono 7 anni di ritardo ...

Si tratta di un re-make di risposta di Keilly, che permette di ottenere quando il pulsante del mouse viene cliccato, ovunque. Il problema principale è che i giochi a schermo intero sono sempre sfocati e diventa noioso da gestire.

Ecco il codice:

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

     } 
    } 
}