I'm new to JavaFX , i'm trying to create a transparent scene and stage the problem is when I add nodes like images and labels , the scene is no longer transparent
this is my code
package application;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
public class Main extends Application {
private double xOffset = 0;
private double yOffset = 0;
public void start(Stage primaryStage) throws Exception {
try{
Parent root ;
root = FXMLLoader.load(getClass().getResource("/View/Authentification.fxml"));
primaryStage.initStyle(StageStyle.TRANSPARENT);
Scene scene = new Scene(root);
scene.setFill(null);
root.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
xOffset = event.getSceneX();
yOffset = event.getSceneY();
}
});
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
primaryStage.setX(event.getScreenX() - xOffset);
primaryStage.setY(event.getScreenY() - yOffset);
}
});
primaryStage.setScene(scene);
primaryStage.show();}
catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
and this is my xml code :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<AnchorPane layoutY="94.0" prefHeight="417.0" prefWidth="363.0" style="-fx-background-color: #3D4966;"/>
<AnchorPane layoutX="-1.0" prefHeight="82.0" prefWidth="363.0" style="-fx-background-color: #3D4966;">
<children>
<Label layoutX="280.0" layoutY="70.0" text="Fermer" textFill="#eee5e5">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<ImageView layoutX="288.0" layoutY="22.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../images/Shutdown.png" />
</image>
</ImageView>
<Label layoutX="146.0" layoutY="61.0" prefHeight="17.0" prefWidth="92.0" text="crée un compte" textFill="#eee5e5">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<ImageView layoutX="167.0" layoutY="21.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../images/Add_User.png" />
</image>
</ImageView>
<ImageView layoutX="50.0" layoutY="21.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../images/User.png" />
</image>
</ImageView>
<Label layoutX="50.0" layoutY="62.0" text="Ce connecter" textFill="#eee5e5">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
</children>
</AnchorPane>
</AnchorPane>
i tried a lot of other codes but nothing seems to work
these are some screenshots with nodes
without nodes
If you create one or more controls (specifically, any instance of Control or a subclass), the default stylesheet is applied to the scene. This sets the background color of the root of the scene to a non-transparent "very light grey" (basically 26.4% lighter than #ececec).
(Specifically, the default stylesheet contains the following:
.root {
/***************************************************************************
* *
* The main color palette from which the rest of the colors are derived. *
* *
**************************************************************************/
/* A light grey that is the base color for objects. Instead of using
* -fx-base directly, the sections in this file will typically use -fx-color.
*/
-fx-base: #ececec;
/* A very light grey used for the background of windows. See also
* -fx-text-background-color, which should be used as the -fx-text-fill
* value for text painted on top of backgrounds colored with -fx-background.
*/
-fx-background: derive(-fx-base,26.4%);
/* ... */
-fx-background-color: -fx-background;
}
The source for the current version of the default stylesheet (at the time of writing) can be found at http://hg.openjdk.java.net/openjfx/9/rt/file/c734b008e3e8/modules/javafx.controls/src/main/resources/com/sun/javafx/scene/control/skin/modena/modena.css).
So you need to make the root of the scene transparent too.
You can do this using inline CSS, either in the FXML:
<AnchorPane style="-fx-background-color: transparent ;" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
or in Java:
Parent root ;
root = FXMLLoader.load(getClass().getResource("/View/Authentification.fxml"));
root.setStyle("-fx-background-color: transparent ;");
or you can do it in an external style sheet:
.root {
-fx-background-color: transparent ;
}
Related
I'm running an FXML project and I can't load my fxml files, IntelliJ keeps indicating there is something wrong with my AnchorPane tag, however this was all generated by scene builder. This error even shows up for fxml files created by IntelliJ. The issue seems to be xmlns="http://javafx.com/javafx/19" within the AnchorPane tag at least that's where the compiler is pointing to.
I'm running IntelliJ 2022 with JDK 17.0.4.1 with JavaFX 19 using Maven, and I'm using scene builder 19.
here is my fxml code
`
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.LoginController">
<children>
<VBox prefHeight="400.0" prefWidth="600.0" />
<TextField id="Username" layoutX="115.0" layoutY="60.0" prefHeight="25.0" prefWidth="126.0" promptText="user#account.com" />
<Label layoutX="39.0" layoutY="64.0" prefHeight="17.0" prefWidth="63.0" text="Username" />
<Label layoutX="39.0" layoutY="116.0" text="Password" />
<TextField id="password" layoutX="115.0" layoutY="112.0" prefHeight="25.0" prefWidth="126.0" />
<Button id="login" layoutX="132.0" layoutY="210.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="85.0" text="Login" />
<Label layoutX="39.0" layoutY="153.0" prefHeight="17.0" prefWidth="63.0" text="Location" />
<TextField id="Location" disable="true" layoutX="115.0" layoutY="149.0" prefHeight="25.0" prefWidth="126.0" promptText="Your location here" />
<Label id="ErrorMessage" alignment="CENTER" disable="true" layoutX="91.0" layoutY="183.0" prefHeight="17.0" prefWidth="187.0" text="Error Label" textAlignment="CENTER" textFill="#e10724">
<font>
<Font name="System Italic" size="12.0" />
</font>
</Label>
</children>
</AnchorPane>
`
and here is my java code
`
package controllers;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.net.URL;
public class LoginController {
#FXML
private TextField Username;
//Buttons
#FXML
private TextField Password;
#FXML
private TextField Location;
#FXML
private Label ErrorMessage;
#FXML
private Button Login;
public void BeginStart(){
//Loader
try {
//debugging fxml path
URL uri = getClass().getResource("/views/login.fxml");
System.out.println(uri);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/views/login.fxml"));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
/*Parent root = loader.load();
Stage stage = new Stage();
stage.setTitle("Scheduler Login");
stage.setScene(new Scene(root));
stage.show();*/
}catch(Exception e){
System.out.println("Failed to load login.fxml");
System.out.println("Exception: " + e.toString());
}
}
}
`
uri is non-null so there appears to be no problem with the file path.
Previously I've had the "uri not registered" error before I deleted the javaFX files included with Maven, and used a local copy of the JavaFX19 library, along with the proper JVM arguments.
Note: the image I included is from a previous version of my project. Under resources "controllers" is actually supposed to be "views".
Ok, so the issue was with the fx:controller reference. My controller class was not within src/main/java/com.example.scheduler.
After moving it there the error ceased.
We're currently developing a social media platform as a project at school (to be handed in in 2 weeks), and we've ran into some issues when trying to get the UI to scale with the application window. Currently it works as supposed when previewing it in SceneBuilder (see the first link) , but it seems to be stuck in the upper left corner when running the actual application via IntelliJ IDEA. I've also linked a screenshot of how it's actual behavior is (second link).
This is how the scaling should work, and as you can see it does work when i use SceneBuilder's preview function.
This is how the scaling is working when we run the app, which isn't scaling at all.
At the moment we're just trying to understand whats wrong, therefore our only focus is the 'discover page' of the platform (you access the page from the events page). So i will post the fxml code for the discover page as well as the events controller. Bare in mind this is my first ever post on here, so if there's anything else that could help you help us just tell me and i'll get it uploaded! Here is a screenshot of all the classes in our project, if there's any other class that would be helpful if i post just say the word :)
All classes in the project.
FXML for the Discover page:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<BorderPane fx:id="borderPaneDiscover" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="JavaFX.DiscoverController">
<center>
<AnchorPane prefHeight="200.0" prefWidth="900.0" BorderPane.alignment="CENTER">
<children>
<TableView fx:id="tableViewDiscover" layoutY="62.0" onMouseClicked="#showDetails" prefHeight="331.0" prefWidth="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="65.0">
<columns>
<TableColumn fx:id="eventNameColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event name" />
<TableColumn fx:id="eventLocationColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event location" />
<TableColumn fx:id="eventDateColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event date" />
<TableColumn fx:id="eventCategoryColumnCategory" minWidth="180.0" prefWidth="75.0" text="Event category" />
<TableColumn fx:id="eventCreatorColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event Creator" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<Label alignment="CENTER" prefHeight="18.0" prefWidth="190.0" text="Choose category of the event:" textAlignment="CENTER" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
<ChoiceBox fx:id="choiceBoxDiscover" layoutX="375.0" layoutY="20.0" prefHeight="30.0" prefWidth="150.0" AnchorPane.leftAnchor="375.0" AnchorPane.rightAnchor="375.0" AnchorPane.topAnchor="20.0" />
<Button fx:id="buttonGo" layoutX="505.0" mnemonicParsing="false" onAction="#showTableDiscover" prefHeight="30.0" prefWidth="55.0" style="-fx-background-color: #313131; -fx-text-fill: #FFF; -fx-font-weight: BOLD;" text="Go" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="20.0">
<effect>
<DropShadow />
</effect>
</Button>
</children>
</AnchorPane>
</center>
<bottom>
<AnchorPane prefHeight="145.0" prefWidth="900.0" BorderPane.alignment="CENTER">
<children>
<TextArea fx:id="textAreaDescription" editable="false" layoutX="60.0" layoutY="20.0" prefHeight="120.0" prefWidth="250.0" wrapText="true" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="60.0" AnchorPane.rightAnchor="590.0" AnchorPane.topAnchor="20.0" />
<TextArea fx:id="textAreaParticipants" editable="false" layoutX="360.0" layoutY="20.0" prefHeight="120.0" prefWidth="250.0" wrapText="true" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="290.0" AnchorPane.topAnchor="20.0" />
<Button fx:id="attendButton" layoutX="660.0" layoutY="45.0" mnemonicParsing="false" onAction="#attendEvent" prefHeight="50.0" prefWidth="100.0" style="-fx-background-color: #313131; -fx-text-fill: #ffffff; -fx-font-weight: BOLD;" text="Attend" AnchorPane.bottomAnchor="50.0" AnchorPane.rightAnchor="40.0" AnchorPane.topAnchor="45.0">
<effect>
<DropShadow />
</effect>
</Button>
<Text layoutX="65.0" layoutY="15.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 14; -fx-font-weight: BOLD;" text="Description:" AnchorPane.leftAnchor="60.0" AnchorPane.topAnchor="2.0">
<font>
<Font name="Segoe UI Symbol" size="14.0" />
</font>
</Text>
<Text layoutX="365.0" layoutY="15.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 14; -fx-font-weight: BOLD;" text="Participants:" AnchorPane.rightAnchor="457.0" AnchorPane.topAnchor="2.0">
<font>
<Font name="Segoe UI Symbol" size="14.0" />
</font>
</Text>
</children>
</AnchorPane>
</bottom>
<top>
<AnchorPane prefHeight="16.0" prefWidth="900.0" BorderPane.alignment="CENTER">
<children>
<Label alignment="CENTER" contentDisplay="CENTER" layoutX="315.0" prefHeight="54.0" prefWidth="289.0" text="Discover events" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<font>
<Font name="System Bold" size="36.0" />
</font>
</Label>
<Button alignment="CENTER_RIGHT" layoutX="833.0" layoutY="10.0" mnemonicParsing="false" onAction="#BackToEvents" prefHeight="34.0" prefWidth="55.0" style="-fx-background-color: #313131; -fx-text-fill: #FFF; -fx-font-size: 14; -fx-font-weight: BOLD;" text="Back" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="10.0">
<font>
<Font name="Segoe UI Symbol" size="20.0" />
</font>
<effect>
<DropShadow />
</effect>
</Button>
</children>
</AnchorPane>
</top>
</BorderPane>
FXML for the events page:
package JavaFX;
import javafx.collections.*;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import java.io.IOException;
public class EventsController {
private ObservableList<String> usersChoice = FXCollections.observableArrayList("My events(attended/to attend and created)", "Discover(search by category and attend)", "Create event");
#FXML
private BorderPane eventsPane;
#FXML
private ChoiceBox <String> choicebox;
#FXML
private Label labelOfUserChoice;
#FXML
private void initialize(){
choicebox.setItems(usersChoice);
//choicebox.getSelectionModel().selectedItemProperty().addListener(changeListener);
}
#FXML
private void changeLabel() throws IOException/*, InterruptedException*/{
switch (choicebox.getValue()) {
//ask sokol about it
case ("My events(attended/to attend and created)"):
labelOfUserChoice.setText("You have chosen: " + choicebox.getValue());
choicebox.setDisable(true);
//TimeUnit.SECONDS.sleep(5);
loadMyEvents();
break;
case ("Discover(search by category and attend)"):
labelOfUserChoice.setText("You have chosen: " + choicebox.getValue());
choicebox.setDisable(true);
//TimeUnit.SECONDS.sleep(1);
loadDiscover();
break;
case ("Create event"):
labelOfUserChoice.setText("You have chosen: " + choicebox.getValue());
//TimeUnit.SECONDS.sleep(1);
loadCreateEvent();
break;
default:
System.out.println("YOU'VE BETTER LEARN HOW TO USE JFX!");
}
}
#FXML
private void goToMainMenu(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/mainMenu.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
#FXML
private void goToProfile(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/profile.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
#FXML
private void goToFriends(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/resources/friendsPage.fxml"));
loader.setLocation(getClass().getResource("/resources/friendsPage.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
#FXML
private void goToChat(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/chatclient/FXMLDocument.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
private void loadMyEvents() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/myEvents.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
private void loadDiscover() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/discover.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
private void loadCreateEvent() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/createEvent.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
}
So far i've read probably all the posts in here that are issues remotely like ours, but none of them have seemed to work. I haven't been able to find a post stating the exact same issue as ours, where the preview window in SceneBuilder works as supposed and the program when we run it doesn't. I hope someone can help us out, thanks in advance! :)
I previously asked this question: How do I make JavaFX MediaView stretch and shrink media to fill/fit parent container? about making a JavaFX media player expand to fill the parent. Unfortunately, that hack with a pane around the video pushes the controllers far away from the video:
The colors are there just to understand how the layout is acting. The video player is composed of this FXML:
<VBox alignment="TOP_CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0" style="-fx-background-color: red;" HBox.hgrow="ALWAYS">
<Pane fx:id="mediaViewPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0"
minWidth="0.0" VBox.vgrow="ALWAYS" style="-fx-background-color: green;">
<MediaView fx:id="tutorialPlayer" managed="false" />
</Pane>
<Slider fx:id="timeSlider" VBox.vgrow="NEVER">
<VBox.margin>
<Insets />
</VBox.margin>
</Slider>
<HBox alignment="TOP_CENTER" spacing="10.0" style="-fx-background-color: magenta;" VBox.vgrow="SOMETIMES">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<Button fx:id="playButton" minHeight="40.0" minWidth="40.0" mnemonicParsing="false" onAction="#play">
<graphic>
<FontIcon iconLiteral="fas-play" iconSize="25" />
</graphic>
</Button>
<Button fx:id="pauseButton" managed="false" minHeight="40.0" minWidth="40.0" mnemonicParsing="false" onAction="#pause" visible="false">
<graphic>
<FontIcon iconLiteral="fas-pause" iconSize="25" />
</graphic>
</Button>
<Button fx:id="restartButton" disable="true" minHeight="40.0" minWidth="40.0" mnemonicParsing="false" onAction="#restart">
<graphic>
<FontIcon iconLiteral="fas-retweet" iconSize="25" />
</graphic>
</Button>
<Button fx:id="muteButton" minHeight="40.0" minWidth="40.0" mnemonicParsing="false" onAction="#mute">
<graphic>
<FontIcon iconLiteral="fas-volume-up" iconSize="25" />
</graphic>
</Button>
<Button fx:id="unmuteButton" managed="false" minHeight="40.0" minWidth="40.0" mnemonicParsing="false" onAction="#unmute" visible="false">
<graphic>
<FontIcon iconLiteral="fas-volume-off" iconSize="25" />
</graphic>
</Button>
<Slider fx:id="volumeSlider" blockIncrement="0.1" max="1.0" value="1.0" />
</HBox>
<HBox.margin>
<Insets />
</HBox.margin>
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
While the hacky code to resize is this:
// Resize the video to fit and fill the allocated space. Why isn't this the default?????
InvalidationListener resizeTutorialPlayer = observable -> {
tutorialPlayer.setFitWidth(mediaViewPane.getWidth());
tutorialPlayer.setFitHeight(mediaViewPane.getHeight());
Bounds actualVideoSize = tutorialPlayer.getLayoutBounds(); // After setting a big fit width and height, the layout bounds match the video size. Not sure why and this feels fragile.
tutorialPlayer.setX((mediaViewPane.getWidth() - actualVideoSize.getWidth()) / 2);
tutorialPlayer.setY((mediaViewPane.getHeight() - actualVideoSize.getHeight()) / 2);
};
mediaViewPane.heightProperty().addListener(resizeTutorialPlayer);
mediaViewPane.widthProperty().addListener(resizeTutorialPlayer);
Any ideas how to have the same as big as possible and centered while respecting the aspect ratio functionality but keeping the controllers for the video just next to the video?
You can probably make this work with your current strategy by wrapping the controls and media view in another pane (VBox?), then subtracting the height of the controls when you set the media view's fitHeight property. Then just configure that pane so it centers everything.
To be honest, though, I try to avoid using bindings and listeners to manage layout. Sometimes it's inevitable, but once you reach a certain critical point it's probably better to define a custom layout by subclassing Pane. The strategy I outlined above exceeds that critical point, in my judgement (your mileage may vary, of course).
So I'd define a layout pane specifically to manage this. It's not too bad; just override the various computeXXWidth/Height() methods and the layoutChildren() method:
package mediaviewlayout;
import javafx.beans.NamedArg;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.media.MediaView;
public class MediaViewLayout extends Pane {
private final MediaView mediaView ;
private final Node content ;
private static final double SPACING = 5 ; // can make this configurable if needed...
public MediaViewLayout(
#NamedArg("mediaView") MediaView mediaView,
#NamedArg("content") Node content) {
this.mediaView = mediaView ;
this.content = content ;
this.getChildren().addAll(mediaView, content);
}
#Override
public double computeMinWidth(double height) {
return Math.max(mediaView.minWidth(height), content.minWidth(height));
}
#Override
public double computePrefWidth(double height) {
return Math.max(mediaView.prefWidth(height), content.prefWidth(height));
}
#Override
public double computeMaxWidth(double height) {
return Math.min(mediaView.maxWidth(height), content.maxWidth(height));
}
#Override
public double computeMinHeight(double width) {
return mediaView.minHeight(width) + content.minHeight(width) + SPACING ;
}
#Override
public double computePrefHeight(double width) {
return mediaView.prefHeight(width) + content.prefHeight(width) + SPACING ;
}
#Override
public double computeMaxHeight(double width) {
return mediaView.maxHeight(width) + content.minHeight(width) + SPACING ;
}
#Override
protected void layoutChildren() {
double width = getWidth();
double height = getHeight();
double contentHeight = content.prefHeight(-1);
double availableHeight = height - SPACING - contentHeight ;
mediaView.setFitWidth(width);
mediaView.setFitHeight(availableHeight);
Bounds actualMediaBounds = mediaView.getBoundsInLocal();
double totalUsedHeight = actualMediaBounds.getHeight() + SPACING + contentHeight ;
double mediaX = (width - actualMediaBounds.getWidth()) / 2 ;
double mediaY = (height - totalUsedHeight) / 2;
mediaView.relocate(mediaX, mediaY);
content.resizeRelocate(0, mediaY+actualMediaBounds.getHeight()+SPACING, width, contentHeight);
}
}
This always places the content below the media view. You could introduce additional properties such as an ObjectProperty<Side> if you wanted to make this more configurable and resuable.
You can then test this out either in Java:
package mediaviewlayout;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
public class MediaViewTest extends Application {
private static final String MEDIA_URL = "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv";
#Override
public void start(Stage primaryStage) throws Exception {
MediaView mediaView = new MediaView();
mediaView.setPreserveRatio(true);
MediaPlayer mediaPlayer = new MediaPlayer(new Media(MEDIA_URL));
mediaPlayer.setAutoPlay(true);
mediaView.setMediaPlayer(mediaPlayer);
VBox controls = new VBox(5);
controls.setAlignment(Pos.CENTER);
Slider slider = new Slider();
controls.getChildren().add(slider);
Button play = new Button("Play");
HBox buttons = new HBox(5, play, new Button("Restart"), new Button("Volume"), new Slider());
buttons.setAlignment(Pos.TOP_CENTER);
controls.getChildren().add(buttons);
MediaViewLayout layout = new MediaViewLayout(mediaView, controls);
Scene scene = new Scene(layout, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
or in FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import mediaviewlayout.MediaViewLayout?>
<?import javafx.scene.media.Media?>
<?import javafx.scene.media.MediaPlayer?>
<?import javafx.scene.media.MediaView?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<MediaViewLayout xmlns:fx="http://javafx.com/fxml/1" style="-fx-background-color: green;">
<mediaView>
<MediaView>
<mediaPlayer>
<MediaPlayer autoPlay="true">
<media>
<Media source="http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv"/>
</media>
</MediaPlayer>
</mediaPlayer>
</MediaView>
</mediaView>
<content>
<VBox spacing="5" style="-fx-background-color: red;">
<Slider/>
<HBox spacing="5" alignment="TOP_CENTER" style="-fx-background-color: magenta;">
<Button text="Play"/>
<Button text="Restart"/>
<Button text="Volume"/>
<Slider/>
</HBox>
</VBox>
</content>
</MediaViewLayout>
with
package mediaviewlayout;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MediaViewTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
MediaViewLayout layout = FXMLLoader.load(getClass().getResource("MediaViewLayoutTest.fxml"));
Scene scene = new Scene(layout, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Screenshot from FXML version:
So for some context, all I want to to do is have two buttons appear after a different button is clicked, and then those two buttons would do something when they are clicked. Any ideas?
Controller Class:
public class USPSCaseSpinController implements Initializable {
#FXML
public static ImageView setUSPImage;
#FXML
private void handleSpinMechBack(MouseEvent event) throws IOException{
Parent handleInventoryBackParent = FXMLLoader.load(getClass().getResource("/csgocaseopener/OpenCase.fxml"));
Scene OPBackScene = new Scene(handleInventoryBackParent);
Stage handleInventoryBackStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
handleInventoryBackStage.setScene(OPBackScene);
handleInventoryBackStage.show();
}
#FXML
private void SpinUSPSCase(ActionEvent event) throws IOException{
Random rand = new Random();
int gunSelect = rand.nextInt(99)+1;
test test = new test();
if(gunSelect<=30)
LeadConduitUSPS(setUSPImage);
else if(gunSelect>=31 && gunSelect<=60)
NightOpsUSPS(setUSPImage);
else if(gunSelect>=61 && gunSelect<=90)
TorqueUSPS(setUSPImage);
else if(gunSelect>=91 && gunSelect<=93.5)
GuardianUSPS(setUSPImage);
else if(gunSelect>=94.5 && gunSelect<=97)
CyrexUSPS(setUSPImage);
else if(gunSelect>=98 && gunSelect<=99)
CaimanUSPS(setUSPImage);
else if(gunSelect==100)
KillConfirmedUSPS(setUSPImage);
}
#FXML
public void SetUSPImage(){
setUSPImage.setImage(new Image("AWPCase.png"));
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
FXML File:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="CaseSpinners.USPSCaseSpinController">
<children>
<ImageView fitHeight="400.0" fitWidth="600.0" pickOnBounds="true">
<image>
<Image url="#../csgocaseopener/back.png" />
</image>
</ImageView>
<ImageView fx:id="spinmechback" fitHeight="45.0" fitWidth="45.0" onMouseClicked="#handleSpinMechBack" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="-1.0">
<image>
<Image url="#../csgocaseopener/backbtn.png" />
</image>
</ImageView>
<Button fx:id="SpinUSPS" layoutX="235.0" layoutY="301.0" mnemonicParsing="false" onAction="#SpinUSPSCase" text="SPIN">
<font>
<Font name="System Bold" size="36.0" />
</font>
</Button>
<ImageView fx:id="setUSPImage" fitHeight="200.0" fitWidth="200.0" layoutX="201.0" layoutY="100.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../csgocaseopener/bprof.png" />
</image></ImageView>
</children>
</AnchorPane>
I just want the button that is already created to do what is explained above!
You question is a bit vague, but I'll try to answer it as best I can.
There are several ways in which you can do this. The simplest would probably be as follows:
First, you can add define the buttons in your fxml file, and set them to be invisible by default. Just like with SpinUSPS you can attach an actionEvent to each of these new buttons:
<Button fx:id="SpinUSPS" layoutX="235.0" layoutY="301.0" mnemonicParsing="false" onAction="#SpinUSPSCase" text="SPIN">
<font>
<Font name="System Bold" size="36.0" />
</font>
</Button>
<Button fx:id="invisible1" visible="false" layoutX="235.0" layoutY="320.0" mnemonicParsing="false" onAction="#invisibleMethod1" text="Something1"/>
<Button fx:id="invisible2" visible="false" layoutX="235.0" layoutY="340.0" mnemonicParsing="false" onAction="#invisibleMethod2" text="Something2"/>
When you press the SpinUSPS button, you want to change the visiblity of the buttons. To do this from within the USPSCaseSpinController class you should first define them at the top of your class:
#FXML
Button invisible1;
#FXML
Button invisible2;
Inside your SpinUSPSCase method you then place the following to make them visible when the SpinUSPS is clicked:
invisible1.setVisible(true);
invisible2.setVisible(true);
To actually make these new buttons do something you can then write action events for these new buttons:
#FXML
private void invisibleMethod1(ActionEvent event) throws IOException {
// your code goes here
}
#FXML
private void invisibleMethod2(ActionEvent event) throws IOException {
// your code goes here
}
The event method that I'm talking about is changeBackgroundScreen. The button is being covered by a background image in one of my css file. At first I thought it was the background blocking the button from being interact with. I took the background image off and it still didn't work. Now I have no clue.
Here is a portion of the FXML File For you to focus on:
<HBox alignment="CENTER" spacing="200">
<children>
<Button fx:id="optionButton1" onAction="#changeBackgroundScreen" prefWidth="80" prefHeight="50" id="SmallBlueBackground1"/>
<Button fx:id="optionButton2" onAction="#changeBackgroundScreen" prefWidth="80" prefHeight="50" id="SmallBlueBackground2"/>
<Button fx:id="optionButton3" onAction="#changeBackgroundScreen" prefWidth="80" prefHeight="50" id="SmallBlueBackground3"/>
</children>
</HBox>
Here is the entire FXML File if you're interested:
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.*?>
<?import java.net.URL?>
<StackPane fx:id="Optionmenu" id="BlueBackground1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="millionairetriviagame.OptionscreenController">
<stylesheets>
<URL value="#BackgroundImages.css" />
</stylesheets>
<stylesheets>
<URL value="#ButtonLayout.css"/>
</stylesheets>
<children>
<VBox alignment="TOP_CENTER" spacing="20">
<ImageView>
<image>
<Image url="#ImageFiles/MillionaireLogo1.png"/>
</image>
</ImageView>
<Label text="Click to Change the Background Color" style="-fx-font-style: Italic;" textFill="white">
<font>
<javafx.scene.text.Font name="sans-serif" size="20" />
</font>
</Label>
<HBox alignment="CENTER" spacing="200">
<children>
<Button fx:id="optionButton1" onAction="#changeBackgroundScreen" prefWidth="80" prefHeight="50" id="SmallBlueBackground1"/>
<Button fx:id="optionButton2" onAction="#changeBackgroundScreen" prefWidth="80" prefHeight="50" id="SmallBlueBackground2"/>
<Button fx:id="optionButton3" onAction="#changeBackgroundScreen" prefWidth="80" prefHeight="50" id="SmallBlueBackground3"/>
</children>
</HBox>
</VBox>
<HBox alignment="BOTTOM_RIGHT" spacing="10" >
<children>
<Button fx:id="backToMain" prefWidth="200" prefHeight="30" onAction="#goToTheMainMenu" text="Back to the Main Menu" styleClass="ButtonLayout">
<shape>
<javafx.scene.shape.Rectangle width="200" height="30" arcHeight="30" arcWidth="30" />
</shape>
</Button>
</children>
</HBox>
</children>
</StackPane>
Here is my controller Class
package millionairetriviagame;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
public class OptionscreenController implements Initializable, ControllingScreens
{
private ScreenNavigator controller;
private MediaPlayer optionMenuPlayer;
#FXML private Button backToMain;
private BooleanProperty isDisabled;
#FXML private StackPane Optionmenu;
#FXML private Button optionButton1;
#FXML private Button optionButton2;
#FXML private Button optionButton3;
#FXML private StackPane mainMenu;
#Override
public void initialize(URL url, ResourceBundle rb)
{
configureProperties();
playSong();
}
private void configureProperties()
{
isDisabled = new SimpleBooleanProperty();
backToMain.disableProperty().bind(isDisabled);
}
#Override
public void setScreenParent(ScreenNavigator parentScreen)
{
controller = parentScreen;
}
private void playSong()
{
Media optionIntroTheme = new Media(getClass().getResource("/millionairetriviagame/AudioFiles/OptionMenuMusic.mp3").toExternalForm());
optionMenuPlayer = new MediaPlayer(optionIntroTheme);
optionMenuPlayer.setAutoPlay(true);
optionMenuPlayer.setVolume(0.1);
optionMenuPlayer.setCycleCount(MediaPlayer.INDEFINITE);
}
#FXML private void changeBackgroundScreen(ActionEvent event)
{
try
{
FXMLLoader myLoader = new FXMLLoader(getClass().getResource(MillionaireTriviaGame.MAIN));
myLoader.load();
mainMenu = myLoader.getRoot();
}
catch (IOException ex)
{
Logger.getLogger(OptionscreenController.class.getName()).log(Level.SEVERE, null, ex);
}
if(optionButton2.isPressed())
{
mainMenu.setId("BlueBackground2");
Optionmenu.setId("BlueBackground2");
}
}
#FXML private void goToTheMainMenu(ActionEvent event)
{
isDisabled.setValue(true);
optionMenuPlayer.stop();
controller.loadScreen(MillionaireTriviaGame.MAINSCREENID, MillionaireTriviaGame.MAIN);
controller.setScreen(MillionaireTriviaGame.MAINSCREENID);
}
}
Here is my CSS File if you need to look at it as well.
#BlueBackground1
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor.jpg");
}
#BlueBackground2
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor2.jpg");
}
#SmallBlueBackground1
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 80 50;
-fx-background-position: center center;
-fx-background-insets: 0, 0, 0, 0;
}
#SmallBlueBackground2
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor2.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 80 50;
-fx-background-position: center center;
-fx-background-insets: 0, 0, 0, 0;
}
#SmallBlueBackground3
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor3.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 80 50;
-fx-background-position: center center;
-fx-background-insets: 0, 0, 0, 0;
}
Here is a visual
Problem
The problem is with your layout. You have a StackPane with VBox (containing the buttons which fire the changeBackgroundScreen methods) and on top of that you have a HBox (with a single button, aligned to bottom right).
At the first glance everything might just look cool. But, remember VBox and HBox are layouts which fill their parent. So, even if you can't see, the HBox lies on top of your buttons in the VBox blocking all the interactions.
Solution
A more complex solution would be to use something other than a StackPane because I don't really see the need of it. But, since you already have the layout, lets go with something which needs little tweaking to the layout.
A very simple solution would be to move the HBox into the VBox. This way, there is no blocking layer. But, since you want the button to stick to the bottom-right of the scene, we will use a Region in between the children of the VBox and set the VGrow as Always. This will push the newly added HBox to the bottom of the scene and make it stick there no matter what your scene size is.
Complete FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.*?>
<?import java.net.URL?>
<StackPane id="BlueBackground1" fx:id="Optionmenu" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="millionairetriviagame.OptionscreenController">
<stylesheets>
<URL value="#BackgroundImages.css" />
</stylesheets>
<stylesheets>
<URL value="#ButtonLayout.css" />
</stylesheets>
<children>
<VBox alignment="TOP_CENTER" spacing="20">
<ImageView>
<image>
<Image url="#ImageFiles/MillionaireLogo1.png" />
</image>
</ImageView>
<Label style="-fx-font-style: Italic;" text="Click to Change the Background Color" textFill="white">
<font>
<javafx.scene.text.Font name="sans-serif" size="20" />
</font>
</Label>
<HBox alignment="CENTER" spacing="200">
<children>
<Button id="SmallBlueBackground1" fx:id="optionButton1" onAction="#changeBackgroundScreen" prefHeight="50" prefWidth="80" />
<Button id="SmallBlueBackground2" fx:id="optionButton2" onAction="#changeBackgroundScreen" prefHeight="50" prefWidth="80" />
<Button id="SmallBlueBackground3" fx:id="optionButton3" onAction="#changeBackgroundScreen" prefHeight="50" prefWidth="80" />
</children>
</HBox>
<Region prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox alignment="BOTTOM_RIGHT" spacing="10">
<children>
<Button fx:id="backToMain" onAction="#goToTheMainMenu" prefHeight="30" prefWidth="200" styleClass="ButtonLayout" text="Back to the Main Menu">
<shape>
<javafx.scene.shape.Rectangle arcHeight="30" arcWidth="30" height="30" width="200" />
</shape>
</Button>
</children>
</HBox>
</VBox>
</children>
</StackPane>