2015-06-10 10 views
5

Possiedo un'app per Java Swing su cui sto verificando se è persino possibile effettuare il porting su JavaFX. L'app è un ambiente di sviluppo e un simulatore per un linguaggio di scripting utilizzato internamente. La cosa interessante è che puoi impostare i breakpoint per questo linguaggio di scripting e superarlo, come ogni programmatore si aspetterebbe per una lingua.SecondaryLoop in JavaFX, come Swing?

Ora poiché il linguaggio nel simulatore viene interpretato, in profondità nell'esecuzione dell'interprete, quando raggiunge un punto di interruzione, può tornare alla GUI con una classe Java Swing SecondaryLoop. Quindi, quando viene colpito il punto di interruzione, chiama secondaryLoop.enter(). Il gui è quindi attivo per l'utente per ispezionare le variabili e i componenti dell'interfaccia grafica sono attivi. Quando l'utente preme "Continua" nel programma, chiama secondaryLoop.exit() per continuare l'esecuzione dell'interprete. Non sarebbe realmente fattibile per l'interprete di srotolare l'intero stato per tornare al ciclo primario, e riprendere da dove era stato interrotto esattamente allo stesso punto. Ecco perché SecondaryLoop ha un valore inestimabile nel farlo funzionare.

È possibile in JavaFX?

risposta

2

Sì, è possibile. È necessario utilizzare i metodi enterNestedEventLoop e exitNestedEventLoop (si trovano nella classe com.sun.javafx.tk.Toolkit). Vedi questo esempio di utilizzo:

// Make sure to import the FX Toolkit first 
import com.sun.javafx.tk.Toolkit; 

// This object will be used as a unique identifier to the nested loop (to 
// block the execution of the thread until exitNestedEventLoop is called) 
final Object loopLock = new Object(); 

// Simulate a long process thread (DB call, download, etc) 
Thread longProcess = new Thread(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
     // Sleep for 12 seconds to simulate a long process 
     try 
     { 
      Thread.sleep(12000); 
     } catch (InterruptedException e) 
     { 
      e.printStackTrace(); 
     } 

     // Setup a result to pass back to the enterNestedLoop() caller 
     String result = "Result of this long process"; 

     // We are now done. Call exitNestedEventLoop() to unblock 
     // the enterNestedLoop() caller. This needs to run from 
     // the FX Thread so use Platform.runLater() 
     Runnable fxRunner = new Runnable() 
     { 
      public void run() 
      { 
       try 
       { 
        Toolkit.getToolkit().exitNestedEventLoop(loopLock, 
          result); 
       } catch (Throwable t) 
       { 
        t.printStackTrace(); 
       } 
      } 
     }; 
     Platform.runLater(fxRunner); 
    } 
}); 

// Start that long process from the FX Thread 
longProcess.start(); 
// The next call will block until exitNestedEventLoop is called, however 
// the FX Thread will continue processing UI requests 
Object result = Toolkit.getToolkit().enterNestedEventLoop(loopLock); 
// Next statement will print: "Result of this long process" 
System.out.println("Result is: " + result); 

Ora, prima di utilizzare questo sia avvertito di due cose importanti:

  1. Il com.sun.javafx.tk.Toolkit classe è non fa parte dell'API pubblica, quindi Oracle si riserva il diritto di rimuoverlo senza preavviso. L'ho usato bene da Java 7 a 8u51 in modo che potessero rimanere lì per sempre, cambiare pacchetto/nomi o scomparire completamente (improbabile).

  2. I loop nidificati (e i loop secondari di Swing) sono ottimi per flessibilità e piccole applicazioni, ma l'uso eccessivo di questi ultimi spesso ha un prezzo. L'annidamento a molti loop (traccia stack enorme) spesso causa un comportamento "strano" nelle tue applicazioni poiché le parti iniziali del tuo codice potrebbero finire per attendere quattro o cinque elementi in avanti completamente estranei a loro. Ho visto loop nidificati su FX che causano eccezioni "vuote" nelle chiamate executeScript() di FX WebEngine e duplicazione della preelaborazione della tastiera (quando si accoppia FX + Swing) tra altri problemi.

Detto questo mi consiglia di utilizzare l'javafx.concurrent.Task invece (se ha un senso). L'utilizzo della classe Task richiederà un po 'più di fatica, ma penso che sia il modo corretto di fare le cose e probabilmente ti farà risparmiare molto tempo di manutenzione.

Per avere un riferimento in più sulla FX classe Task vedere questo grande articolo: http://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm

UPDATE: enterNestedEventLoop e exitNestedEventLoop sarà parte del Java 9 API pubblica (classe Platform), maggiori informazioni in JDK-8090865

Spero che questo aiuti!

+1

Secondo JEP 253: "Con la prossima versione di Java 9, e in particolare con l'introduzione di forti confini tra i moduli in Project Jigsaw, gli sviluppatori scopriranno che il loro codice non verrà più compilato o eseguito dal' com.sun . * 'I pacchetti non saranno più accessibili." [Anche] (http://blog.codefx.org/java/dev/how-java-9-and-project-jigsaw-may-break-your-code/#Internal-API): "Quindi se inizia con' com.sun. * ', non esisterà su qualsiasi JDK non Oracle. E se appartiene a uno di questi pacchetti e non è annotato con' @ jdk.Exported', non sarà accessibile da Java 9 in poi. " – jewelsea

+1

Grazie per l'informazione extra jewelsea! In effetti questo è sempre il rischio di usare pacchetti * sun *. Tuttavia, penso che FX Toolkit finirà per essere parte dell'API pubblica, comunque se qualcuno è interessato a seguire [vedi questa richiesta openJDK] (https://bugs.openjdk.java.net/browse/JDK- 8090865) – JavierJ

+0

L'esempio non funziona. 'exitNestedEventLoop' genera un'eccezione che non viene chiamata sul thread della piattaforma. : -/ – Vampire