I am working on creating a small game.
I use scene switching (scene with a main game's screen and scene with some Help information). So, I decided to use HashMap scenes and set all scenes there. And clicking the button "Help" causes the scene switching.
But I have an issue. I want to stop all animations on non-active scene and currently I just set scene as NULL. I know that it is very bad realization.
Could somebody help me and also explain how to pause or stop all animations on scene?
Setting scene on primaryStage:
public static void setSceneToStage(String sceneId, Stage stage) {
SceneCollection.instance().clearCurrentActiveScene();
SceneCollection.instance().setNewActiveScene(sceneId);
stage.setScene(SceneCollection.instance().getScene(sceneId));
stage.setTitle(sceneId);
}
Clearing non-active scene:
public void clearCurrentActiveScene() {
if(activeScene != null) {
scenes.get(activeScene).clearScene();
}
}
public void clearScene() {
scene = null;
}
Initialize new scene:
public void setNewActiveScene(String sceneId) {
activeScene = sceneId;
scenes.get(sceneId).init();
}
public void init() {
scene = new Scene(new Pane(), 300, 300);
}
I think your program has to have a structure that you can have access to all transitions at time, for example you can have ''TransitonManager Class'' and in that class you have a arraylist of transitions and then you can add this transitions to that in their constructors and then when ever you want , you can have access to all transitions and stop them.
class TransitionManger{
public static ArrayList<Transition> transitions = new ArrayList<>();
}
class CustomTransition extends Transition{
CustomTransition(){
TransitionManger.transitions.add(this);
}
#Override
protected void interpolate(double v) {
//todo do what you want
}
}
you can also use singleton design pattern for TransitionManger for better encapsulation.
Related
I'm new to JavaFX. I'm trying to change scene in my first project and I'm wondering if I can do it like that:
public class A {
...
public void start(Stage primaryStage) throws Exception {
...
B ObjectB = new B();
Scene scene = new Scene();
primaryStage.setScene(scene);
...
if (...) {
ObjectB.anotherFunction(primaryStage);
}
primaryStage.show();
}
}
public class B {
...
public void anotherFunction(Stage stage) {
...
Scene NewScene = new Scene();
stage.setScene(NewScene);
stage.show();
}
}
Code above is shortened version of what I wrote.
I want to change scene from one class that is like menu class (A) in other class (B) and display new scene on the screen. It seems like it's not possible in the way I did it and I'm curious what are good practices in that kind of things.
It`s works. For example just try simply call
ObjectB.anotherFunction(primaryStage);
after or before your
primaryStage.show();
method. Your problem here is that you check this "if" once, even before showing this stage and it false at the start, and then, when it comes true - this piece of code already passed. You just need to run ObjectB.anotherFunction(primaryStage);, when set condition of your if to true.
PS. and pls, start name of your variables from a small letter, objectB instead of ObjectB - it`s just a Java Naming Convention.
This seems like it should be easy, so I must be missing something obvious: I have 4 standalone applications in the same package, us.glenedwards.myPackage,
myClass1 extends Application
myClass2 extends Application
etc...
I need each class to act as its own standalone application. Yet I want to be able to start the other 3 classes from the one I'm in by clicking a link. Android allows me to do this using Intents:
Intent intent = new Intent(this, EditData.class);
overridePendingTransition(R.layout.edit_data_scrollview, R.layout.state);
startActivity(intent);
I've tried starting myClass2 from myClass1 using
myClass2.launch("");
But I get an error, "Application launch must not be called more than once". The only way I can get it to work is if I remove both "extends application" and the start() method from myClass2, which means that myClass2 is no longer a standalone application.
How can I start myClass2, myClass3, or myClass4 from myClass1 with all 4 of them being standalone applications?
You can make this work by calling start(...) directly on a new instance of one of the Application subclasses, but it kind of feels like a bit of a hack, and is contrary to the intended use of the start(...) method. (Just semantically: a method called start in a class called Application should be executed when your application starts, not at some arbitrary point after it is already running.)
You should really think of the start method as the replacement for the main method in a traditional Java application. If you had one application calling another application's main method, you would (hopefully) come to the conclusion that you had structured things incorrectly.
So I would recommend refactoring your design so that your individual components are not application subclasses, but just plain old regular classes:
public class FirstModule {
// can be any Parent subclass:
private BorderPane view ;
public FirstModule() {
// create view; you could also just load some FXML if you use FXML
view = new BorderPane();
// configure view, populate with controls, etc...
}
public Parent getView() {
return view ;
}
// other methods as needed...
}
and, similarly,
public class SecondModule {
private GridPane view ;
public SecondModule {
view = new GridPane();
// etc etc
}
public Parent getView() {
return view ;
}
}
Now you can just do things like
FirstModule firstModule = new FirstModule();
Scene scene = new Scene(firstModule.getView());
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
anywhere you need to do them. So you can create standalone applications for each module:
public class FirstApplication extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new FirstModule().getView());
primaryStage.setScene(scene);
primaryStage.show();
}
}
or you can instantiate them as part of a bigger application:
public class CompositeModule {
private HBox view ;
public CompositeModule() {
Button first = new Button("First Module");
first.setOnAction(e -> {
Parent view = new FirstModule().getView();
Scene scene = new Scene(view);
Stage stage = new Stage();
stage.initOwner(first.getScene().getWindow());
stage.setScene(scene);
stage.show();
});
Button second = new Button("Second Module");
second.setOnAction(e -> {
Parent view = new SecondModule().getView();
Scene scene = new Scene(view);
Stage stage = new Stage();
stage.initOwner(second.getScene().getWindow());
stage.setScene(scene);
stage.show();
});
HBox view = new HBox(10, first, second);
view.setAlignment(Pos.CENTER);
}
public Parent getView() {
return view ;
}
}
and
public class CompositeApplication extends Application {
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new CompositeModule().getView(), 360, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
}
The way I think of this is that Application subclasses represent an entire running application. Consequently it makes sense only to ever instantiate one such class once per JVM, so you should consider these inherently not to be reusable. Move any code you want to reuse into a different class somewhere.
have you tried this?
Runtime.getRuntime().exec("myClass1 [args]"); //put all args as you used in command
Also, handle/catch the exceptions, as needed.
I was right; it was a no-brainer. That's what I get for writing code on 4 hours of sleep:
myClass2 class2 = new myClass2();
try {
class2.start(stage);
} catch (Exception e) { e.printStackTrace(); } }
#FXML
private Pane pane;
#Override
public void initialize(URL location, ResourceBundle resources) {
pane.getScene().setOnKeyPressed(....);
}
I want set the scene event on the FXMLController class , what should i do?
The scene won't be set on the pane until the root element of the FXML is added to a scene graph. In the controller, you have no control over when that will happen, but it has to happen after the initialize() method has completed.
The best approach here is to find some other way to register the event; e.g. do you really want to register it on the scene: can you register it on the root element of the FXML-generated node graph instead?
If you really need to access the scene from the controller, you need to register a listener with the scene property of one of the nodes and set the key pressed handler when the scene is initialized. To be really bullet-proof, you should handle the possibility that your pane may be removed from a scene at some point.
public void initialize() {
EventHandler<KeyEvent> sceneKeyPressedHandler = ... ;
pane.sceneProperty().addListener((ov, oldScene, newScene) -> {
if (oldScene != null) {
oldScene.removeEventHandler(KeyEvent.KEY_PRESSED, sceneKeyPressedHandler);
}
if (newScene != null) {
newScene.addEventHandler(KeyEvent.KEY_PRESSED, sceneKeyPressedHandler);
}
}
// ...
}
first post on here so please be gentle...
I am fairly new to JavaFX and have successfully set up quite a complicated GUI which reads a csv file in order to populate certain components within the GUI.
I'm using a timeline in the intialize function for the GUI Controller which fires a button every second on the GUI - the button calls a function which reads the csv file form disc.. all this is working fine.
When I quit/exit the GUI stage I want to stop the timeline from running... but can't seem to manage this...
I have a small function which loads the Stage and also has an event listener to detect when it's closed... what I'd like to do is be able to close the timeline at the commented line... in the try/catch section.
public void Show_MACD() throws IOException
{
Parent root = FXMLLoader.load(getClass().getResource("MACD Turbo.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle("FX AlgoTrader MACD Turbo");
stage.show();
JavaFX.thisstage=stage;
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent we) {
LoginController sp=new LoginController();
try {
//how can I stop the timeline here?
sp.Show_Products(); // this loads up another stage - a menu in fact
} catch (IOException ex) {
Logger.getLogger(MACD_Controller.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
//System.out.println("running");
}
Here's the section in the initialize function where the timeline is set up and run from....(this is in the same class as the controller called 'MACD_Controller' which is also home to the 'Show_MACD' function which has a event listener for window close events.. that's kind of where I would like to stop the timeline ie when the window closes)
#Override
public void initialize(URL url, ResourceBundle rb) {
final Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent)
{
Refresh.fire(); //Refresh is a button on the GUI which calls the csv file
}
}));
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
}
I know I need to somehow create a reference to 'timeline' so that I can use the 'timeline.stop' function... I've tried all sorts of mumbo jumbo but I keep getting an NPE.
I know this is super basic but I'm a bit stuck..
Cheers
Crispin
A few days ago I started studying JavaFX, and came across the desire to perform 2 experiments. Firstly, I would like to know if it is possible to put an animated background behind an user interface. I've succeeded in creating an animated background, and now I'm having great difficulties to position some controls in the middle of my interface.
I'd like to introduce you 2 pictures of my program. The first demonstrates the undesirable result that I'm getting:
I believe this is my nodes tree:
This is the code of my application:
public class AnimatedBackground extends Application
{
// #########################################################################################################
// MAIN
// #########################################################################################################
public static void main(String[] args)
{
Application.launch(args);
}
// #########################################################################################################
// INSTÂNCIAS
// #########################################################################################################
private Group root;
private Group grp_hexagons;
private Rectangle rect_background;
private Scene cenario;
// UI
private VBox lay_box_controls;
private Label lab_test;
private TextArea texA_test;
private Button bot_test;
// #########################################################################################################
// INÍCIO FX
// #########################################################################################################
#Override public void start(Stage stage) throws Exception
{
this.confFX();
cenario = new Scene(this.root , 640 , 480);
this.rect_background.widthProperty().bind(this.cenario.widthProperty());
this.rect_background.heightProperty().bind(this.cenario.heightProperty());
stage.setScene(cenario);
stage.setTitle("Meu programa JavaFX - R.D.S.");
stage.show();
}
protected void confFX()
{
this.root = new Group();
this.grp_hexagons = new Group();
// Initiate the circles and all animation stuff.
for(int cont = 0 ; cont < 15 ; cont++)
{
Circle circle = new Circle();
circle.setFill(Color.WHITE);
circle.setEffect(new GaussianBlur(Math.random() * 8 + 2));
circle.setOpacity(Math.random());
circle.setRadius(20);
this.grp_hexagons.getChildren().add(circle);
double randScale = (Math.random() * 4) + 1;
KeyValue kValueX = new KeyValue(circle.scaleXProperty() , randScale);
KeyValue kValueY = new KeyValue(circle.scaleYProperty() , randScale);
KeyFrame kFrame = new KeyFrame(Duration.millis(5000 + (Math.random() * 5000)) , kValueX , kValueY);
Timeline linhaT = new Timeline();
linhaT.getKeyFrames().add(kFrame);
linhaT.setAutoReverse(true);
linhaT.setCycleCount(Animation.INDEFINITE);
linhaT.play();
}
this.rect_background = new Rectangle();
this.root.getChildren().add(this.rect_background);
this.root.getChildren().add(this.grp_hexagons);
// UI
this.lay_box_controls = new VBox();
this.lay_box_controls.setSpacing(20);
this.lay_box_controls.setAlignment(Pos.CENTER);
this.bot_test = new Button("CHANGE POSITIONS");
this.bot_test.setAlignment(Pos.CENTER);
this.bot_test.setOnAction(new EventHandler<ActionEvent>()
{
#Override public void handle(ActionEvent e)
{
for(Node hexagono : grp_hexagons.getChildren())
{
hexagono.setTranslateX(Math.random() * cenario.getWidth());
hexagono.setTranslateY(Math.random() * cenario.getHeight());
}
}
});
this.texA_test = new TextArea();
this.texA_test.setText("This is just a test.");
this.lab_test = new Label("This is just a label.");
this.lab_test.setTextFill(Color.WHITE);
this.lab_test.setFont(new Font(32));
this.lay_box_controls.getChildren().add(this.lab_test);
this.lay_box_controls.getChildren().add(this.texA_test);
this.lay_box_controls.getChildren().add(this.bot_test);
this.root.getChildren().add(this.lay_box_controls);
}
}
I've tried to make the use of a StackPane as the root of my scene graph, but also found an undesired result. Despite the controls have stayed in the center of the window, the circles begin to move in as they grow and shrink, making it appear that everything is weird.
The second thing I would like to know is if it is possible to customize the controls so they perform some animation when some event happens. Although we can change the appearance of controls using CSS, it's harder to create something complex. For example, when a control changes its appearance due to a change of state, the transition state change is not made in an animated way, but in an abrupt and static way. Is there a way to animate, for example, a button between its states? This would be done using the JavaFX API? Or would that be using CSS? Or would not be possible in any way?
Thank you for your attention.
after much struggle, I and some users of the Oracle community could resolve this issue. I see no need to repeat here all the resolution made by us, so I'll post the link so you can access the solution of the problem. I hope this benefits us all. Thanks for your attention anyway.
https://community.oracle.com/thread/2620500