Is there any way to make fullscreen(and if possible resizing too) to instead of rearranging everything (actually what it does is to rearrange the elements like resizing but to the whole screen) to make an actual fullscreen mode? (like games that what usually do is change screen resolution), so that buttons and text grows accordingly to the size of the screen/window
Also how can I remove the message and the effect on click the "esc" key to exit the fullscreen mode?
EDIT: use this way to make resizeable
#Override public void start(Stage stage) throws Exception{
final int initWidth = 720; //initial width
final int initHeight = 1080; //initial height
final Pane root = new Pane(); //necessary evil
Pane controller = new CtrlMainMenu(); //initial view
controller.setPrefWidth(initWidth); //if not initialized
controller.setPrefHeight(initHeight); //if not initialized
root.getChildren().add(controller); //necessary evil
Scale scale = new Scale(1, 1, 0, 0);
scale.xProperty().bind(root.widthProperty().divide(initWidth)); //must match with the one in the controller
scale.yProperty().bind(root.heightProperty().divide(initHeight)); //must match with the one in the controller
root.getTransforms().add(scale);
final Scene scene = new Scene(root, initWidth, initHeight);
stage.setScene(scene);
stage.setResizable(true);
stage.show();
//add listener for the use of scene.setRoot()
scene.rootProperty().addListener(new ChangeListener<Parent>(){
#Override public void changed(ObservableValue<? extends Parent> arg0, Parent oldValue, Parent newValue){
scene.rootProperty().removeListener(this);
scene.setRoot(root);
((Region)newValue).setPrefWidth(initWidth); //make sure is a Region!
((Region)newValue).setPrefHeight(initHeight); //make sure is a Region!
root.getChildren().clear();
root.getChildren().add(newValue);
scene.rootProperty().addListener(this);
}
});
}
There are a couple of ways to resize your UI.
Scale by Font Size
You can scale all controls by setting -fx-font-size in the .root of your scene's style sheet.
For example, if you apply the following stylesheet to your scene, then all controls will be doubled in size (because the default font size is 13px).
.root {
-fx-font-size: 26px;
}
The above will work to scale controls, which is fine for things which are completely control based, but not so good for things which are graphic and shape based.
Scale by Transform
Apply a Scale transform pivoted at (0,0) to your scene's root node.
Scale scale = new Scale(scaleFactor, scaleFactor);
scale.setPivotX(0);
scale.setPivotY(0);
scene.getRoot().getTransforms().setAll(scale);
To scale a game I developed which includes graphics and various shapes, I used a letter boxing technique which sized the game window to a constant aspect ratio, (similar to the letter boxing you see when you watch a 4:3 tv show on a 16:9 screen).
The SceneSizeChangeListener in the code below listens for changes to the scene size and scales the content of the scene appropriate to the available scene size.
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;
import org.jewelsea.games.supersnake.layout.LayoutController;
import java.io.IOException;
import java.util.ResourceBundle;
/* Main JavaFX application class */
public class SuperSnake extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(final Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("layout/layout.fxml"),
ResourceBundle.getBundle("org.jewelsea.games.supersnake.layout.text")
);
Pane root = (Pane) loader.load();
GameManager.instance().setLayoutController(loader.<LayoutController>getController());
Scene scene = new Scene(new Group(root));
stage.setScene(scene);
stage.show();
GameManager.instance().showMenu();
letterbox(scene, root);
stage.setFullScreen(true);
}
private void letterbox(final Scene scene, final Pane contentPane) {
final double initWidth = scene.getWidth();
final double initHeight = scene.getHeight();
final double ratio = initWidth / initHeight;
SceneSizeChangeListener sizeListener = new SceneSizeChangeListener(scene, ratio, initHeight, initWidth, contentPane);
scene.widthProperty().addListener(sizeListener);
scene.heightProperty().addListener(sizeListener);
}
private static class SceneSizeChangeListener implements ChangeListener<Number> {
private final Scene scene;
private final double ratio;
private final double initHeight;
private final double initWidth;
private final Pane contentPane;
public SceneSizeChangeListener(Scene scene, double ratio, double initHeight, double initWidth, Pane contentPane) {
this.scene = scene;
this.ratio = ratio;
this.initHeight = initHeight;
this.initWidth = initWidth;
this.contentPane = contentPane;
}
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
final double newWidth = scene.getWidth();
final double newHeight = scene.getHeight();
double scaleFactor =
newWidth / newHeight > ratio
? newHeight / initHeight
: newWidth / initWidth;
if (scaleFactor >= 1) {
Scale scale = new Scale(scaleFactor, scaleFactor);
scale.setPivotX(0);
scale.setPivotY(0);
scene.getRoot().getTransforms().setAll(scale);
contentPane.setPrefWidth (newWidth / scaleFactor);
contentPane.setPrefHeight(newHeight / scaleFactor);
} else {
contentPane.setPrefWidth (Math.max(initWidth, newWidth));
contentPane.setPrefHeight(Math.max(initHeight, newHeight));
}
}
}
}
Here is a screenshot where you can see the letterboxing and scaling taking effect. The green grass in the middle is the main game content screen and scales up and down to fit the available screen area. The wood texture around the outside provides a flexibly sized border which fills in the area where the black letterbox bars would normally be if you were watching a tv program at a different aspect ratio to your screen. Note that the background in the screenshot below is blurry at the title page because I make it so, when the game starts, the blur effect is removed and the view is crisp regardless of the size.
Windowed version:
Scaled full screen version:
You might think that the scaling method above might make everything go all blocky and pixelated, but it doesn't. All font's and controls scale smoothly. All standard drawing and graphic commands and css based styles scale smoothly as they are all vector based. Even bitmapped images scale well because JavaFX uses fairly high quality filters when scaling the images.
One trick to get good scaling on images is to provide high resolution images, so that when the screen scales up, the JavaFX system has more raw data to work from. For example, if the preferred window size for an app is quarter of the screen size and it contains a 64x64 icon, instead use a 128x128 icon, so that when the app is put in full screen and all elements scaled, the scaler has more raw pixel data samples to use for interpolating values.
The scaling is also fast as it is hardware accelerated.
how can I remove the message and the effect on click the "esc" key to exit the fullscreen mode?
It's not possible to remove the full screen exit message in JavaFX 2.2, it will be possible in JavaFX 8:
RT-15314 Allow trusted apps to disable the fullscreen overlay warning and disable the "Exit on ESC" behavior
It will be nice when that is done, because then my games won't have that "look at me - I look like a beta" feel about them.
"Also how can I remove the message and the effect on click the "esc" key to exit the fullscreen mode?"
Use this code :
stage.setFullScreenExitHint("");
It will change the string message "Press Esc to quit Fullscreen mode" into empty string so it will not show up.
You may copy this into JavaFXApplication
Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
double width = resolution.getWidth();
double height = resolution.getHeight();
double w = width/1280; // your window width
double h = height/720; // your window height
Scale scale = new Scale(w, h, 0, 0);
root.getTransforms().add(scale);
Related
I have an image saved in my database that is passed to an image as a byte array and then loaded to the Image view. However, I can't get it to fill the imageView. I use the following code:
package com.example.AppPrototipo.ui.tourist;
imports...
#Component
public class ExperienceController {
#FXML
Pane imagePane;
#FXML
ImageView imageViewPrincipal;
private final ExperienceRepository experienceRepository;
public ExperienceController(ExperienceRepository experienceRepository) {
this.experienceRepository = experienceRepository;
}
#FXML
private void initialize(){
Experience experience = experienceRepository.findById(1);
Image image = new Image(new ByteArrayInputStream(experience.getImages().get(0).getImageData()));
imageViewPrincipal.setImage(image);
imageViewPrincipal.fitWidthProperty().bind(imagePane.widthProperty());
imageViewPrincipal.fitHeightProperty().bind(imagePane.heightProperty());
}
}
This is the result i get:
The desired result would be that the image fills the whole width (fill the black side) by cropping the top and bottom sides and remaining centered. Would anyone be able to help me?
Assuming you're setting the preserveRatio property to true on the ImageView, and as matt stated is his comment, you only need to set one of them, say fitWidth, and the fitHeight will be calculated using the image ratio.
the problem is that the ratios of the image and the pane don't match so you need to do some cropping using setViewport, and it would be best to do the cropping when the pane's height or width change.
What you need to do is to calculate the ratio of the image, and compare it to the ratio of the pane, the comparison will let you decide whether to keep the original width or original height of the image, and you'll calculate the other using the pane's ratio.
Not really sure if that's the best practice but here's the code for what i have described
double oldImageWidth = image.getWidth(), oldImageHeight = image.getHeight(); //saving the original image size and ratio
double imageRatio = oldImageWidth / oldImageHeight;
imageViewPrincipal.setImage(image);
ChangeListener<Number> listener = (obs, ov, nv) -> {
double paneWidth = imagePane.getWidth();
double paneHeight = imagePane.getHeight();
double paneRatio = paneWidth / paneHeight; //calculating the new pane's ratio
//after width or height changed
double newImageWidth = oldImageWidth, newImageHeight = oldImageHeight;
if (paneRatio > imageRatio) {
newImageHeight = oldImageWidth / paneRatio;
} else if (paneRatio < imageRatio) {
newImageWidth = oldImageHeight * paneRatio;
}
imageViewPrincipal.setViewport(new Rectangle2D( // The rectangle used to crop
(oldImageWidth - newImageWidth) / 2, (oldImageHeight - newImageHeight) / 2, //MinX and MinY to crop from the center
newImageWidth, newImageHeight) // new width and height
);
imageViewPrincipal.setFitWidth(paneWidth);
};
imagePane.widthProperty().addListener(listener);
imagePane.heightProperty().addListener(listener);
And here is how it looks
I would like an explanation as to why some white space appears around my content when I set the stage's re-sizable property to false. I want to prevent the user from resizing the window, but keep the window so that there is no white space showing.
Things I have tried:
I have tried setting the min and max height of every element, pane, grid, stage, etc... I have tried setting the margins and paddings and insets to zero. I also tried something weird I read online that involved setting the insets to -1. Some of these work, but they involve seemingly random values needing to be added or subtracted from the GAME_HEIGHT and GAME_WIDTH. For example, setting
Scene scene = new Scene(pane, GAME_WIDTH-12, GAME_HEIGHT-12);
works but seems too arbitrary and it feels wrong to hard-code random 12's in.
Here is the minimum code needed to recreate what is happening:
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
final int GAME_HEIGHT = 480;
final int GAME_WIDTH = 736;
Image img = new Image("file:test.gif");
GridPane grid = new GridPane();
Pane pane = new Pane();
for(int row=0; row<15; row++)
for(int column=0; column<23; column++) {
ImageView view = new ImageView(img);
view.setViewport(new Rectangle2D(0, 0, 32, 32));
grid.add(view, column, row);
}
// Imageview viewports are 32x32
// 15*32 = 480 = GAME_HEIGHT
// 23*32 = 736 = GAME_WIDTH
pane.getChildren().addAll(grid);
Scene scene = new Scene(pane, GAME_WIDTH, GAME_HEIGHT);
primaryStage.setScene(scene);
//primaryStage.setResizable(false); // commenting this out makes the game window the correct size
primaryStage.show();
}
1. Before setting the stage resizable to false.
2. After setting resizable white space appears on the right and bottom.
3. After setting the stages max height and width, it zoom cuts the content off.
How can I fill in JavaFX a 3D Sphere with a linear gradient like a 2d Circle?
I work with the JavaFX Scene Builder.
As #mohsenmadi has pointed out, the diffuse color doesn't allow you using other than one single color.
But you can have different colors on the sphere by using an image as a diffuse map.
Based on your first image, I've created this texture image (called diffuse.jpg, and placed under the same folder as the JavaFX class):
You can create now your bicolored sphere:
#Override
public void start(Stage primaryStage) throws Exception {
// 3D
Sphere sphere = new Sphere(5);
PhongMaterial phongMaterial = new PhongMaterial();
phongMaterial.setDiffuseMap(new Image(getClass().getResource("diffuse.jpg").toExternalForm()));
sphere.setMaterial(phongMaterial);
...
}
So you will see this:
Note that you may have some side effects on the poles.
You can also have a look at the FXyz project, a library with aditional JavaFX 3D complex shapes, and also complex texture options.
For instance, you can use a density map to create the same effect you want, but without providing the texture image.
Under org/fxyz/shapes/primitives you can find several primitives like SegmentedSphereMesh.
Like an sphere you can create one giving the number of divisions, the crop divisions (0 in this case for x and y), the radiuos, and the center:
SegmentedSphereMesh sphere = new SegmentedSphereMesh(200,0,0,100,new Point3D(0f,0f,0f));
Now you can define the function:
Function<Point3D, Number> dens = p->p.y>0?1:0;
and apply it, with the number of colors (2 in this case):
sphere.setTextureModeVertices3D(2,dens);
Now you will have this:
Now you won't have side effects on the poles, and you could modify this function easily to other cases.
Note that you can add create your own palette of colors or play with the HSB function under org/fxyz/utils/Palette.
The way to achieve gradient-like effects on 3D shapes is by applying lighting material and lighting position. You can't simply apply two colours that gradually transform into each other. I cooked for you a small app that shows just how to achieve this.
public class ShadedSphere extends Application {
public void start(Stage stage) {
StackPane layout = new StackPane();
layout.setPrefSize(300, 300);
Scene scene = new Scene(layout);
createScene(scene);
stage.setScene(scene);
stage.show();
}
private void createScene(Scene scene) {
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(Color.ORANGE);
material.setSpecularColor(Color.BLACK);
Sphere sphere = new Sphere(100);
sphere.setMaterial(material);
Pane root = (Pane) scene.getRoot();
root.getChildren().add(sphere);
}
public static void main(String[] args) {
launch(args);
}
}
Which will give you this:
If you change the location of the sphere (e.g., using setTranslateX() and same for Y and Z), you should notice different effects of lighting on it; so the next thing for you to grasp is how to control location of lighting fixtures. Also, lights can have colour! Which means you can achieve even Northern Lights effects if you want to see cool stuff.
To learn a bit more about lighting, camera and effects, see this link.
This code will create a 3d scene that is 300x300 large. The viewport won't resize when I resize the containing window/stage.
Parent doesn't have any width or height properties. How do I adjust the size of the Parent and/or SubScene to the changing window size?
bind it to the parent
SubScene subscene = new SubScene(root, 1024, 768, true, null);
subscene.setFill(Color.GREY);
subscene.setCamera(camera);
StackPane stackPane = new StackPane();
stackPane.getChildren().add(subscene);
subscene.heightProperty().bind(stackPane.heightProperty());
subscene.widthProperty().bind(stackPane.widthProperty());
I found it is also important to set the managed property of the SubScene object to false.
subscene.setManaged(false);
This way, the SubScene object's size will not impact the size of its parent StackPane object and resizing will also work when reducing the StackPane object's size.
With the following approach you can put your SubScene into any class that extends the Pane class (e.g. BorderPane, GridPane, etc.). Also the subScene can have a different size from your Pane:
public class GuiControler extends BorderPane implements Initializable,ChangeListener {
//Set a changeListener to the Stage's Window and Implement the ChangeListener in the class where you want to make the subScene scaling.
stage.widthProperty().addListener(this);
stage.heightProperty().addListener(this);
//....
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
double width = stage.getWidth();
double height = stage.getHeight();
if(observable.equals(this.widthProperty())) {
double scale = width / 400; // 400 is my initial width size of the stage (main java app window) window
subScene.setWidth(200*scale); // 200 is my initial size of the subscene window
}else if(observable.equals(this.heightProperty())){
double scale = height / 400; // 400 is initial size for stage height window
subScene.setHeight(250*scale); // 250 is initial size for subScene width
}
}
}
Ypu may want to use getTransforms().add(new Scale(parameter1, para2,...));
I'm writing a method for the Java Helper Library to show a "windowless" swing component (image) which can be used as a way to show a progress wheel or something. I asked how to do this a while ago and received a good answer which I'm using. It works great except the animated gif is not animated. (I'm not using the image itself because seeing it the whole time you're reading this might make you sick...) It's not animated as in it's not moving. It's seemingly paused or something. The answer on the other question said animated gifs would work fine. Is the answer-er wrong or am I implementing this wrong?:
public static void main(String[] args) throws IOException, InterruptedException {
Image image = SwingHelper.resizeImageFromResourceBy(TestClass.class, progressImageLocation, 32, true); //This just gets the image in the right size I want it.
JWindow window = SwingHelper.getProgressWheelWindow(new ImageIcon(image), .9f, 600, 400);
window.setVisible(true);
Thread.sleep(3000); //Just so the image only shows up for a short period of time.
window.setVisible(false);
SwingHelper.centerAndPack(window); //A method to center and pack the window
}
/**
* Returns a window with a partially opaque progress Icon
*
* #param icon the icon to set in the progress window
* #param opacity a float value from 0-1
* #param x the x location of the window
* #param y the y location of the window
* #return a jWindow of the progress wheel
*/
public static JWindow getProgressWheelWindow(final Icon icon, final Float opacity, final int x, final int y) {
JWindow jWindow = new JWindow() {
{
setOpacity(opacity);
setLocation(x, y);
setSize(icon.getIconWidth(), icon.getIconHeight());
add(new JLabel(icon));
pack();
}
};
return jWindow;
}
SwingHelper.resizeImageFromResourceBy(
TestClass.class, progressImageLocation, 32, true);
//This just gets the image in the right size I want it.
My best guess short of an SSCCE, is that the helper method returns a static (resized) version of the original image.
Note that by using HTML in the label, an animated GIF can be resized 'on-the-fly', however the effect is less than optimal. It is better to design the image the right size.