I would like move vertically with the String which is converted to Text and then implemented
into translate transition. When I start it, nothing happened. Any idea how could it work.
Thanks.
Code:
public class Pohyb extends Application {
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 300);
scene.setFill(Paint.valueOf("B0B0B0"));
primaryStage.setTitle("Canvas");
primaryStage.setScene(scene);
startTransition(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private void startTransition(Scene scene) {
//OBDELNÍK
final Rectangle rect = new Rectangle(32, 32);
rect.setLayoutX((300/2)- (32/2));
rect.setLayoutY((300/2)- (32/2));
rect.setFill(Paint.valueOf("ffffff"));
Text text = new Text("A");
text.setLayoutX(145);
text.setLayoutY(155);
Group root = (Group) scene.getRoot();
root.getChildren().add(rect);
root.getChildren().add(text);
final TranslateTransition translate = new TranslateTransition(new Duration(1000));
translate.setNode(text);
translate.setFromY(text.getLayoutY());
translate.setToX(text.getLayoutY() + 100);
translate.setAutoReverse(true);
translate.setCycleCount(5);
translate.play();
} }
If you increase the size of the stage you'll see your animation working, but at a higher Y coordinate than expected.
If you look at the javadoc for TranslateTransition, it states that it will use translateY property by default. So this will work:
final TranslateTransition translate = new TranslateTransition(new Duration(1000));
translate.setNode(text);
translate.setFromY(text.getTranslateY());
translate.setToY(text.getTranslateY()+100);
translate.setAutoReverse(true);
translate.setCycleCount(5);
translate.play();
This will also work, since the byY property will by used if no toY one is provided:
final TranslateTransition translate = new TranslateTransition(new Duration(1000));
translate.setNode(text);
translate.setByY(100);
translate.setAutoReverse(true);
translate.setCycleCount(5);
translate.play();
Related
I'm trying to code a simple maze with a character that moves using a Joystick (touchpad). I used a Fit viewport to maintain the aspect ration of my maze while keeping it at the center of the screen;
However, I find that that the joystick is also added beside the maze. sample of what it looks like currently
I want the joystick to be of the far bottom-left of the screen. I tried doing this using a different viewport for UI elements (including the joystick), but then the whole maze just gets distorted.
Here is part of my BaseScreen class, an extension I made to reuse in other games as well:
public abstract class BaseScreen implements Screen, InputProcessor {
public BaseScreen(){
gameWorldHeight = 1024;
gameWorldWidth = 1024;
cam = new OrthographicCamera(gameWorldWidth, gameWorldHeight);
port = new FitViewport(cam.viewportWidth, cam.viewportHeight, cam);
port.apply();
cam.update();
mainStage = new Stage(port);
uiStage = new Stage(port);
uiTable = new Table();
uiTable.setFillParent(true);
uiStage.addActor(uiTable);
initialize();
}
public abstract void initialize();
public void render(float dt) {
mainStage.getCamera().update();
uiStage.getCamera().update();
uiStage.act(dt);
mainStage.act(dt);
update(dt);
mainStage.draw();
uiStage.draw();
}
public abstract void update(float dt);
public void resize(int width, int height) {
mainStage.getViewport().update(width,height, true);
uiStage.getViewport().update(width,height,false);
}
}
Here is also a part of my gameScreen class, where I actually code all the core mechanics of the game
public class gameScreen extends BaseScreen {
#Override
public void initialize() {
//..
uiTable.pad(10);
uiTable.add().expandX().expandY();
uiTable.row();
uiTable.add(ball.touchpad).left();
uiTable.add().expandX();
}
}
and in case you were wondering, here is what ball.touchpad is
public class Ball extends BaseActor {
public Touchpad touchpad;
public Touchpad.TouchpadStyle touchpadStyle;
public Skin touchpadSkin;
public Drawable touchBackground;
public Drawable touchKnob;
public Ball (float x, float y, Stage s) {
//..
//Create a touchpad skin
touchpadSkin = new Skin();
//Set background image
touchpadSkin.add("touchBackground", new Texture("touchBackground.png"));
//Set knob image
touchpadSkin.add("touchKnob", new Texture("touchKnob.png"));
//Create TouchPad Style
touchpadStyle = new Touchpad.TouchpadStyle();
//Create Drawable's from TouchPad skin
touchBackground = touchpadSkin.getDrawable("touchBackground");
touchKnob = touchpadSkin.getDrawable("touchKnob");
//Apply the Drawables to the TouchPad Style
touchpadStyle.background = touchBackground;
touchpadStyle.knob = touchKnob;
//Create new TouchPad with the created style
touchpad = new Touchpad(10, touchpadStyle);
//setBounds(x,y,width,height)
touchpad.setBounds(15, 15, 200, 200);
}
So how can i add this touchpad on the bottom left of the screen?
Please go through the image below.
In the above image you can find that horizontal scrolling is not started.
Now visit the After Scroll image of the same contents...
Now in the second image you can see that horizontal scrolling is done ...
JFXPanel contents are scroll horizontally... Which was perfect...
Now the third image will describe the problem....
It is liitle bit stretched to see as it is maximized...
You can see that the JFXPanel contents have changed their original position...
Moreover the contents must start with X_DisplaceMent = 0.0 [X-Cordinate], which was done automatically in the first two images...
All the contents are nodes like [Rectangle,Line etc.. ], after that all are placed in Group node...
And this Group node is set in the ScrollPane through
js.setContent(Group node);
Each component is placed with given x,y cordiante value .. then how did this happen while doing the maximized ?
Please help me to find the root cause ...
Thanks in advance...
Here are some facts that cause the problem.
- Start Position of Scene : 0.0
- Start Position of Group in Scene : 49.5
- Width of the root : 364.5
- Start Position of Scene : 0.0
- Start Position of Group in Scene : 63.5
- Width of the root : 364.5
- Start Position of Scene : 0.0
- Start Position of Group in Scene : 83.5
- Width of the root : 364.5
Whenever we drag the window horizontally Group is moving in the scene... That should not happen... how to avoid this ...
Ok... Here is the MCVE.....
There is a Frame. which contain SplitPane having vertical split.
The SplitPane will show the contents of two JFxPanels.
Both fxpanels are having rectangle on same x cordinate but Y cordinate is different.
And both the fxPanels are horizontal scroll sync. Not bi-directional. When you scroll lower panel horizonatally, the upper panel will get scrolled due to horizontal sync.
Here is the code for fxPanel 1...
public class FxPanel1 extends JFXPanel
{
private ScrollPane scroll ;
public ScrollPane getJs() {
return scroll;
}
public void setJs(ScrollPane js) {
this.scroll = js;
}
private boolean initFX(JFXPanel fxPanel) {
Scene scene = createScene();
fxPanel.setScene(scene);
return true;
//craneAssignmentChartView.setFxPanel(fxPanel);
}
private Scene createScene() {
Group root = new Group();
Rectangle rect = new Rectangle(10.0, 20.0, 800, 40);
rect.setFill(javafx.scene.paint.Color.TRANSPARENT);
rect.setStroke(javafx.scene.paint.Color.RED);
AnchorPane anchor = new AnchorPane();
anchor.getChildren().add(rect);
GridPane grid = new GridPane();
grid.setHgap(0);
grid.setVgap(0);
grid.setPadding(new Insets(0, 0, 0, 0));
grid.add(anchor, 1, 0);
root.getChildren().add(grid);
ScrollPane scroll = new ScrollPane();
scroll.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
scroll.setContent(root);
setJs(scroll);
return new Scene(scroll, javafx.scene.paint.Color.WHITE);
}
private void createUI(final JFXPanel fxPanel)
{
Platform.runLater(new Runnable() {
#Override
public void run()
{
initFX(fxPanel);
}
});
}
public FxPanel1( JFXPanel fxPanel)
{
createUI(fxPanel);
}
}
Now the code for second fxPanel looks like ...
public class FxPanel2 extends JFXPanel
{
private ScrollPane scroll ;
public ScrollPane getJs() {
return scroll;
}
public void setJs(ScrollPane js) {
this.scroll = js;
}
private boolean initFX(JFXPanel fxPanel) {
Scene scene = createScene();
fxPanel.setScene(scene);
return true;
//craneAssignmentChartView.setFxPanel(fxPanel);
}
private Scene createScene() {
Group root = new Group();
Rectangle rect = new Rectangle(10.0, 180.0, 800, 40);
rect.setFill(javafx.scene.paint.Color.TRANSPARENT);
rect.setStroke(javafx.scene.paint.Color.RED);
AnchorPane anchor = new AnchorPane();
anchor.getChildren().add(rect);
GridPane grid = new GridPane();
grid.setHgap(0);
grid.setVgap(0);
grid.setPadding(new Insets(0, 0, 0, 0));
grid.add(anchor, 1, 0);
root.getChildren().add(grid);
ScrollPane scroll = new ScrollPane();
scroll.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollBarPolicy.NEVER);
scroll.setContent(root);
setJs(scroll);
return new Scene(scroll, javafx.scene.paint.Color.WHITE);
}
private void createUI(final JFXPanel fxPanel)
{
Platform.runLater(new Runnable() {
#Override
public void run()
{
initFX(fxPanel);
}
});
}
public FxPanel2( JFXPanel fxPanel)
{
createUI(fxPanel);
}
}
The main class looks like ....
public class DemoToCheckUIAlignment extends JFrame
{
public static void main(String[] args)
{
final DemoToCheckUIAlignment demo = new DemoToCheckUIAlignment();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFXPanel panel1 = new JFXPanel();
FxPanel1 fxObj1 = new FxPanel1(panel1);
JFXPanel panel2 = new JFXPanel();
FxPanel2 fxObj2 = new FxPanel2(panel2);
DemoToCheckUIAlignment frame = new DemoToCheckUIAlignment();
frame.setSize(800, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JSplitPane chartSplitPane = new JSplitPane();
chartSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
chartSplitPane.setDividerLocation(200);
chartSplitPane.setDividerSize(2);
chartSplitPane.setTopComponent(panel1);
chartSplitPane.setBottomComponent(panel2);
demo.provideScrollSyncBetweenFXPanels(fxObj1.getJs(), fxObj2.getJs());
frame.getContentPane().add(chartSplitPane);
//frame.getContentPane().add(panel2);
frame.setVisible(true);
}
});
}
public static void provideScrollSyncBetweenFXPanels(final ScrollPane upperSP, final ScrollPane lowerSP)
{
lowerSP.hvalueProperty().addListener(new ChangeListener<Number>()
{
public void changed(ObservableValue<? extends Number> ov,
Number old_val, Number new_val)
{
upperSP.hvalueProperty().set(new_val.doubleValue());
}
});
}
}
Now to check the problem follow the simple steps...
Ofcorse run the program...
Scroll the bottom Panel ....that is FxPanel2...
And maximized the window .... The x - position for the inner contents is changed now...
which does not happen with Swing....
Here are the screen shots where the problem reproduce for the attached MCVE....Please go through the images....
You may use setFitToWidth of the ScrollPane Object to match a particular dimension. For more details you may refer to the link http://docs.oracle.com/javafx/2/ui_controls/scrollpane.htm at down the page, Resizing Components in the Scroll Pane, you may find more on the solution
b1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
try {
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager
.getConnection("jdbc:mysql://localhost:3306/project?"
+ "user=root&password=virus");
statement = connect.createStatement();
preparedStatement = connect
.prepareStatement("select * from mark where clsnum = " + txt1.getText() + "");
rs = preparedStatement.executeQuery();
if (rs.next()) {
delete();
} else {
msg.setText("Student Not Found...!");
}
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(DeleteMark.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
This is my code to display a message if the query not worked(I mean if no row is returned to ResultSet rs). msg is an object of Text and its declaration and other details are -
Text msg = new Text();
msg.setFont(Font.font("Calibri", FontWeight.THIN, 18));
msg.setFill(Color.RED);
I want to make the Text disappear after sometime, like 3 or 4 seconds. Is it possible to do it in JavaFX (with the help of timer or something else you know) ? If yes, how ?
Use Timelines and/or Transitions.
This answer is for a previous iteration of the question.
Sample solution code
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class BlinkingAndFading extends Application {
#Override
public void start(Stage stage) {
Label label = new Label("Blinking");
label.setStyle("-fx-text-fill: red; -fx-padding: 10px;");
Timeline blinker = createBlinker(label);
blinker.setOnFinished(event -> label.setText("Fading"));
FadeTransition fader = createFader(label);
SequentialTransition blinkThenFade = new SequentialTransition(
label,
blinker,
fader
);
stage.setScene(new Scene(new StackPane(label), 100, 50));
stage.show();
blinkThenFade.play();
}
private Timeline createBlinker(Node node) {
Timeline blink = new Timeline(
new KeyFrame(
Duration.seconds(0),
new KeyValue(
node.opacityProperty(),
1,
Interpolator.DISCRETE
)
),
new KeyFrame(
Duration.seconds(0.5),
new KeyValue(
node.opacityProperty(),
0,
Interpolator.DISCRETE
)
),
new KeyFrame(
Duration.seconds(1),
new KeyValue(
node.opacityProperty(),
1,
Interpolator.DISCRETE
)
)
);
blink.setCycleCount(3);
return blink;
}
private FadeTransition createFader(Node node) {
FadeTransition fade = new FadeTransition(Duration.seconds(2), node);
fade.setFromValue(1);
fade.setToValue(0);
return fade;
}
public static void main(String[] args) {
launch(args);
}
}
Answers to additional questions
lambda expression not expected here lambda expressions are not supported in -source 1.7 (use -source 8 or higher to enable lambda expressions)
You should use Java 8 and not set -source 1.7. If you wish to stick with Java 7 (which I don't advise for JavaFX work), you can replace the Lambda:
blinker.setOnFinished(event -> label.setText("Fading"));
with:
blinker.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
label.setText("Fading");
}
});
actual and formal argument lists differ in length
Again, you should use Java 8. But if you wish to use Java 7, replace:
stage.setScene(new Scene(new StackPane(label), 100, 50));
with:
StackPane layout = new StackPane();
layout.getChildren().add(label);
stage.setScene(new Scene(layout, 100, 50));
Further recommendations
Good call on not having the text both blink and fade. Blinking text makes for pretty distracting UI, but just fading is fine.
I don't think I'd recommend fading an error message, at least until the user clicks on it or something like that. What if the user didn't see the error message before it faded away?
So I have a TextArea and as the user pastes paragraphs into it, or just writes in it, I want it to expand vertically to reveal all the available text. I.e. not to use a scrollbar in the text field itself... much like what happens on many web pages. Many users, myself included, don't like to be forced to edit in a small window. Exactly how Facebook status updates box works.
I've tried
myTextArea.autoSize()
wrapped in an
myTextArea.textProperty().addListener(new ChangeListener()....);
but that doesn't work. I think it's happy autosizing to its current size.
The left, right & top anchors are set to it's parent AnchorPane. I've tried it with the bottom attached and not attached. Ideally I'd like to grow the anchor pane as the textarea grows.
I don't mind reading the TextProperty and calculating a trigger size which I set myself... but this seems a hacky approach IF there is already a best practise. The number of properties and sub objects of javafx is sufficiently daunting that it seems like a good point to ask the question here, rather than trying to figure out how many pixels the font/paragraphs etc are taking up.
Update:
So I thought maybe I was overthinking it, and all I needed to do was to switch the scrollbars off and the rest would happen. Alas, looking for available fields and methods for "scroll", "vertical", "vbar" comes up with nothing I can use. ScrollTopProperty looks like it's for something else.
The problem; the height of textArea is wanted to be grown or shrunk while its text is changing by either user's typing or copy-pasting. Here is another approach:
public class TextAreaDemo extends Application {
private Text textHolder = new Text();
private double oldHeight = 0;
#Override
public void start(Stage primaryStage) {
final TextArea textArea = new TextArea();
textArea.setPrefSize(200, 40);
textArea.setWrapText(true);
textHolder.textProperty().bind(textArea.textProperty());
textHolder.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
if (oldHeight != newValue.getHeight()) {
System.out.println("newValue = " + newValue.getHeight());
oldHeight = newValue.getHeight();
textArea.setPrefHeight(textHolder.getLayoutBounds().getHeight() + 20); // +20 is for paddings
}
}
});
Group root = new Group(textArea);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
// See the explanation below of the following line.
// textHolder.setWrappingWidth(textArea.getWidth() - 10); // -10 for left-right padding. Exact value can be obtained from caspian.css
}
public static void main(String[] args) {
launch(args);
}
}
But it has a drawback; the textarea's height is changing only if there are line breaks (ie Enter keys) between multiple lines, if the user types long enough the text gets wrapped to multiple line but the height is not changing.
To workaround this drawback I added this line
textHolder.setWrappingWidth(textArea.getWidth() - 10);
after primaryStage.show();. It works well for long typings where user does not linebreaks. However this generates another problem. This problem occurs when the user is deleting the text by hitting "backspace". The problem occurs exactly when the textHolder height is changed and where the textArea's height is set to new value. IMO it maybe a bug, didn't observe deeper.
In both case the copy-pasting is handling properly.
Awaiting a better, i use this hacky solution.
lookup the vertical scrollbar of the textarea.
make it transparent
listen to its visible property
when the scrollbar become visible i add a row to the textarea.
The code:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class GrowGrowTextArea extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
AnchorPane root = new AnchorPane();
root.setStyle("-fx-padding:20;-fx-background-color:dodgerblue;");
final TextArea textArea = new TextArea();
AnchorPane.setTopAnchor(textArea, 10.0);
AnchorPane.setLeftAnchor(textArea, 10.0);
AnchorPane.setRightAnchor(textArea, 10.0);
root.getChildren().add(textArea);
primaryStage.setScene(new Scene(root, 400, 300));
primaryStage.show();
ScrollBar scrollBar = lookupVerticalScrollBar(textArea);
scrollBar.setOpacity(0.0);
scrollBar.visibleProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> source,
Boolean wasVisible,
Boolean isVisible) {
if (isVisible) {
textArea.setPrefRowCount(textArea.getPrefRowCount() + 1);
textArea.requestLayout();
}
}
});
}
private ScrollBar lookupVerticalScrollBar(Node node) {
if (node instanceof ScrollBar && ((ScrollBar)node).getOrientation() == Orientation.VERTICAL) {
return (ScrollBar) node;
}
if (node instanceof Parent) {
ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
for (Node child : children) {
ScrollBar scrollBar = lookupVerticalScrollBar(child);
if (scrollBar != null) {
return scrollBar;
}
}
}
return null;
}
}
I had a similar problem with creating expanding TextArea. I was creating TextArea that looks like TextField and expand vertically every time when there is no more space in line.
I have tested all solutions that I could find on this topic on stack and other sources available. I found few good solutions but neither was good enough.
After many hours of fighting, I figured out this approach.
I extended TextArea class, override layoutChildren() method and add a listener on text height.
#Override
protected void layoutChildren() {
super.layoutChildren();
setWrapText(true);
addListenerToTextHeight();
}
private void addListenerToTextHeight() {
ScrollPane scrollPane = (ScrollPane) lookup(".scroll-pane");
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
StackPane viewport = (StackPane) scrollPane.lookup(".viewport");
Region content = (Region) viewport.lookup(".content");
Text text = (Text) content.lookup(".text");
text.textProperty().addListener(textHeightListener(text));
}
private InvalidationListener textHeightListener(Text text) {
return (property) -> {
// + 1 for little margin
double textHeight = text.getBoundsInLocal().getHeight() + 1;
//To prevent that our TextArena will be smaller than our TextField
//I used DEFAULT_HEIGHT = 18.0
if (textHeight < DEFAULT_HEIGHT) {
textHeight = DEFAULT_HEIGHT;
}
setMinHeight(textHeight);
setPrefHeight(textHeight);
setMaxHeight(textHeight);
};
}
I used some of the code found in the previous answers.
The growTextAreaIfNecessary method will increase the height of textArea until the scrollbar is not visible (limited to 20 lines in this example).
The problem with this approach is that the window needs to be redrawn several times until the perfect height is found.
private ScrollBar lookupVerticalScrollBar(Node node) {
if (node instanceof ScrollBar && ((ScrollBar) node).getOrientation() == Orientation.VERTICAL) {
return (ScrollBar) node;
}
if (node instanceof Parent) {
ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
for (Node child : children) {
ScrollBar scrollBar = lookupVerticalScrollBar(child);
if (scrollBar != null) {
return scrollBar;
}
}
}
return null;
}
private void growTextAreaIfNecessary(TextArea textArea) {
Platform.runLater(() -> {
ScrollBar lookupVerticalScrollBar = lookupVerticalScrollBar(textArea);
int prefRowCount = textArea.getPrefRowCount();
if (lookupVerticalScrollBar.isVisible() && prefRowCount < 20) {
textArea.setPrefRowCount(prefRowCount + 1);
System.out.println("increasing height to: " + (prefRowCount + 1));
growTextAreaIfNecessary(textArea);
}
});
}
I have tried many hacks, most of them had jitters while typing, this to me was the perfect result:
textArea.textProperty().addListener((obs,old,niu)->{
Text t = new Text(old+niu);
t.setFont(textArea.getFont());
StackPane pane = new StackPane(t);
pane.layout();
double height = t.getLayoutBounds().getHeight();
double padding = 20 ;
textArea.setMinHeight(height+padding);
});
As I'm learning the new world of JavaFX2 I stumbled on another annoying problem. I'm developing a program with multiple scenes (~10 scenes). For that I created a small class like this:
public class SceneSelector {
...
public void setScene(Stage stage, String fxmlfilename, ObservableList ol) throws Exception{
String s = "../" + fxmlfilename;
Parent root = FXMLLoader.load(getClass().getResource(s));
root.setUserData(ol);
Scene scene = new Scene(root);
stage.setScene(scene);
//show the stage
stage.show();
}
}
This class works good enough for switching between the scenes.
Now the problem is that I sometimes need to pass data from Scene1 to Scene2. I'm trying to do this by setting the setUserData() for the new scene which basicly works exept for one thing. How can I get the userdata when the new Scene is beeing initialized? (because the Nodes are still null at that time)
Code at scene1:
//Code connected to a button that opens the new Scene
private void openLabID(ActionEvent event) throws Exception {
final Stage primaryStage = (Stage) btnNewScene.getScene().getWindow();
ObservableList<Koe> olAfTeWerkenKoeien = DA_Koe.getAfTeWerkenKoeien();
ss.setScene(primaryStage, "GUI/scenes/koe/Koe.fxml", olAfTeWerkenKoeien);
}
Code at scene2:
public void initialize(URL url, ResourceBundle rb) {
Scene s = lbl.getScene();
ObservableList<Koe> olAfTeWerkenKoeien = (ObservableList<Koe>) s.getRoot().getUserData();
System.out.println(olAfTeWerkenKoeien.size());
}
Of course Scene s gives a null value at this point (because lbl is null at this point), so I wonder, is there a method that is beeing fired right after initialize?
When I attach this code to a button on Scene2, it works like a charm, but it should be loaded automatically.
EDIT:
The setting of the data with the setMyData() method is not a problem, however retrieving it is:
public ObservableList<Koe> getMyData() {
return this.myData;
}
How can I get the CustomScene object when a controller initializes? Because doing this below will result in a NullPointerException (because btnSluiten is not initialized just yet):
#Override
public void initialize(URL url, ResourceBundle rb) {
...
Stage stage = (Stage) btnSluiten.getScene().getWindow();
CustomScene cs = (CustomScene) stage.getScene();
ObservableList<Koe> olKoe = cs.getMyData();
System.out.println(olKoe.size());
}
I believe you missed the point within the Scene object. From the Scene class documentation we can see that:
The JavaFX Scene class is the container for all content in a scene graph.
Which means that the Scene object is just a container and as such it's not supposed to hold any data.
With that in mind, you can make another static object with a field such as
private static Label lbl;
...
public static Label getLbl()
{
return MyStaticObject.Lbl;
}
...
and use it to store your lbl (or whatever object suits your information) and then statically retrieve it.
I'm doing that to set the owner of my other Stage objects from my application. I hope it helps. Cheers
If you really want your scene to be meaningful (aka store specific user data) you can extend it:
public class FooScene extends Scene {
private ObservableList myData;
public setMyData(ObservableList data) {
this.myData = data;
//handle data
}
}
The easiest way to make sure setup code is called after scene initialized it to call it by yourself:
public class SceneSelector {
...
public void setScene(Stage stage, String fxmlfilename, ObservableList ol) throws Exception{
String s = "../" + fxmlfilename;
Parent root = FXMLLoader.load(getClass().getResource(s));
// first: add root to scene
FooScene scene = new FooScene(root);
// second: apply data to scene (or root)
scene.setMyData(ol);
stage.setScene(scene);
//show the stage
stage.show();
}
}
You can use controller for scenes and pass the data through controller:
String filePath1 = "../" + fxmlfilename;
URL location1 = YourController1.class.getResource(filePath1);
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location1);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Node) fxmlLoader.load(location1.openStream());
YourController1 ctrl1 = (YourController1) fxmlLoader.getController();
Then you can assign data to the controller:
ctrl1.setUserData();
Finally, just show the scene as you want:
Scene scene = new Scene(root);
stage.setScene(scene);
//show the stage
stage.show();
In the initialize() method in the controller, just get data from controller as usual data object.
Some Addition of #Sergey Grinev :
Create A custom Scene :
package sample;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class DataPassingScene extends Scene {
public DataPassingScene(Parent parent) {
super(parent);
}
String tafsir;
public String getTafsir() {
return tafsir;
}
public void setTafsir(String tafsir) {
this.tafsir = tafsir;
}
}
Suppose your Main Class Name is App.java, Then Create a method to show new Stage :
public static void showLayout (Stage primaryStage, String fxmlFileName, String stringData) throws IOException {
Parent root = FXMLLoader.load(Objects.requireNonNull(App.class.getClassLoader().getResource(fxmlFileName)));
DataPassingScene scene = new DataPassingScene(root);
scene.setTafsir(stringData); // Here we pass the data
primaryStage.setScene(scene);
primaryStage.show();
}
Now When you want to pass the Data, Call the above method from any Where / any class in your app with some Data :
String tafsir = "This My Data" ;
try {
App.showLayout(new Stage(), "showTafsirFxml.fxml",tafsir);
} catch (IOException e) {
e.printStackTrace();
}
Then Get the data in your controller. To get the scene you have to get the stage, and to get the stage you have use one of your elements of FXML, suppose here your element is a button, called closeButton, So :
#FXML
private Button closeButton;
#Override
public void initialize(URL url, ResourceBundle rb) {
Platform.runLater(new Runnable() {
#Override public void run() {
Stage stage = (Stage) closeButton.getScene().getWindow();
DataPassingScene scene = (DataPassingScene) stage.getScene();
String s = scene.getTafsir(); // Here we get the Data
if(s!=null)
System.out.println("This is Tafsir From Highlight Table: "+s);
else
System.out.println("Data Passing Null");
}});
}
because, You have to wait some Times in above runLater, because for initializing scene take some time. Other wise scene will be null.