I am working on educational klondike game project with JavaFX.
What I am trying to do is to create dynamic scaling of whole game.
I used scale class to do so. It seems almost good, as it change the scale of all interface elements, apart of the background, which is a bit smaller then the actual window.
I already tried to manipulate with BackgroundSize, but it doesn't make any change. How can I fix it?
Thanks a lot for Your help!
I add pictures to show the problem:
public class Klondike extends Application {
private static final double WINDOW_WIDTH = 1400;
private static final double WINDOW_HEIGHT = 900;
Button changeThemeButton;
Button newGame;
Button undo;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
startGame(primaryStage);
}
public void startGame(Stage primaryStage){
Card.loadCardImages();
Game game = new Game();
game.setTableBackground(new Image(Common.loadThemeSettings().get(0)));
initializeButtons(game, primaryStage);
primaryStage.setTitle("Klondike Solitaire");
primaryStage.setScene(new Scene(game, WINDOW_WIDTH, WINDOW_HEIGHT));
// SCALLING:
Scale scale = new Scale(1, 1);
scale.xProperty().bind(game.widthProperty().divide(WINDOW_WIDTH));
scale.yProperty().bind(game.heightProperty().divide(WINDOW_HEIGHT));
game.getTransforms().add(scale);
primaryStage.setResizable(true);
// SCALLING END:
primaryStage.show();
}
BACKGROUND PICTURE:
public void setTableBackground(Image tableBackground) {
setBackground(new Background(new BackgroundImage(tableBackground,
BackgroundRepeat.REPEAT, BackgroundRepeat.REPEAT,
BackgroundPosition.CENTER, BackgroundSize.DEFAULT)));
}
Related
I'm experiencing poor performance of JavaFX when the size of a Stage increases, even if only a small portion of the area changes.
The following example updates only a little square of 25x25, changing its background.
public class WindowSizeTest extends Application {
private int speed = 1500000000;
#Override
public void start(Stage primaryStage) {
StackPane content = new StackPane();
content.setPrefSize(25, 25);
content.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
new AnimationTimer() {
#Override
public void handle(long now) {
double val = ((double) now % speed) / speed;
BackgroundFill backgroundFill = new BackgroundFill(Color.color(val, val, val), CornerRadii.EMPTY, Insets.EMPTY);
Background background = new Background(backgroundFill);
content.setBackground(background);
}
}.start();
StackPane root = new StackPane(content);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Everything goes smoothly when the window is small:
..but..
if maximized on my 4k external monitor, it uses a lot my GPU and the performance of the entire system goes down:
It seems that JavaFX redraws the entire window content and not only the modified part (same behaviour on Windows).
Is this the expected behaviour? Can someone tell me why this is happening?
So I've been running into an issue lately. Whenever I want to play a videofile with JavaFX MediaPlayer combined with MediaView the video seems to stutter all over the place. I tried different types of videofiles (I rendered most of them myself as .mp4 with h264 encoding) where framerates range from 30fps to 60fps, the bitrate being 14.000.000 to 28.000.000 bps.
The lag also occurs with most files that I haven't rendered myself, so I'm quite sure that there is nothing wrong with my renderings.
edit
Further testing confirmed that it does not matter that I rendered the videofiles myself.
Do you guys know why this videostutter might be occuring and how to fix it? I'm open to any type of fixes, including using different ways of displaying the videofiles other than through JavaFX. Here is the main code of the videoplayer:
public class VideoPlayer extends JPanel implements Checkable
{
private MediaView view;
public JFXPanel pane;
private String path;
public MediaPlayer player;
private Dimension size;
public VideoPlayer(String path, Dimension size)
{
this.size = size;
this.path = path;
pane = new JFXPanel();
player = new MediaPlayer(new Media(path));
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(pane);
}
});
pane.setPreferredSize(size);
pane.setSize(size);
pane.setLocation(0,0);
add(pane);
}
public void initFX(JFXPanel fxPanel) {
Scene scene = createScene();
pane.setScene(scene);
}
private Scene createScene()
{
view = new MediaView();
view.setMediaPlayer(player);
Group root = new Group();
view.setPreserveRatio(true);
view.setFitWidth(size.width);
view.setSmooth(false);
root.getChildren().add(view);
Scene scene = null;
try{
scene = new Scene(root, size.width, size.height)
;}catch(Exception e){System.out.println(e);}
return scene;
}
public void play()
{
player.play();
}
}
Here, the videoplayer receives a String with the path to the videofile, the Dimension size is the size the player should be.
The class itself extends JPanel so that it can be added to a JFrame. This JPanel contains a JFXPanel which in its turn contains the MediaView.
If you guys can figgure out why the video is getting stutter it would be amazing. I'm open to all solutions!
Thanks for the help in advance!
Edits
As suggested by #AlmasB I made a bare-bone pure JavaFX application to play the exact same files. It might have reduced stutter by a tiny amount, but perhaps not at all. It was very hard to see wether it was better or not. Here is the code of the bare-bones JavaFX videoplayer:
public class VideoPlayerTest extends Application {
static MediaView view;
static MediaPlayer player;
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
//root.getChildren().add(btn);
makeMediaView();
root.getChildren().add(view);
player.play();
Scene scene = new Scene(root, 1920, 1080);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private static void makeMediaView(){
player = new MediaPlayer(new Media("file:///C:/Users/wesse/Documents/CowLite%20GabenQuest/resources/cutscenes/gabenquestepisode1intro.mp4.old"));
view = new MediaView(player);
view.setPreserveRatio(true);
view.setFitWidth(1920);
}
public static void main(String[] args) {
launch(args);
}
}
As suggested by #AlmasB some info:
System info
Windows 10
Latest JDK version (1.8)
gtx960, intel i5 3470, 8gb RAM
video tests
1080p 60fps 28mbit/s stutter
1080p 30fps 14mbit/s stutter
720p 29fps 1.8mbit/s no stutter, but poor video quality due to low bitrate/resolution, downloaded from YT
1080p 60fps 5.3mbit/s very slight stutter, decent video quality, downloaded from YT
1080p 60fps 6.3mbit/s medium stutter, perfect quality, self rendered
I'm rendering some videos myself now with lower bitrate to see if this is the problem.
I use certain events to place small rectangles on an HBox. Their placement is perfect when the window has not been resized, but when you for example go from small to fullscreen, their placement is wrong (of course, because they get a certain value for X at the time of placement - this is measured by getting the width of the HBox at that specific moment).
Question:
How can I make these positions dynamic, so when I resize the window, they stay in proportion?
Pictures:
Code:
#FXML HBox tagLine; // initializes the HBox
...
public void addTag(String sort) {
Rectangle rect = new Rectangle(20, tagLine.getHeight());
double pos = timeSlider.getValue() / 100 * tagLine.getWidth(); // retrieves position at the moment of being called
rect.setTranslateX(pos);
rect.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
showNotification("Gemarkeerde gebeurtenis: " + sort);
}
});
rect.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
notificationHide.play();
}
});
tagLine.getChildren().add(rect);
}
Few things that you need to take into account while translating a shape with accountable size is that you need to :
Translate the shape from its center
If the translation is dependent on the width of a Node, listen to the changes made to the with of that particular node and make changes to the translate property accordingly
Both of the above points seem to be missing in your implementation. You are never listening to width property of HBox. Neither is your calculation for pos taking the center of Rectangle into account.
Here is an example which try to keep the Rectangle at the center no matter what the size of your HBox is.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
private static final int SIDE = 40;
private static final double DEFAULT_WIDTH = 200;
private static final double DEFAULT_POSITION = 100;
#Override
public void start(Stage primaryStage) {
Rectangle rectangle = new Rectangle(SIDE, SIDE);
HBox root = new HBox(rectangle);
root.setPrefWidth(DEFAULT_WIDTH);
rectangle.translateXProperty().bind(root.widthProperty().multiply(DEFAULT_POSITION/DEFAULT_WIDTH).subtract(SIDE/2));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This question already has answers here:
How to create Splash screen with transparent background in JavaFX
(2 answers)
Closed 9 years ago.
I'm interested how I can display "Loading" message during JavaFX startup. I noticed for example that when I start SceneBuilder I have to wait ~5 seconds before the application is displayed in front of the user. Can I for example display some message during JVM start time?
UPDATE
I tested this code:
public class test extends Application
{
private Pane splashLayout;
private ProgressBar loadProgress;
private Label progressText;
private WebView webView;
private Stage mainStage;
private static final int SPLASH_WIDTH = 676;
private static final int SPLASH_HEIGHT = 227;
public static void main(String[] args) throws Exception
{
launch(args);
}
#Override
public void init()
{
ImageView splash = new ImageView(new Image("http://fxexperience.com/wp-content/uploads/2010/06/logo.png"));
loadProgress = new ProgressBar();
loadProgress.setPrefWidth(SPLASH_WIDTH - 20);
progressText = new Label("Loading System Modules ...");
splashLayout = new VBox();
splashLayout.getChildren().addAll(splash, loadProgress, progressText);
progressText.setAlignment(Pos.CENTER);
splashLayout.setStyle("-fx-padding: 5; -fx-background-color: cornsilk; -fx-border-width:5; -fx-border-color: linear-gradient(to bottom, chocolate, derive(chocolate, 50%));");
splashLayout.setEffect(new DropShadow());
}
#Override
public void start(final Stage initStage) throws Exception
{
showSplash(initStage);
showMainStage();
webView.getEngine().documentProperty().addListener(new ChangeListener<Document>()
{
#Override
public void changed(ObservableValue<? extends Document> observableValue, Document document, Document document1)
{
if (initStage.isShowing())
{
loadProgress.progressProperty().unbind();
loadProgress.setProgress(1);
progressText.setText("All Modules Are Loaded!");
mainStage.setIconified(false);
initStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.2), splashLayout);
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent actionEvent)
{
initStage.hide();
}
});
fadeSplash.play();
}
}
});
}
private void showMainStage()
{
mainStage = new Stage(StageStyle.DECORATED);
mainStage.setTitle("FX Experience");
mainStage.setIconified(true);
// create a WebView.
webView = new WebView();
webView.getEngine().load("http://fxexperience.com/");
loadProgress.progressProperty().bind(webView.getEngine().getLoadWorker().workDoneProperty().divide(100));
// layout the scene.
Scene scene = new Scene(webView, 1000, 600);
webView.prefWidthProperty().bind(scene.widthProperty());
webView.prefHeightProperty().bind(scene.heightProperty());
mainStage.setScene(scene);
mainStage.show();
}
private void showSplash(Stage initStage)
{
Scene splashScene = new Scene(splashLayout);
initStage.initStyle(StageStyle.UNDECORATED);
final Rectangle2D bounds = Screen.getPrimary().getBounds();
initStage.setScene(splashScene);
initStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2);
initStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2);
initStage.show();
}
}
I noticed that the splash image is started with the main stage simultaneity but the main stage is minimized. Can I freeze the appearance of the main stage until the splash screen is completed with the loading. I want to do some internal checks before I display the main stage.
Use javax.swing.JProgressBar to achieve this.
Check the details in JProgressBar (docs)
I recently found javafx 2.1 very useful for my project of making a video player but after a
success I faced a problem with the video size Dimensions. In other words, when I run the
program and video is playing normally I can't see the whole video because it's dimensions
are bigger than my screen resolution .What Can I do in the following code to resize the actual size of video in windows7 64bit:
public class HelloFx extends Application {
public static void main(String[] args){
launch(args);
}
#Override
public void start(final Stage stage) throws Exception {
stage.setTitle("Movie Player");
final BorderPane root = new BorderPane();
final Media media = new Media("file:///Users//user//Videos//Sintel.mp4");
final MediaPlayer player = new MediaPlayer(media);
final MediaView view = new MediaView(player);
// System.out.println("media.width: "+media.getWidth());
root.getChildren().add(view);
final Scene scene = new Scene(root, 400, 400, Color.BLACK);
stage.setScene(scene);
stage.show();
player.play();
player.setOnReady(new Runnable() {
#Override
public void run() {
int w = player.getMedia().getWidth();
int h = player.getMedia().getHeight();
stage.setMinWidth(w);
stage.setMinHeight(h);
}
});
//player.play();
}
}
The JavaFX 2 MediaView class has 2 functions which can help. They are .setFitHeight() and .setFitWidth() .
So, you could, instead of letting the media dictate the size of screen, let your stage set the size of the screen...
public void run() {
int w = stage.getWidth(); // player.getMedia().getWidth();
int h = stage.getHeight(); // player.getMedia().getHeight();
// stage.setMinWidth(w);
// stage.setMinHeight(h);
// make the video conform to the size of the stage now...
player.setFitWidth(w);
player.setFitHeight(h);
}
Then the video should fit inside of the stage. That above code is pretty crude, and you may want to "Scale" the video better, ie: find the ratio of the media width VS the stage width & media height VS stage height ... But that code above should get you started.