Coding a GUI in a Java project I've encountered a problem with JavaFX.
I've not found any soulutions for my specific problem, so here I am:)
Is it possible to let a JavaFX scene be resizeable by the user and at the same time have it not resized by child nodes, that are bigger, than the window?
Here is some sample code:
#Override
public void startGUI(int width, int height) {
this.main = new MainWindow(this, this.logic);
this.scene = new Scene(this.main.getRoot());
this.main.setScene(this.scene);
this.primaryStage.setScene(this.scene);
this.primaryStage.setMinHeight(height);
this.primaryStage.setMinWidth(width);
}
The 'MainWindow' has got a childnode, that can be very big (>1024x768).
I want the window not to be resized by this node, but at the same time, the user should be able to resize the window by dragging its borders.
Use a Scene constructor which specifies initial size constraints.
For example:
Scene scene = new Scene(root, 600, 400);
That way the initial size of the Scene will be taken from these constraints rather than calculated from the preferred size of the root node.
Related
My layout looks like that:
Panel is a VBox and Content is a HBox. Both are contained in an HBox.
I need to make panel fixed size, so right now I'm doing it like that:
VBox panel = new VBox();
double fixedWidth = Screen.getPrimary().getBounds().getWidth() / 10;
panel.setMinWidth(fixedWidth);
panel.setMaxHeight(fixedWidth);
... but what if user's screen resolution change? That code doesn't handle that and I'm afraid the Screen class doesn't provide any type of callback.
Your title and most of your question indicate you want panel to use 10% of the screen’s width, and content to use 90% of the screen’s width. However, you also use the term “fixed width” which is something different; namely, that panel would have the same width at all times, regardless of screen size.
I shall assume you meant the first concept: that you want panel to use 10% of the width and content to use 90% of the width.
Instead of an HBox, use a GridPane. Set its column constraints to 10% and 90%.
ColumnConstraints panelWidth = new ColumnConstraints();
panelWidth.setPercentWidth(10);
panelWidth.setFillWidth(true);
ColumnConstraints contentWidth = new ColumnConstraints();
contentWidth.setPercentWidth(90);
contentWidth.setFillWidth(true);
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setFillHeight(true);
rowConstraints.setVgrow(Priority.ALWAYS);
GridPane pane = new GridPane();
pane.addRow(0, panel, content);
pane.getColumnConstraints().setAll(panelWidth, contentWidth);
pane.getRowConstraints().setAll(rowConstraints);
Based on your current solution, you seem to be giving 10% size to your panel which means 90% is the content panel. You can directly bind screen size to your scene object and initialize your scene with screen size. It will make the whole application reactive to the screen resolution changes. Here is a sample from my code on how I do it:
final Scene scene = new Scene(root,width,height);
logger.debug("Scene Created");
stage.centerOnScreen();
stage.setScene(scene);
final ChangeListener<Number> listener = new ChangeListener<Number>()
{
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue)
{
logger.debug("Scene Resize Started");
Scale scale = new Scale();
scale.xProperty().bind(scene.widthProperty().divide(width));
scale.yProperty().bind(scene.heightProperty().divide(height));
scale.setPivotX(0); scale.setPivotY(0);
root.getTransforms().clear();
root.getTransforms().addAll(scale);
logger.debug("Scene Resize Ended");
}
};
scene.widthProperty().addListener(listener);
scene.heightProperty().addListener(listener);
This takes care of resize as well as resolution changes. The width and height variable in the start are width and height captured from Screen of the user.
I am trying to change the brightness of the whole scene in javafx. This is what my code looks like at the moment:
public void start(Stage primaryStage) {
StackPane root = new StackPane();
Rectangle rec1 = new Rectangle();
rec1.setWidth(300);
rec1.setHeight(300);
rec1.setFill(javafx.scene.paint.Color.RED);
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setBrightness(-0.8);
root.setEffect(colorAdjust);
Scene scene = new Scene(root, 1920, 1080);
root.getChildren().add(rec1);
primaryStage.setFullScreen(true);
primaryStage.setScene(scene);
primaryStage.show();
}
The problem is, like this only the brightness of the rectangle changes, but not the brightness of the whole scene. I also need to change the brightness of the "background". Is there any way to do that?
Strangely this seems to be fixed by adding a node to the StackPane in order for it to adjust the color to everything, not just shapes. When shapes are the only thing visible, that is all that's ColorAdjusted. At least one Node must be present. Changing the one line to the following will do what you want:
root.getChildren().addAll(rec1, new Label());
However, this could have consequences to your project by shift something slightly even though it's empty. We can get around this by making it invisible and not-managed so that it isn't considered in layout calculations.
Label fix = new Label("Fix colorAdjust whole scene.");
fix.setVisible(false);
fix.setManaged(false);
Scene scene = new Scene(root, 500, 500);
root.getChildren().addAll(rec1, fix);
I am having problems with positioning my images in my JavaFX program using setX and setY on the ImageView's for the images. I am not sure what is the problem? Appreciate any help given!
Here's my code:
Image rocket2 = new Image("img/Rocket.png");
ImageView iv1 = new ImageView(rocket2);
iv1.setX(60);
iv1.setY(44);
Image rocket1 = new Image("img/Rocket.png");
ImageView iv2 = new ImageView(rocket1);
iv2.setX(5);
iv2.setY(16);
Image background = new Image("img/space.png");
ImageView iv3 = new ImageView(background);
StackPane root = new StackPane();
root.getChildren().addAll(iv3, iv2, iv1);
Scene scene = new Scene(root, 300, 300);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.setTitle("Space stuff");
primaryStage.show();
I suspect that something goes wrong because I have set a background image.
img here on what's happening
Don't place your items in a StackPane if you want to explicitly define their layout positions (setX and setY). A StackPane is a managed layout pane. It will automatically set the location of items added to it (default is to center everything one on top of the other inside the StackPane).
Instead use a Pane or a Group, which are not managed layout panes and allow you to layout your content in the Pane however you wish.
To layout your content inside the Pane, you can use setLayoutX and setLayoutY rather than setX and setY, though I guess setX and setY should also work (I've never used them before on ImageView).
Pavlo, already created an answer while I was typing this (so this answer is a duplicate), but I'll leave this as it adds a bit more explanation.
Replacing StackPane with Pane should solve the problem.
If you however want for whatever reason to position a item in a StackPane you can use setTranslateX and setTranslateY. Theese methods set the x and y values AFTER the StackPane has done its layouting, so you will have a different starting position depending on the Alignment your StackPane uses for its children.
I'm new to JavaFX. I'm trying to create a simple centred menu that contains text with buttons below.
I've created two elements, Text title and Button testButton. Then I created StackPane stackPane. I'm then trying to add the two elements to the stackPanes children and adding that to a new Scene. However, only the last element shows up.
How can I add multiple elements to the StackPane?
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Test Title");
Text title = new Text("hey!");
StackPane.setAlignment(title, Pos.TOP_CENTER);
Button testButton = new Button("Testing");
StackPane.setAlignment(testButton, Pos.TOP_CENTER);
StackPane stackPane = new StackPane();
stackPane.setPrefSize(300, 300);
stackPane.setPadding(new Insets(25, 0, 0, 0));
stackPane.getChildren().add(title);
stackPane.getChildren().add(testButton);
Scene scene = new Scene(stackPane);
primaryStage.setScene(scene);
primaryStage.show();
}
I want to reference the official documentation here: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/StackPane.html, especially:
StackPane lays out its children in a back-to-front stack.
The z-order of the children is defined by the order of the children list with the 0th child being the bottom and last child on top. If a border and/or padding have been set, the children will be layed out within those insets.
Now, to answer your question: You do it as you did, but you probably want an offset as both the children are at the same position, hence the one later added is overlaying all the previous ones.
You can check that by changing e.g.
Text title = new Text("Adding a very, very, very, very, very, very long text here... now that vile button should not overlap me anymore!");
or setting the alignment differently.
If you don't want to bother with the optimal layout by manually positioning, it's probably better to use another Pane that does that for you, e.g. one of the direct known subclasses here: https://docs.oracle.com/javafx/2/api/javafx/scene/layout/Pane.html
This is kind of a vague question, but I'm trying to create a code editor using JavaFX Canvas technologies and its being incredibly slow for what I'd like.
Take the following code for example
public class JavaFXApplication13 extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
int extent = 6300;
System.out.println(System.getProperty("java.version"));
Canvas cvs = new Canvas(extent,extent);
ScrollPane scpn = new ScrollPane();
root.setTop(cvs);
scpn.setContent(root);
root.autosize();
scpn.autosize();
GraphicsContext ctx = cvs.getGraphicsContext2D();
for(int i = 0; extent / 300 > i; i++){
ctx.setFill(Color.RED);
ctx.fillRect(i*300, 0, 100, extent);
ctx.setFill(Color.BLUE);
ctx.fillRect(i*300+100, 0, 100, extent);
ctx.setFill(Color.GREEN);
ctx.fillRect(i*300+200, 0, 100, extent);
}
//// root.getChildren().add(btn);
Scene scene = new Scene(scpn, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
If you try to slide pane around, theres a good few seconds between when you move the cursor and when the scrollbar and the scroll pane update. This has to do with the size of the canvas, which is set to 6300, which is nothing. I can open NotePad and get line heights in the million and its able to draw them with ease.
Performance is even worse when trying to draw on a large sized canvas, simple
onKeyPress((a) -> drawText(a.getText(), ...));
takes seconds to process.
I guess what I'm trying to say is, is this performance normal? or should I just suck it up and move on to something more powerful such as OpenGL?
A code editor should be virtual and only draw the lines you see on screen! So IMHO your use of canvas is completely incorrect!
Canvas at its heart can be seen like a buffered image you can draw on and on the OpenGL / Directx side only sees a image.
Why reinvent the wheel there are at least 2 opensource javafx code editors. See https://tomasmikula.github.io/blog/ and http://tomsondev.bestsolution.at/2014/08/11/efxclipse-1-0-new-features-styledtext-control-to-build-a-code-editor-framework/
I tested JavaFX for a game project about 6 months ago, I was drawing 10000 rectangles and using an animation timer to change the color of each rectangle 60 times a second.
I found that using the canvas for this was really slow and was getting about a frame a second. I changed to just using the scene graph by just adding JavaFX rectangle nodes to a Group node and it worked with no lag.
I was surprised that using JavaFX objects was way more efficient that using the canvas, I am now working on my second JavaFX 2 game using nodes in the scene graph.