View Full Version : [JavaFX e Java] inserire una animazione javafx in un JPanel
fbcyborg
12-04-2010, 19:53
Salve a tutti,
sono oramai settimane che cerco di ottenere un risultato senza riuscire a capire come fare.
La cosa che vorrei fare dovrebbe essere abbastanza semplice, ma con tutto il materiale che ho trovato in giro fin'ora non riesco a fare quanto sto per descrivere.
Vorrei inserire una stupida animazione (un disco rosso che cambia dimensione ripetutamente) in javafx, all'interno di un JPanel.
Qual'è il modo per farlo?
L'animazione è la seguente:
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;
var radius = 15;
Timeline {
repeatCount: Timeline.INDEFINITE,
keyFrames: [
KeyFrame {
time: 0.5s,
canSkip: true
values : [
radius => 5 tween Interpolator.EASEBOTH
]
} // KeyFrame
KeyFrame {
time: 1.0s,
canSkip: true
values : [
radius => 15 tween Interpolator.EASEBOTH
]
} // KeyFrame
] // keyFrames
}.play(); // Timeline
Stage {
title : "Alert"
scene: Scene {
width: 30
height: 30
content: [
Circle {
centerX: 15,
centerY: 15,
radius: bind radius
fill: Color.RED
} // Circle
] // content
} // Scene
} // Stage
In giro ho trovato del codice che utilizza una certa classe LoadScene, che se volete posso postare, ma non funziona nella maniera più assoluta.
Qualcuno mi può aiutare per favore?
Hai già provato con questo esempio:
http://blogs.sun.com/javafx/entry/how_to_use_javafx_in
?
fbcyborg
12-04-2010, 20:56
Non ancora, e ti dirò che l'ho trovato proprio poco dopo il post. Lo provo e ti faccio sapere.
Sai già se funziona? Perché vedo che l'articolo è vecchio, e non vorrei che nel frattempo siano cambiate delle cose.
Lì si parla di un workaround, poiché al tempo non era prevista l'integrazione di javafx in java.
Grazie!
Non l'ho provato ma se l'han messo nel sito ufficiale ci sono ottime probabilità che funzioni. Circa la possibilità che nel frattempo sia evaporato l'avvertimento c'è ma Sun ha sempre avvertito e mai tolto (basti pensare a "stop" che è deprecated da 15 anni :D). Sono ottimista. Fammi sapere se funzia.
fbcyborg
12-04-2010, 22:10
È un po' strano questo esempio.
Premesso che lavoro con eclipse,
dopo aver creato la classe JXScene in un nuovo progetto Java, sembra che voglia farmi creare un nuovo progetto JavaFX in cui mettere sia il file dell'animazione in javafx, sia la seguente classe:
public class MyScene extends Scene {
init {
content = [
Rectangle { width: 200 height: 200 fill: Color.BLUE },
Text { x: 20 y: 20 content: "Greetings Earthling!" fill: Color.WHITE }
]
}
}
Sinceramente non mi è molto chiaro.
Io vorrei creare un progetto Java, e usare una classe javafx.. qui sembra che voglia fare le cose separatamente, e la cosa mi confonde.
Forse lo fa perchè da Java non è possibile usare sorgenti javafx. Importando il progetto JavaFx in java gli elementi JavaFX sono certamente visti come normali file class.
Se puoi creare un progetto java con elementi javafx (non viceversa) allora il secondo progetto non dovrebbe essere necessario.
fbcyborg
12-04-2010, 22:35
Ah, quindi se non ho capito male, usa un secondo progetto JavaFX per creare i .class delle classi javafx, che poi dovrò copiare nel progetto java.
Sì, più che copiarle userai il jar creato dal progetto javafx come libreria per il progetto java ma il succo dovrebbe essere quello.
fbcyborg
12-04-2010, 23:39
Ok, sembrerebbe tutto a posto, ma ottengo un errore di runtime:
java.lang.ClassNotFoundException: com.sun.test.MyScene
Eppure il jar che contiene quella classe è incluso nel progetto.
Nel progetto includo i seguenti jar:
javafxc.jar, JXScene.jar e MyScene.jar.
Solo che questo pezzo di codice sembra non andar bene:
JXScene scene = new JXScene(); // create a new JXScene
scene.setScript("com.sun.test.MyScene"); // the name of your main JavaFX class
jContentPane.add(scene); // add the scene your swing scene
In particolare segnala l'errore nell'ultima riga.
EDIT: forse ho risolto il problema, mettendo la classe di javafx in un package com.sun.test, in modo da ritrovarmelo nel jar a quel percorso.
Ora però mi trovo con il seguente problema:
Exception in thread "main" java.lang.NoClassDefFoundError: javafx/scene/Scene
[...]
Caused by: java.lang.ClassNotFoundException: javafx.scene.Scene
Può essere un problema di denominazione (la tua classe MyScene è in un package com.sun.test?) o di classpath e qui bisogna vedere come Eclipse gestisca la faccenda. Non uso Eclipse, non saprei dire come controllare questo secondo caso.
fbcyborg
12-04-2010, 23:56
Si, hai ragione, infatti avevo appena finito di editare il post precedente.. :)
Per il nuovo problema, sembra che non trovi in esecuzione eclipse non trovi le librerie della piattaforma javafx.
fbcyborg
13-04-2010, 00:03
Dunque, risolto anche questo.
Mi ero dimenticato di importare tutte le librerie che dice lui, da shared e desktop, ma ora da un altro problema:
java.lang.NoSuchMethodException: com.sun.test.MyScene.javafx$run$(com.sun.javafx.runtime.sequence.Sequence)
E qui non saprei proprio quale possa essere la causa.
Uno ha anche commentato la cosa, e sembra aver avuto lo stesso problema.
Nel post dicono di aggiungere alla classe javafx una funzione:
public function run(args : String[]) {
MyScene {}
}
fbcyborg
13-04-2010, 00:13
In realtà ho letto anche quanto dicono in questo articolo:
http://karussell.wordpress.com/2009/02/27/calling-javafx-from-java/
Solo che non è molto chiaro come faccia a caricare la classe fx in questione.. Comunque provo a fare come hai detto.
fbcyborg
13-04-2010, 00:16
Nel post dicono di aggiungere alla classe javafx una funzione:
public function run(args : String[]) {
MyScene {}
}
Niente, non cambia nulla...
Anche se provo a mandare in esecuzione la classe fx da Eclipse mi da sempre quell'errore.
Sicuro di averlo aggiunto nel punto giusto?
fbcyborg
13-04-2010, 00:21
Non saprei. L'ho aggiunto alla fine... Ho provato a metterlo in testa ma è uguale.
Prova con
http://code.google.com/p/jfxtras/
(è bello dare consigli senza provare prima :D, prova questo, prova quello, prova quell'altro :D)
fbcyborg
13-04-2010, 00:27
Nada
Domani gli do un'occhiata (però con netbeans).
fbcyborg
13-04-2010, 08:47
OK, aspetto notizie! Grazie!
fbcyborg
13-04-2010, 09:49
Nel frattempo ho provato anche il codice riportato a questo indirizzo (http://www.javafxgame.com/calling-javafx-classes-from-java-code/). Peccato che nemmeno questo funzioni.
Non capisco come facciano altre persone a dire che il codice funziona benissimo. A me non trova la classe FX, eppure è tutto come scritto nell'articolo.
Provata anche questa soluzione (http://steveonjava.com/2009/06/22/jfxtras-0-5-release-announcement/), ma niente. Non trova la classe FX.
Comincio a perdere le speranze sinceramente. Mi sa che è una gran bufala sto javafx... Tanto fico quanto inutilizzabile.
Buondì :coffee:
Mi sa che è una gran bufala sto javafx... Tanto fico quanto inutilizzabile.
Non è un buon approccio.
http://www.youtube.com/watch?v=jmKINcGY9dw
Allora, JavaFX SDK 1.2.3, Java 1.6._19. Netbeans, ovviamente, ma non vedo perchè non dovrebbe andare su Eclipse, è tutto manuale.
Questo è il componente javafx:
package test;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
public class FXWidget extends Scene {
init {
content = [
Rectangle { width: 200 height: 200 fill: Color.BLUE }
Text { x: 20 y: 20 content: "Hello World!" fill: Color.WHITE }
]
}
}
Questa è la classe Java.
package fxswingtest;
import com.sun.javafx.tk.swing.SwingScene;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.scene.Scene;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
start();
}
});
}
private static void start() {
JComponent fxComponent = sceneClassToJComponent("test.FXWidget");
JFrame window = new JFrame("Test");
window.add(fxComponent);
window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
window.setSize(640, 640);
window.setVisible(true);
}
private static JComponent sceneClassToJComponent(String fxSceneClassName) {
try {
Scene scene = (Scene) Class.forName(fxSceneClassName).newInstance();
return ((SwingScene) scene.get$javafx$scene$Scene$impl_peer()).scenePanel;
} catch(Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "", ex);
return new JLabel("ERR");
}
}
}
Qui funziona, bisogna vedere se è anche "dinamico".
fbcyborg
13-04-2010, 17:33
Buondì :coffee:
Non è un buon approccio.
http://www.youtube.com/watch?v=jmKINcGY9dw
LOL :rotfl:
Allora, JavaFX SDK 1.2.3, Java 1.6._19. Netbeans, ovviamente, ma non vedo perchè non dovrebbe andare su Eclipse, è tutto manuale.
Questo è il componente javafx:
package test;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
public class FXWidget extends Scene {
init {
content = [
Rectangle { width: 200 height: 200 fill: Color.BLUE }
Text { x: 20 y: 20 content: "Hello World!" fill: Color.WHITE }
]
}
}
Questa è la classe Java.
[CUT]
Qui funziona, bisogna vedere se è anche "dinamico".
Dunque, se a te funziona su Netbeans deve funzionare anche a me su Eclipse. Andiamo per gradi. Voglio provare a fare un progetto simile al tuo, ovviamente con Eclipse.
Parto con la prima domanda. Hai creato un nuovo progetto javafx o java?
Così provo anche io.
Grazie! :)
ho creato un progetto javafx vuoto con quell'unica classe e l'ho compilato e impacchettato in un jar.
Poi ho scaricato l'sdk di javafx (1.2.3), ho creato un nuovo progetto Java e aggiunto le librerie dell'sdk javafx più il jar del progetto javafx.
Dopodichè ho aggiunto al progetto java quella classe Main. Eseguendo il progetto java, salta fuori una finestra con un rettangolo blu e la scritta hello world.
fbcyborg
13-04-2010, 18:43
Ok...
a te te lo esegue il file javafx, se lo fai partire da solo da Netbeans?
No perchè manca il metodo "main" (che sarebbe il function run(args: String[])). Ma non serve che sia eseguibile ai fini dell'integrazione in Swing (o così pare).
fbcyborg
13-04-2010, 18:46
Ok, perfetto.
No perché a me da sempre questo errore:
java.lang.NoSuchMethodException: test.FXWidget.javafx$run$(com.sun.javafx.runtime.sequence.Sequence)
at java.lang.Class.getMethod(Class.java:1605)
at com.sun.javafx.runtime.Entry.start(Entry.java:63)
at com.sun.javafx.runtime.Main.main(Main.java:80)
at com.sun.javafx.runtime.main.Main.main(Main.java:35)
A quanto ho capito è proprio quello a cui ti riferisci tu.
Procedo...
fbcyborg
13-04-2010, 18:54
Fico!
Funziona anche a me. Alleluja!!!
Ora vorrei poter usare questa classe fx al posto di quella hello world che hai messo tu:
package test;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;
var radius = 15;
Timeline {
repeatCount: Timeline.INDEFINITE,
keyFrames: [
KeyFrame {
time: 0.5s,
canSkip: true
values : [
radius => 5 tween Interpolator.EASEBOTH
]
} // KeyFrame
KeyFrame {
time: 1.0s,
canSkip: true
values : [
radius => 15 tween Interpolator.EASEBOTH
]
} // KeyFrame
] // keyFrames
}.play(); // Timeline
Stage {
title : "Alert"
scene: Scene {
width: 30
height: 30
content: [
Circle {
centerX: 15,
centerY: 15,
radius: bind radius
fill: Color.RED
} // Circle
] // content
} // Scene
} // Stage
Non saprei però, come impostarla nella classe, con il metodo init.. Tu sai come fare?
Non ne ho la più pallida idea :D
Uno stage può essere contenuto in uno Scene? Boh. Bisogna anche far partire l'animazione. Si potrà fare nell'init? Mah. Insomma, bisogna fare qualche esperimento.
Se ficchi tutto nell'init cosa dice?
fbcyborg
13-04-2010, 19:03
Se ficchi tutto nell'init cosa dice?
Tutto sottolineato in rosso!!!!!! :D
Che poi se ci fai caso, nell'init che hai usato tu, ci mette solo il content, mentre nel mio caso ci sarebbe un sacco di roba. Però non saprei dove piazzare tutto il resto. Pare che ficcando tutto nell'init, si incazzi! :stordita:
Vabbè, non intendevo proprio un buttar lì tutto alla "valàchelavàben'" :D.
package test;
import javafx.scene.Scene;
import javafx.animation.Timeline;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
public class FXWidget extends Scene {
init {
var radius = 15;
content = [
Circle {
centerX: 15,
centerY: 15,
radius: bind radius
fill: Color.RED
}
];
Timeline {
repeatCount: Timeline.INDEFINITE,
keyFrames: [
KeyFrame {
time: 0.5s,
canSkip: true
values: [
radius => 5 tween Interpolator.EASEBOTH
]
} // KeyFrame
KeyFrame {
time: 1.0s,
canSkip: true
values: [
radius => 15 tween Interpolator.EASEBOTH
]
} // KeyFrame
] // keyFrames
}.play();
}
}
Esteticamente il codice javafx è orrendo.
Una nota: pare che il thread dell'animazione resti in vita anche dopo la morte della finestra Swing. Al posto di DISPOSE_ON_CLOSE ci va un EXIT_ON_CLOSE. In alternativa si dovrebbe trovare un modo per terminare i thread di javax (magari Timeline ha un stop). Ma sono questioni minori.
fbcyborg
13-04-2010, 19:20
A me non lo carica...
Il file si chiama Luce.fx e la classe si chiama Luce, ma quando tento di caricarla dalla gui, mi esce:
Apr 13, 2010 7:19:06 PM fxswingtest.Main sceneClassToJComponent
SEVERE:
java.lang.ClassCastException: test.Luce cannot be cast to javafx.scene.Scene
Luce estende Scene? Puoi incollare il codice che provo direttamente qui?
fbcyborg
13-04-2010, 19:25
Certo, ecco il codice di Luce.fx:
package test;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;
public class Luce extends Scene {
init {
var radius = 15;
content = [
Circle {
centerX: 15,
centerY: 15,
radius: bind radius
fill: Color.RED
}
];
Timeline {
repeatCount: Timeline.INDEFINITE,
keyFrames: [
KeyFrame {
time: 0.5s,
canSkip: true
values: [
radius => 5 tween Interpolator.EASEBOTH
]
} // KeyFrame
KeyFrame {
time: 1.0s,
canSkip: true
values: [
radius => 15 tween Interpolator.EASEBOTH
]
} // KeyFrame
] // keyFrames
}.play();
}
}
Qui me la prende. In effetti non vedo perchè non dovrebbe, Scene lo estende.
Prova a fare un po' di "clean and build" o a riavviare Eclipse.
fbcyborg
13-04-2010, 19:34
Perfetto ha funzionato.. Ho cancellato il jar e l'ha ricreato. Ora va bene.
Una nota: pare che il thread dell'animazione resti in vita anche dopo la morte della finestra Swing. Al posto di DISPOSE_ON_CLOSE ci va un EXIT_ON_CLOSE. In alternativa si dovrebbe trovare un modo per terminare i thread di javax (magari Timeline ha un stop). Ma sono questioni minori.
Credo che a tal proposito sia possibile scrivere un metodo interno alla classe fx che stoppi l'animazione, invocabile normalmente come qualsiasi metodo Java.
A dire il vero però non ho notato che l'animazione rimane in vita. Tu cosa hai notato?
Ho notato che l'applicazione Java non schiatta :D.
fbcyborg
13-04-2010, 19:42
Ah! Vabbé, certo! :) come dicevi anche tu appunto, se non metti EXIT_ON_CLOSE, quella fa una semplice dispose(), ma chiudendo il JFrame, muore anche l'animazione suppongo (nel caso EXIT, ovvio!).
Comunque, il mio intento finale è quello di inserirlo in un JPanel. Suppongo che come muore tale oggetto di tipo JPanel, muoia anche l'animazione.
fbcyborg
13-04-2010, 20:37
Non so se c'hai fatto caso, ma il pallino rosso che "lampeggia", lampeggia su uno sfondo bianco. Io vorrei mettere uno sfondo con il colore RGB 224,223,222, ed ho visto che c'è un parametro "fill" a tal proposito, solo che:
1) non so se prende parametri RGB
2) non so in che punto del codice della classe fx inserirlo
Hai qualche idea?
A naso sono arrivato a:
...class Luce...
...omissis...
init {
fill = Color.rgb(224, 223, 222);
...il resto...
Ma è, ripeto, un approccio "nasale". Al momento non ho un grande interesse per JavaFX, ti lascio volentieri l'incombenza di controllare sulla documentazione se sia il modo giusto di fare.
fbcyborg
13-04-2010, 20:53
Proprio qualche istante fa ho trovato il modo. Basta modificare la classe così:
[...]
init {
var radius = 15;
fill = null;
content = [
Circle {
centerX: 15,
centerY: 15,
radius: bind radius
fill: Color.RED
}
];
[...]
Ho aggiunto fill = null; dal momento che il mio scopo era quello di avere un background trasparente in realtà.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.