JavaFX: Just Declaring Nodes changes Background of other Nodes - java

I have a program that first starts up a little splash screen, and after 5 seconds it continues to a new Stage.
The strange thing is, until now it worked fine, but now that I'm starting to build the new Stage I'm declaring new Nodes in the class to use it.
Now all of the sudden the splash screen has a white background, commenting the before created nodes out will revert the image back to being transparent.
public static Pane pane = new Pane(); //this is fine
//Uncommenting this Node will change the splash screen background white
//public static TextArea textArea = new TextArea();
public static Image splashImage = new Image(Class.class.getClassLoader().getResourceAsStream("image.png"));
public static ImageView splashImageView = new ImageView(splashImage);
public static BorderPane splashPane = new BorderPane(splashImageView);
public static Scene splashScene = new Scene(splashPane);
#Override
public void start(Stage primaryStage) throws Exception {
splashScene.setFill(Color.TRANSPARENT);
primaryStage.setScene(splashScene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
Here a shortened version of my code
Could this be because of memory issues or something? I have never encountered anything like this.
Any help is appreciated.

The default style sheet is only loaded if a control (i.e an instance of Control or one of its subclasses) is created. (The idea behind this is to avoid the performance overhead of loading CSS for applications that manage all their own graphics and don't use any controls, such as games or simulations.)
The default stylesheet sets the background color of the root node (the splashPane in your example) to a very light grey (specifically, it is 26.4% brighter than the color #ececec).
Since the text area is the only control in your class, creating it causes the default style sheet to be loaded, which sets the background color of the splashPane to a very light grey.
If you need to instantiate controls and want the background of the pane to be transparent, you need to specify that in an external CSS:
splashStyle.css:
.root {
-fx-background-color: transparent ;
}
And
#Override
public void start(Stage primaryStage) throws Exception {
splashScene.setFill(Color.TRANSPARENT);
splashScene.getStylesheets().add("splashStyle.css");
primaryStage.setScene(splashScene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
(As a quick check that this will work, you can just test with
splashPane.setStyle("-fx-background-color: transparent; ");
)

Related

My Scene changes its color once I add element to it [duplicate]

I have a program that first starts up a little splash screen, and after 5 seconds it continues to a new Stage.
The strange thing is, until now it worked fine, but now that I'm starting to build the new Stage I'm declaring new Nodes in the class to use it.
Now all of the sudden the splash screen has a white background, commenting the before created nodes out will revert the image back to being transparent.
public static Pane pane = new Pane(); //this is fine
//Uncommenting this Node will change the splash screen background white
//public static TextArea textArea = new TextArea();
public static Image splashImage = new Image(Class.class.getClassLoader().getResourceAsStream("image.png"));
public static ImageView splashImageView = new ImageView(splashImage);
public static BorderPane splashPane = new BorderPane(splashImageView);
public static Scene splashScene = new Scene(splashPane);
#Override
public void start(Stage primaryStage) throws Exception {
splashScene.setFill(Color.TRANSPARENT);
primaryStage.setScene(splashScene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
Here a shortened version of my code
Could this be because of memory issues or something? I have never encountered anything like this.
Any help is appreciated.
The default style sheet is only loaded if a control (i.e an instance of Control or one of its subclasses) is created. (The idea behind this is to avoid the performance overhead of loading CSS for applications that manage all their own graphics and don't use any controls, such as games or simulations.)
The default stylesheet sets the background color of the root node (the splashPane in your example) to a very light grey (specifically, it is 26.4% brighter than the color #ececec).
Since the text area is the only control in your class, creating it causes the default style sheet to be loaded, which sets the background color of the splashPane to a very light grey.
If you need to instantiate controls and want the background of the pane to be transparent, you need to specify that in an external CSS:
splashStyle.css:
.root {
-fx-background-color: transparent ;
}
And
#Override
public void start(Stage primaryStage) throws Exception {
splashScene.setFill(Color.TRANSPARENT);
splashScene.getStylesheets().add("splashStyle.css");
primaryStage.setScene(splashScene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
(As a quick check that this will work, you can just test with
splashPane.setStyle("-fx-background-color: transparent; ");
)

How can I center a ScrollPane that wraps a fixed-sized Canvas in a BorderPane?

In a JavaFX application I need to center a fixed-sized Canvas wrapped by a StackPane, then a ScrollPane, within a BorderPane. The problem is that when I include the ScrollPane, the component tree is no longer centered in the middle of the center area of the BorderPane. One solution I tried is to fix the max size of the ScrollPane. This works (the components become centered), but creates a different problem: when the viewport area is insufficient in any one dimension (say, width), both scrollbars will appear anyways. Because ScrollPane's size is bounded, the extra space occupied by the scrollbar in one dimension will cause the viewport to shrink in the other dimension and the max size property, required for centering, will prevent allowing more space for it.
Here is a working demonstration of the problem:
public final class Minimal extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Canvas canvas = new Canvas(200,200) {
#Override
public boolean isResizable() {
return false;
}
};
StackPane pane = new StackPane(canvas);
pane.setStyle("-fx-border-insets: 4; -fx-border-style: solid;");
ScrollPane scroll = new ScrollPane(pane);
// scroll.setMaxSize(212, 212); // Imperfect Solution
BorderPane root = new BorderPane();
root.setCenter(scroll);
stage.setScene(new Scene(root));
stage.show();
}
}
With the line commented out, when resized, the frame shows up as:
If I fix the max size: then both scroll bars show up at once (notice how the vertical one is not necessary:
The closest I found was this question, which does not really have an answer. Unfortunately, this solution, which seems to work well in Swing, does not appear to do anything since I'm already using a wrapper (the StackPane), and it's not helping. I'm hoping there's a solution that exclusively relies on layouts, without having to revert to writing listeners for resize events or binding to size properties, etc.
Let the StackPane fill the entire ScrollPane. The StackPane will then center the canvas for you:
The stackpane will attempt to resize each child to fill its content area. If the child could not be sized to fill the stackpane (either because it was not resizable or its max size prevented it) then it will be aligned within the area using the alignment property, which defaults to Pos.CENTER.
Thus, all you need to do is set the ScrollPane’s ‘fitTo…’ properties, so the StackPane will fill it:
scroll.setFitToWidth(true);
scroll.setFitToHeight(true);

Unresizable ever JavaFX Window

My problem is that my JavaFX window expands further than it should at the bottom, thus showing a weird blank background...
I set stage.setResizable(false) but it doesn't seem to work. I also set
stage.setMinWidth(1280);
stage.setMaxWidth(1280);
stage.setMinHeight(800);
stage.setMaxHeight(800);
I think it's due to some ImageView bigger than the window, but I really would like my window to stick to the max I set and be absolutely not resizable ever.
Here's what it looks like : click here
I also noticed it happens only when I set stage.initStyle(StageStyle.TRANSPARENT).
But I don't want my window to be decorated with stage.initStyle(StageStyle.DECORATED)... :(
Thank you in advance for your help. :)
Have you tried directly using setWidth and setHeight:
stage.setWidth(1280);
stage.setHeight(800);
I think the setMaxWidth, setMinHeight... etc. only works on a decorated screen because its main purpose is to limit the sizes the user can set the window. Here's my example:
public class FixedWindowSize extends Application
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception
{
Pane p = new Pane();
p.setBackground(new Background(new BackgroundFill(Color.RED, null, null)));
p.setMinSize(6000, 6000); //Make this go out beyond window bounds.
Scene s = new Scene(p);
primaryStage.setScene(s);
primaryStage.initStyle(StageStyle.TRANSPARENT);
//This doesn't work
//primaryStage.setMinWidth(1280);
//primaryStage.setMaxWidth(1280);
//primaryStage.setMinHeight(800);
//primaryStage.setMaxHeight(800);
//This should work.
primaryStage.setWidth(1280);
primaryStage.setHeight(800);
primaryStage.show();
}
}

JavaFX: Creating a button resets my stage/scene/panes background color

I'm making a Javafx game with a pane to hold my elements. The background color is set to black (instead of the default white) using the Scene.setFill(); method.
public class backgroundColor extends Application{
#Override
public void start(Stage stage) throws Exception {
Pane background = new Pane();
Scene scene = new Scene(background, 800, 600);
scene.setFill(Color.BLACK);
//Button button = new Button("Just a button");
stage.setScene(scene);
stage.show();
}
}
This works fine and the background is displayed as black... However, when I un-comment the button line, the fill color is suddenly displayed as white. Notice that the button is only initialized, it isn't being used, eclipse even gives me the warning that the data field "button" is unused.
Is this a weakness of Scene.setFill()? Or is this a unintended feature of creating a controller?
I am working on a game where I switch between different displays by changing the scene's "root" property using Scene.setRoot(), and before I created a button the color was fine no matter how many times I set different panes as the scene's new root node. However, after I created the button I discovered that I had to use a significantly more complicated workaround:
background.setBackground(new Background(new BackgroundFill(Color.BLACK, null, null)));
to fix the issue. Is there a better way to fix the background for the scene, or do I really have to set the background manually for all panes?

How to resize Swing control which is inside SwingNode in JavaFX8?

How to resize Swing control which is inside SwingNode in JavaFX8?
Sometimes, I has controls resized inside SwingNode. But SwingNode seems to resist this.
It is said in resize() apidoc, that
Applications should not invoke this method directly. If an application
needs to directly set the size of the SwingNode, it should set the
Swing component's minimum/preferred/maximum size constraints which
will be propagated correspondingly to the SwingNode and it's parent
will honor those settings during layout.
But apparently it does not work.
Example code is below.
The question is: how to allow control to turn bigger?
public class Try_Sizes_01 extends Application {
private static final Logger log = LoggerFactory.getLogger(Try_Sizes_01.class);
private static final String text = "Very Long Text For Appear On Button ";
private static int position = 7;
//private JButton button = new JButton("short");
private JButton button = new JButton(text.substring(0, position));
private SwingNode swingNode = new SwingNode();
{
swingNode.setContent(button);
}
#Override
public void start(Stage stage) throws Exception {
Group group = new Group();
group.getChildren().add(swingNode);
Scene scene = new Scene(group);
stage.setTitle("Try_Sizes_01");
stage.setScene(scene);
stage.show();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/*
button.setText(button.getText() + text.charAt(position));
position++;
if( position >= text.length() ) {
position=0;
}
*/
button.setPreferredSize(new Dimension((int)button.getPreferredSize().getWidth()+10, (int)button.getPreferredSize().getHeight()));
button.setMinimumSize(new Dimension((int)button.getPreferredSize().getWidth(), (int)button.getPreferredSize().getHeight()));
//button.revalidate();
//button.setBounds(0, 0, (int)button.getBounds().getWidth()+10, (int)button.getBounds().getHeight());
Platform.runLater(new Runnable() {
#Override
public void run() {
//swingNode.autosize(); // does not work
//swingNode.resize(button.getBounds().getWidth(), button.getBounds().getHeight()); // does not work and cancels button resizing
//swingNode.setContent(button); // works sometimes but imperfect
}
});
log.info("Swing thread");
log.info("Preferred width is now = {}", button.getPreferredSize().getWidth());
log.info("Bounds width is now = {}", button.getBounds().getWidth());
}
}).start();
}
});
}
public static void main(String[] args) {
launch(args);
}
}
After fighting for hours with basically the same issue, I finally figured out what was going on.
Basically, the problem is that the parent of the SwingNode is trying to set its size when layout occurs, based on the size of the parent. So when you resize your button, and then trigger a layout, the parent of the SwingNode sets it back to its default size. This is occurring because SwingNode overrides the isResizable() method to return true, giving permission to its parent objects to resize it.
In order to avoid this, you can:
Create a custom subclass of SwingNode which overrides isResizable() to false,
or:
Call setAutosizeChildren(false) on the Group which contains the SwingNode.
The latter technique will probably need to be used if you are defining your classes in FXML.
Note, by the way, that you can still call resize(width,height) on a SwingNode even if it overrides isResizable() to false.
I'm not sure if its exactly the same case, but seems related in the sense of getting swing components to size properly with the parent containers. In my case I had a SwingNode containing a JFreeChart (ChartPanel), which I simply couldn't get to resize properly when the parent frame (a border pane within a SplitPane) was itself resized. In the end i simply added a listener to the height/width properties:
pane.widthProperty().addListener((w,o,n)->c.resizeChart((int)n.intValue(), (int)pane.getHeight()));
pane.heightProperty().addListener((w,o,n)->c.resizeChart((int)pane.getWidth(), (int)n.intValue()));
Nothing else I tried could emulate this.
Thanks
I found the pane listener helps but due to the proprietary nature of my component it still didn't resize. I was using fxml and attempting to place the SwingNode inside a Pane for layout purposes. I then I noticed a number of the examples used a StackPane rather than just a Pane and suddently have just made this change the code worked. This was inside a AnchorPane which also seemed to ensure the initial display of the component filled all the available space. In summary a StackPane within the AnchorPane with all the Anchors set to 0 ensured the controlled filled all the initial available space and then did all the resizing, when the manual resize listeners where added it all started working.
pane.widthProperty().addListener((w,o,n)->c.resizeChart((int)n.intValue(), (int)pane.getHeight()));
pane.heightProperty().addListener((w,o,n)->c.resizeChart((int)pane.getWidth(), (int)n.intValue()));

Categories