2013-08-26 6 views
5

Auf einem (eingebetteten) Ubuntu 12.04-System haben wir ein einfaches Java-Programm, das einige Grafikmuster in einem Fenster anzeigt und jede Sekunde aktualisiert. Wir verwenden es, um einige Prozesse zu überwachen, die auf dem System laufen. Das Problem besteht darin, dass es zwar aktiv und nicht minimiert ist, aber den Fokus immer dann stiehlt, wenn das Fenster aktualisiert wird. Dies macht das Arbeiten mit den offenen Terminalfenstern unmöglich.Wie verhindert man, dass ein Java-Grafikprogramm den Fokus beim Aktualisieren des Fensters stehlen kann?

Das Verhalten ist gleich, wenn Sie die App-Formular-Befehlszeile oder die Eclipse-IDE ausführen.

Das gleiche Problem tritt unter Windows 7 nicht auf, wenn es unter NetBeans IDE ausgeführt wird.

Wie können wir verhindern, dass die Java-App den Fokus auf den Ubuntu-Rechner stehlen kann?


UPDATE 1: diese Frage gefunden, die mit dem gleichen Problem zu kämpfen scheinen: How do I stop/workaround Java apps stealing focus in Linux window managers. Lesen, ich habe gelernt, dass das Problem mit der Verwendung von JFrame als Container ist, was wir verwenden. Ihre Lösung bestand darin, den JWindow-Container anstelle des JFrame-Containers zu verwenden. Auf der Suche nach dem Unterschied ist die JWindow jedoch "nackt" und verhält sich nicht wie ein "echtes" Fenster, da es keine Dekorationen gibt. Gibt es eine Möglichkeit, JWindow innerhalb eines JFrame zu verwenden, und damit den Fokus Diebstahl zu beseitigen?


UPDATE 2: Des Versuch, dieses Programm auf einem Ubuntu Virtual Machine auf dem PC laufen zu lassen gibt das gleiche Fehlverhalten. Dies deutet darauf hin, dass es einen Unterschied zwischen der Java-Laufzeitumgebung von Windows 7 und Linux gibt und dass das Problem nicht spezifisch für das Embedded-Linux ist.


UPDATE 3: Hier ist ein SSCCE:

//package SSCCE; 

import java.awt.*; 
import java.awt.geom.*; 
import javax.swing.*; 

public class MonitorSSCCE extends JFrame{ 

    public static void main(String[] args) 
    { 
     // Set the frame 
     JFrame ecoreFrame = new JFrame("SSCCE"); 
     ecoreFrame.setSize(120, 120); 
     ecoreFrame.setVisible(true); 

     // Refresh frame every 200 msec 
     while (true) { 
      GRFX grfx = new GRFX(); 
      ecoreFrame.add(grfx); 
      ecoreFrame.setVisible(true); 
      grfx = null; 

      try { 
       Thread.sleep(200); 
      } catch (InterruptedException e) { 

      } 
     } 
    } 


    static int clr = 0; 

    public static class GRFX extends JPanel { 

     public void paintComponent(Graphics comp) { 
      Graphics2D comp2D = (Graphics2D) comp; 

      // Draw a changin color rectangle 
      comp2D.setColor(new Color(clr, 0, 0)); 
      Rectangle2D.Double rect = new Rectangle2D.Double(10, 10, 100, 100); 
      comp2D.fill(rect); 
      clr = clr + 10; 
      if (clr > 255) 
       clr = 0; 
     } 
    } 
} 

UPDATE 4: Während die SSCCE Vorbereitung, ich etwas zu lesen hatte und über die Fülle der Fenster refresh Methoden herauszufinden, des JFrame-Objekts. Es kommt vor, dass das Problem der setVisible() Aufruf innerhalb der while Schleife war. Die Lösung war, es durch die repaint() Methode zu ersetzen.

+0

Bearbeiten Sie Ihre Frage ein minimal [sscce] enthalten (http: //sscce.org/), das das von Ihnen beschriebene Problem aufweist. – trashgod

+0

Zur Referenz: Dieses [Beispiel] (http://stackoverflow.com/a/12228640/230513) "zeigt einige Grafiken ... an, die jede Sekunde aktualisiert werden", aber es stört nicht den Fokus. – trashgod

+1

@trashgod - danke. Ich bin kein Java-Programmierer und der Typ, der die App geschrieben hat, hat Code-Beispiele aus einem Buch kopiert - also ist seine Vertrautheit mit den Java-GUI-Konzepten auch sehr begrenzt. Ich werde mir den von Ihnen bereitgestellten Link ansehen und prüfen, ob er das Problem löst. – ysap

Antwort

0

Austauschen der setVisible() Methodenaufruf innerhalb der while() Schleife durch repaint() beseitigt das Problem:

// Refresh frame every 200 msec 
    while (true) { 
     GRFX grfx = new GRFX(); 
     ecoreFrame.add(grfx); 
     ecoreFrame.repaint(); 
     grfx = null; 

     try { 
      Thread.sleep(200); 
     } catch (InterruptedException e) { 

     } 
    } 
+0

Frage 1 - Ist es notwendig, das 'grfx' Objekt bei jeder Iteration zu" null "zu setzen? Wenn nicht, führt das zu einem Speicherverlust? – ysap

+0

Frage 2 - Sind die Grafikobjekte auf dem JFrame wirklich Objekte in dem Sinne, dass das Rechteck Attribute hat, die später geändert werden können und die Leinwand korrekt neugemalt wird (ein bewegtes Quadrat denken - wird das alte Quadrat richtig gelöscht)? – ysap

+0

Ich habe meine Antwort aktualisiert. – trashgod

2

auf Ubuntu 12.04.2 mit dem Manager Unity Fenster, das example beseelt normalerweise auf dem Desktop im Hintergrund bei 1 Hz, während ein Terminal und Software-Update auch ausgeführt werden. Einige Bezugspunkte zum Vergleich:

Nachtrag: ich wieder einkalkuliert Ihr Beispiel unten einige zusätzliche Punkte zu veranschaulichen:

  • am EDT nicht Schlaf tun; do Verwenden Sie javax.swing.Timer, um die Animation zu beschleunigen.

  • Überschreiben Sie getPreferredSize(), um die ursprüngliche Geometrie einer Grafikkomponente festzulegen.

  • Profile, um die erwartete Heap-Verwendung zu überprüfen.

image

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.Rectangle2D; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

/** 
* @see https://stackoverflow.com/a/18455006/230513 
*/ 
public class TestGRFX { 

    private static class GRFX extends JPanel { 

     private static final int N = 256; 
     private float clr = 0; 
     private Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, N, N); 
     private Timer t = new Timer(100, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       GRFX.this.repaint(); 
      } 
     }); 

     public void start() { 
      t.start(); 
     } 

     @Override 
     public void paintComponent(Graphics g) { 
      Graphics2D g2D = (Graphics2D) g; 
      g2D.setColor(new Color(Color.HSBtoRGB(clr, 1, 1))); 
      g2D.fill(rect); 
      clr += .01; 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(N, N); 
     } 
    } 

    private void display() { 
     JFrame f = new JFrame("TestGRFX"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     GRFX g = new GRFX(); 
     f.add(g); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
     g.start(); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new TestGRFX().display(); 
      } 
     }); 
    } 
} 
+0

Die dritte Kugel ermutigte mich, die Fensteraktualisierungsmethoden zu recherchieren und die Lösung zu finden. Es passiert, dass 'setVisible()' den Fokus stehlen und ersetzt werden muss. – ysap