2013-08-26 18 views
5

Su un sistema (incorporato) Ubuntu 12.04, abbiamo un semplice programma Java che mostra alcuni schemi grafici su una finestra, aggiornando ogni secondo circa. Lo usiamo per monitorare alcuni processi in esecuzione sul sistema. Il problema è che mentre è attivo e non ridotto a icona, ruba il focus ogni volta che la finestra viene aggiornata. Ciò rende impossibile lavorare con le finestre terminali aperte.Come impedire a un programma grafico Java di rubare lo stato quando si aggiorna la finestra?

Il comportamento è lo stesso quando si esegue la riga di comando del modulo dell'app o da IDE di Eclipse.

Lo stesso problema non si verifica in Windows 7 durante l'esecuzione in NetBeans IDE.

Come possiamo impedire all'applicazione Java di mettere a fuoco l'attenzione sulla macchina Ubuntu?


UPDATE 1: trovato questa domanda che sembrano lottare con lo stesso problema: How do I stop/workaround Java apps stealing focus in Linux window managers. Leggendolo, ho appreso che il problema è l'utilizzo di JFrame come contenitore, che è quello che usiamo. La loro soluzione era usare il container JWindow invece del contenitore JFrame. Tuttavia, cercando la differenza, la JWindow è "nuda" e non si comporta come una finestra "reale", in quanto non ci sono decorazioni. C'è un modo per utilizzare JWindow all'interno di JFrame e quindi eliminare il focus stealing?


UPDATE 2: Cercando di eseguire questo programma su una macchina virtuale Ubuntu sul PC dà lo stesso comportamento scorretto. Ciò suggerisce che esiste una differenza tra il runtime Java di Windows 7 e Linux e che il problema non è specifico per Linux incorporato.


UPDATE 3: Ecco uno 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; 
     } 
    } 
} 

AGGIORNAMENTO 4: Durante la preparazione del SSCCE, ho avuto qualche lettura e scoprire la pletora di metodi finestra di aggiornamento dell'oggetto JFrame. Succede che il problema era la chiamata setVisible() all'interno del ciclo while. La soluzione è stata sostituirla con il metodo repaint().

+0

Si prega di modificare la tua domanda per includere un minimo [sscce] (http: //sscce.org/) che mostra il problema che descrivi. – trashgod

+0

Per riferimento, questo [esempio] (http://stackoverflow.com/a/12228640/230513) "visualizza alcuni elementi grafici ..., aggiornando ogni secondo", ma non _non_ ruba lo stato attivo. – trashgod

+1

@trashgod - grazie. Non sono un programmatore Java e il tizio che ha scritto l'app stava copiando un esempio di codice da un libro, quindi anche la sua familiarità con i concetti della GUI Java è molto limitata. Guarderò il link che hai fornito e vedrò se risolve il problema. – ysap

risposta

0

Sostituzione della chiamata setVisible() metodo all'interno del while() loop repaint() eliminato il problema:

// 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

Domanda 1: è necessario "null" l'oggetto 'grfx' ad ogni iterazione? Se non lo faccio, causerà una perdita di memoria? – ysap

+0

Domanda 2 - Gli oggetti grafici posizionati su JFrame sono realmente oggetti nel senso che il rettangolo ha attributi che possono essere modificati in seguito e la tela sarà correttamente ridipinta (si pensi a un quadrato mobile - il vecchio riquadro verrà cancellato correttamente)? – ysap

+0

Ho aggiornato la mia risposta. – trashgod

2

Su Ubuntu 12.04.2 con il window manager Unity, questo example anima la normalmente sul desktop sullo sfondo a 1 Hz, mentre un terminale e aggiornamento software eseguono anche. Alcuni punti di riferimento per il confronto:

Addendum: ho ri-scomposto il tuo esempio di seguito per illustrare alcuni punti aggiuntivi:

  • Non dormire sul EDT; do usa javax.swing.Timer per stimolare l'animazione.

  • Ignora getPreferredSize() per stabilire la geometria iniziale di un componente grafico.

  • Profile per verificare l'utilizzo dell'heap previsto.

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

Il terzo punto mi ha incoraggiato a ricercare i metodi di aggiornamento delle finestre e trovare la soluzione. Succede che 'setVisible()' sta rubando l'attenzione e ha dovuto essere sostituito. – ysap

Problemi correlati