I have a javafx8 app with a complex scene. It consists of a splitpane where, in the top segment I have a stackpane with multitple levels (children). The rear most is a background that would only need redraws on resizing, another with gridlines, lat/long. Another for drawing and, finally, another with a sliding composite control. When the composite (buttons, labels, comboboxes, and textfields, in the last child of the stackframe, it properly intercepted and acted on mouse and keyboard events. However, with it on top no events were getting propagated to the child panes below. I switched the order and now the buttons and axis control work but nothing now gets propagated to the composite control below it. Buttons fail to see the mouse action.
This seems similar to Stackpane - MouseClick to be listened by both its children but it's not real clear that it is nor is it clear that has a correct answer.
I simplified my scenario with a very simple test, source to follow. In this I have a StackPane with two children, both VBox, one if which with top left alignment, the other with top right. Only the second button, top right responds to being pressed.
Why. The reason I have my app with multiple panes is performance. Both drawing actions are expensive and freq and I didn't want to have to constantly redraw static or near static layouts.
fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<StackPane fx:id="containerPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="mouseeventdemo.MouseEventDemoController">
<children>
<VBox fx:id="container1" prefHeight="200.0" prefWidth="100.0">
<children>
<Button fx:id="leftButton" mnemonicParsing="false" onAction="#leftButtonDown" text="left button" />
</children>
</VBox>
<VBox fx:id="container2" alignment="TOP_RIGHT" prefHeight="200.0" prefWidth="100.0">
<children>
<Button fx:id="rightButton" mnemonicParsing="false" onAction="#rightButtonDown" text="Right Button" />
</children>
</VBox>
</children>
</StackPane>
Controller:
package mouseeventdemo;
/**
* Sample Skeleton for 'FXMLDocument.fxml' Controller Class
*/
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
public class MouseEventDemoController {
@FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;
@FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;
@FXML // fx:id="containerPane"
private StackPane containerPane; // Value injected by FXMLLoader
@FXML // fx:id="container1"
private VBox container1; // Value injected by FXMLLoader
@FXML // fx:id="leftButton"
private Button leftButton; // Value injected by FXMLLoader
@FXML // fx:id="container2"
private VBox container2; // Value injected by FXMLLoader
@FXML // fx:id="rightButton"
private Button rightButton; // Value injected by FXMLLoader
@FXML
void leftButtonDown(ActionEvent event) {
System.out.println("leftButtonPressed");
}
@FXML
void rightButtonDown(ActionEvent event) {
System.out.println("rightButtonPressed");
}
@FXML // This method is called by the FXMLLoader when initialization is complete
void initialize() {
assert containerPane != null : "fx:id=\"containerPane\" was not injected: check your FXML file 'FXMLDocument.fxml'.";
assert container1 != null : "fx:id=\"container1\" was not injected: check your FXML file 'FXMLDocument.fxml'.";
assert leftButton != null : "fx:id=\"leftButton\" was not injected: check your FXML file 'FXMLDocument.fxml'.";
assert container2 != null : "fx:id=\"container2\" was not injected: check your FXML file 'FXMLDocument.fxml'.";
assert rightButton != null : "fx:id=\"rightButton\" was not injected: check your FXML file 'FXMLDocument.fxml'.";
}
}
main
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mouseeventdemo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* @author walt
*/
public class MouseEventDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
In my app the rear most pane is a background canvas. It need be drawn but once and redrawn when the window is resized.
The next is a canvas that had lat/long grids. It need only be redrawn when the window size changes or either the vertical or horizontal scales change.
The next is the main drawing canvas in the following
<vbox>
<hbox>
drawing canvas
vertical scale
</hbox>
horizontal scale
</vbox>
The next carries one or more flagpoles where the vertical pole is a slide rule like reticle. These need to be dragable. If this layer is on top it slides perfectly but the two scales fail to get focus. If the top two panes are reversed, the scales work perfectly but the flagpole objects never receive events.
The two button example duplicates very simply what I see.
Thanks!