Java GUI und mehrere Monitore

Ich stand letztens vor folgendem Problem:
Was tun wenn Frames oder Dialoge in einer Java GUI an einer Stelle geöffnet werden, die ausserhalb des Anzeigebereiches sind? Jetzt denkt sich der Leser “Wie zum Teufel soll denn sowas passieren?“.

Dies kann der Fall sein, wenn die Koordinaten gespeichert werden an denen ein bestimmtes Dialog bzw Frame zuletzt geöffnet war. In diesem Fall wäre der Dialog auf Bildschirm 2 zuletzt geöffnet gewesen. Wird der Dialog beim nächsten mal von einem Rechner mit nur einem Bildschirm geöffnet, dann ist der Dialog zwar offen, aber nicht sichtbar. Dies gilt also abzufangen.

(Sollte der Leser keine Lust haben sowas abzufangen, dann sollte er den Dialog wenigstens modal machen, damit User und Admin stundenlang nach dem Grund des “Einfrierens” such können. Dies kann für nebenstehende Beobachter manchmal eine lustige Unterhaltung liefern. Aber das nur mal so am Rande ;-) )

Koordinaten

Stellen wir uns doch mal den Monitor als Koordinatensystem vor. Die Breite als x-Achse und die Höhe als y-Achse. In Java ist der Punkt (0/0) oben links.

monitor_0-0

Nehmen wir mal dass dieser Monitor eine Auflösung von 1024 x 768 Pixel (x=1024 / y=768) hat. Dann jeden die oberen und unteren Ecken folgende Koordinaten:

monitor_allcoord

Die Auflösung für einen einzigen Bildschrim bekommt man übrigens über die Klasse Toolkit aus dem Java-AWT Package

//Eingestellte Auflösung
  1. Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

Würde nun ein Dialog an der Koordinate (1030/0) geöffnet werden, dann wäre dieser Dialog ausserhalb des sichtbaren Bereiches des Monitors und folglich für den User nicht sichtbar.

Jetzt stellen wir mal neben unserem (Haupt-)Monitor noch zwei weitere Monitore. Einen rechts und einen links und betrachten auch hier die Eckkoordinaten

monitor_allcoord_left monitor_allcoord monitor_allcoord_right

Wie wir sehen verschiebt sich das Koordinatensystem nicht auf dem linken Monitor. Die Koordinate (0/0) gehört dem Hauptmonitor.

Alles was links vom Hauptmonitor steht hat negative x-Koordinaten, alles was rechts von ihm steht hat x-Koordinaten die ein Vielfaches des Hauptmonitors sind.

Da wir jetzt wissen wie die Koordinatenbereiche auf Monitoren verteilt wird, wollen wir nun eine Funktion schreiben, die angibt, ob eine Koordinate innerhalb des Gesamt-Anzeigebereiches ist (z. dt.: Werde ich die Dialogbox bzw. Fenster an einer bestimmten Stelle auch sehen können?).

Zunächst stellen wir fest, wieviele Bildschirme vorhanden sind.

AWT bietet die Klasse GraphicsDevice an. Ein GraphicsDevice – Objekt steht für jedes verfügbare Anzeigegerät in der Umgebung. Dies wären z.B. unsere Monitore, aber auch ein Drucker.

Man kann sich alle lokale Anzeigegeräte als Array geben lassen:

// Array mit allen Anzeigegeräten
  1. GraphicsDevice[] gs = GraphicsEnvironment.getLocalGraphicsEnvironment()
  2.                                  .getScreenDevices();

Folglich wäre die Anzahl aller Anzeige-Geräte:

// Anzahl der Anzeigegeräte
  1. int anzahlGeraete = gs.length;

Um die Anzahl der Monitore festzustellen muss man vorher prüfen, ob es sich bei dem GraphicsDevice-Objekt um einen Monitor (TYPE_RASTER_SCREEN) handelt:

// Anzahl der Monitore
  1. int countMonitor = 0;
  2. for(GraphicsDevice gd : gs){
  3.     if(gd.getType() == GraphicsDevice.TYPE_RASTER_SCREEN){
  4.         count++;
  5.     }
  6. }

Und nun wieder zum eigentlichen Problem zurück:  “Liegt die Koordinate im anzeigbarem Bereich?”

Folgende Funktion prüft dies ab und gibt false zurück, falls die Koordinate im nicht-sichtbarem Bereich ist.

Dabei unterstell ich der Einfachheit halber, dass die Anzeigeumgebung nur aus Monitoren besteht und nur maximal zwei Monitore angeschlossen sind.

// Liegt die Koordinate im sichtbarem bereich
  1. public static boolean isInVisibleRange(int x, int y) {
  2.  
  3.     // Array mit allen Anzeigegeräten
  4.     GraphicsDevice[] gs = GraphicsEnvironment.getLocalGraphicsEnvironment()
  5.         .getScreenDevices();
  6.     // Groesse des Hauptmonitors
  7.     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  8.  
  9.     // ein Bildschirm
  10.     if (gs.length == 1) {
  11.         // x-Koordinate ist ausserhalb des Bilschirms
  12.         double monitorX = screenSize.getWidth();
  13.         if (x < 0 || x > monitorX) {
  14.             return false;
  15.         }
  16.         // zwei Bildschirme
  17.     } else if (gs.length == 2) {
  18.  
  19.     // Der Monitor steht links vom Hauptmonitor (negatives X)
  20.     if (getSlaveScreenPosition() == MONITOR_POSITION_LEFT) {
  21.         double monitorX = (secondMonitorSize.getWidth() * -1);
  22.         // Objekt ragt über den linken bzw rechten Bildschirmrand raus
  23.         if (x < monitorX || x > screenSize.getWidth()) {
  24.             return false;
  25.         }
  26.      }
  27.      // Der Monitor steht rechts vom Hauptmonitor (sehr sehr großes X)
  28.      else {
  29.          double monitorX = slaveMonitorSize.getWidth();
  30.          // Objekt ragt über den linken bzw rechten Bildschirmrand raus
  31.          if (x < monitorX || x > (monitorX + screenSize.getWidth())) {
  32.              return false;
  33.          }
  34.        }
  35.      } else {
  36.         return false;
  37.     }
  38.     return true;
  39. }