JavaFX keyboard input stops working after adding buttons - button

I am building a game engine as a school project. When I add button to the same group as where I have my canvas, I can't control my player anymore with keyboard. Buttons and everything else still works like normal.
My code is pretty huge, so this is a simplified code of the problem:
public abstract class GEngine extends Application {
public void start(Stage theStage) throws Exception {
try {
this.stage = theStage;
Group root = new Group();
Scene theScene = new Scene(root);
stage.setScene(theScene);
Canvas canvas = new Canvas(windowWidth, windowHeight);
root.getChildren().add(canvas);
Button btn = new Button("new");
btn.setOnMousePressed(e->System.out.println("press"));
root.getChildren().add(btn);
Timeline gameLoop = new Timeline();
gameLoop.setCycleCount(Timeline.INDEFINITE);
// Handle input
theScene.setOnKeyPressed(Input::handlePressed);
theScene.setOnKeyReleased(Input::handleReleased);
// Control game loop and it's speed
KeyFrame kf = new KeyFrame(
Duration.seconds(0.017), // 60 FPS
(e)->this.controlGameLoop());
gameLoop.getKeyFrames().add( kf );
gameLoop.play();
stage.show();
} catch (Exception e) {
e.printStackTrace();
stop();
}
}
}
There is probably something happening on the background which I just don't understand. I can show my Input class code too if somebody wants to see it, but in my understanding it's not necessary.
I have tried using AnchorPane as main root and make a separate groups for buttons and canvas which I add the to the AnchorPane, but that did not help at all. That was pretty much the only offered solution I could find from google.

Adding btn.setFocusTraversable(false); fixed the problem, thanks to Luxusproblem for providing the answer!

Related

JavaFX secondary stage onCloseRequest

I have a little issue close a secondary stage after clicking the close at the top right corner.
I'm using fxml with controller class, i need a way to handle this situation.
Here is what i do but i get a nullpointer exception :
#Override
public void initialize(URL location, ResourceBundle resources) {
Stage stage = (Stage) tbTabPaneHome.getScene().getWindow();
stage.setOnCloseRequest(e -> {
Platform.exit();
System.exit(0);
});
}
Because the stage not yet intialized completly, so any other ideas ?
Since the Scene nor the Stage are created yet, you can't call them or you get a NPE, as you already mentioned.
One way to install the event handler on the stage will be listening to changes in the sceneProperty() of tbTabPaneHome.
Once the node is added to the scene, that property will give you the Scene instance.
But the scene is not added to the Stage yet, so you need to wait till this is done, with Platform.runLater():
public void initialize() {
tbTabPaneHome.sceneProperty().addListener((obs, oldScene, newScene) -> {
Platform.runLater(() -> {
Stage stage = (Stage) newScene.getWindow();
stage.setOnCloseRequest(e -> {
Platform.exit();
System.exit(0);
});
});
});
}
Did you try to deal with your secondary stage entirely in the main stage controller?
I want to hide or show a help windows from a button or help menu in my main application controller. Something like the following:
public Button helpBtn;
Stage anotherStage = new Stage();
boolean secondaryInitialyzed = false;
boolean secondaryShowing = false;
public void showOrHideHelp(ActionEvent actionEvent) throws IOException {
if (!secondaryInitialyzed){
Parent anotherRoot = FXMLLoader.load(getClass().getResource("mySecondaryStage.fxml"));
anotherStage.setTitle("Secondary stage");
Scene anotherScene = new Scene(anotherRoot, 500, 350);
anotherStage.setScene(anotherScene);
secondaryInitialyzed = true;
}
if (secondaryShowing){
anotherStage.hide();
secondaryShowing = false;
helpBtn.setText("Show Help");
}
else {
anotherStage.show();
secondaryShowing = true;
helpBtn.setText("Hide Help");
}
It does work, and there might be a way for you to handle your setOnCloseRequest within the main controller.
I have the opposing issue, i.e preventing closing the secondary stage window by clicking the close at the top right corner. I'll look into setOnCloseRequest and see if there is a way there.
I also have an other unrelated problem: can I position the secondary in reference to the primary one?

JavaFX 2. How to stop or pause all animations?

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.

[A]How to use setFullScreen methode in javafx?

I have a stage with these properties
stage = new Stage(StageStyle.DECORATED);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.setTitle("My App");
stage.getIcons().add(new Image(icon-address));
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("start.fxml"));
fxmlLoader.setController(this);
...
...//and other properties
It is in full screen in this stage. I have a button and each time I click on it , a method of another class is called and the reference of this stage is passed to it.
For example, if I have two classes Start and ButtonClicked
In Start, I have this :
Button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
buttonClicked a = new buttonClicked ();
try {
a.render(stage);
} catch (Exception ex) {
Logger.getLogger(menuController.class.getName())
.log(Level.SEVERE, null , ex);
}
}
});
Now, the render method is called and I have the following code inside render :
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("buttonclicked.fxml"));
fxmlLoader.setController(this);//set Controller for our fxml file
loader = fxmlLoader.load();//loader is a stackPane because buttonclick.fxml has stackPane
stage.setScene(new Scene(loader));
stage.setFullScreen(true);
...
The problem is, if user clicks on button, stage become a 1024x700(because i have pictures in start.fxml and buttonclicked.fxml. The size of both the picture is 1024x700
After a moment, it becomes full screen. How can i fix this ?
I want to kill the delay in full screen
Thanks
Try
stage.getScene().setRoot(loader);
in render method.
By doing this, the creation of a new scene is eliminated. Therefore I guess, some UI related updates and calculations that must be done after the scene has been shown, are also eliminated.

JavaFX 2.X - Animated background and animated controls

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

How to create a modal window in JavaFX 2.1

I can't figure out how to create a modal window in JavaFX. Basically I have file chooser and I want to ask the user a question when they select a file. I need this information in order to parse the file, so the execution needs to wait for the answer.
I've seen this question but I've not been able to find out how to implement this behavior.
In my opinion this is not good solution, because parent window is all time active.
For example if You want open window as modal after click button...
private void clickShow(ActionEvent event) {
Stage stage = new Stage();
Parent root = FXMLLoader.load(
YourClassController.class.getResource("YourClass.fxml"));
stage.setScene(new Scene(root));
stage.setTitle("My modal window");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(
((Node)event.getSource()).getScene().getWindow() );
stage.show();
}
Now Your new window is REALY modal - parent is block.
also You can use
Modality.APPLICATION_MODAL
Here is link to a solution I created earlier for modal dialogs in JavaFX 2.1
The solution creates a modal stage on top of the current stage and takes action on the dialog results via event handlers for the dialog controls.
JavaFX 8+
The prior linked solution uses a dated event handler approach to take action after a dialog was dismissed. That approach was valid for pre-JavaFX 2.2 implementations. For JavaFX 8+ there is no need for event handers, instead, use the new Stage showAndWait() method. For example:
Stage dialog = new Stage();
// populate dialog with controls.
...
dialog.initOwner(parentStage);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.showAndWait();
// process result of dialog operation.
...
Note that, in order for things to work as expected, it is important to initialize the owner of the Stage and to initialize the modality of the Stage to either WINDOW_MODAL or APPLICATION_MODAL.
There are some high quality standard UI dialogs in JavaFX 8 and ControlsFX, if they fit your requirements, I advise using those rather than developing your own. Those in-built JavaFX Dialog and Alert classes also have initOwner and initModality and showAndWait methods, so that you can set the modality for them as you wish (note that, by default, the in-built dialogs are application modal).
You can create application like my sample. This is only single file JavaFX application.
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Stage stage;
stage = new Stage();
final SwingNode swingNode = new SwingNode();
createSwingContent(swingNode);
StackPane pane = new StackPane();
pane.getChildren().add(swingNode);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Swing in JavaFX");
stage.setScene(new Scene(pane, 250, 150));
stage.show();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private void createSwingContent(final SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
try {
Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
JasperDesign jasperDesign = JRXmlLoader.load(s + "/src/reports/report1.jrxml");
String query = "SELECT * FROM `accounttype`";
JRDesignQuery jrquery = new JRDesignQuery();
jrquery.setText(query);
jasperDesign.setQuery(jrquery);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint JasperPrint = JasperFillManager.fillReport(jasperReport, null, c);
//JRViewer viewer = new JRViewer(JasperPrint);
swingNode.setContent(new JRViewer(JasperPrint));
} catch (JRException ex) {
Logger.getLogger(AccountTypeController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Resources