I am new to Java and JavaFX all together, so please be patient with me if I am asking the wrong question here.
I am trying to add preloader Scene to an application I built: I was able to add the preloader using the code below. It's the default preloader and it looks very basic. So, here is my question. 1) how to add percentage progress status instead of progressbar. 2) Is it possible to load this progress bar on top of an FXML scene
Preloader
public class JavaFXPreloader3 extends Preloader {
ProgressBar bar;
Stage stage;
private Scene createPreloaderScene() throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("FXML.fxml"));
ProgressIndicator pi = new ProgressIndicator();
BorderPane p = new BorderPane();
p.setCenter(pi);
return new Scene(p, 300, 150);
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setScene(createPreloaderScene());
stage.show();
}
#Override
public void handleStateChangeNotification(StateChangeNotification scn) {
if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
stage.hide();
}
}
#Override
public void handleProgressNotification(ProgressNotification pn) {
bar.setProgress(pn.getProgress());
}
}
How do I return root scene instead of the BorderPane p including the Progress Indicator:
ProgressIndicator pi = new ProgressIndicator();
BorderPane p = new BorderPane();
p.setCenter(pi);
return new Scene(p, 300, 150);
This is a excellent tutorial for creating a PreLoader.
https://docs.oracle.com/javafx/2/deployment/preloaders.htm
Related
Please, consider the following code:
public class JavaFxTest4 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button();
button.setText("dialog");
button.setOnAction((e) -> {
Dialog<?> d = new Dialog<>();
final Window window = d.getDialogPane().getScene().getWindow();
Stage stage = (Stage) window;
stage.setMinHeight(450);
stage.setMaxHeight(450);
stage.setHeight(450);
stage.setMinWidth(600);
stage.setMaxWidth(600);
stage.setWidth(600);
window.setY(300); //<---- note this line
window.setX(660); //<---- note this line
d.showAndWait();
});
VBox root = new VBox();
root.getChildren().addAll(button);
var scene = new Scene(root, 1920, 1000);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As you can see window position is 660 (x) and 300 (y). And this is the result:
As you can see x position is correct, but y position is not. Is this a bug or I misunderstand something? I use javafx 19-ea+3 and openjdk version "14.0.2" on Ubuntu 20.
It is a bug in JavaFX. Issue is here
Today I faced the following problem:
I set title for primaryStage using method setTitle(). This title is displayed correctly in the window, but when I hover cursor on program icon in OS dockbar I see just path to main program class (see screenshot below). How I can fix it?
Title in program window and title in OS dockbar. And I use this code:
#Override
public void start(Stage stage) throws IOException {
this.stage = stage;
instance = this;
// App initialization
Parent root = FXMLLoader.load(SlimeBot.class.getClassLoader().getResource("fxml/Main.fxml"));
Scene scene = new Scene(root, 800, 600);
stage.setTitle("SlimeBot - Панель управления");
stage.setScene(scene);
stage.show();
}
Trying set title using field in java.awt.Toolkit:
#Getter
private static SlimeBot instance;
static {
try {
Toolkit xToolkit = Toolkit.getDefaultToolkit();
java.lang.reflect.Field awtAppClassNameField = xToolkit.getClass().getDeclaredField("awtAppClassName");
awtAppClassNameField.setAccessible(true);
awtAppClassNameField.set(xToolkit, "SlimeBot - Панель управления");
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
launch(args);
}
#Getter
private Stage stage;
#Override
public void start(Stage stage) throws IOException {
this.stage = stage;
instance = this;
// App initialization
Parent root = FXMLLoader.load(SlimeBot.class.getClassLoader().getResource("fxml/Main.fxml"));
Scene scene = new Scene(root, 800, 600);
stage.setTitle("SlimeBot - Панель управления");
stage.setScene(scene);
stage.show();
}
}```
I'm making the application with JavaFX and Scene Builder. I have a fullscreen video before my appliaction start. SO it is a kind of intro for my appliaction.
A video has the same background as my main stage.
The problem is I have flickering effect at the very beginning when I launch the appliaction. Buttons and text from main window appear during like half of a second and then my video start.
How can I remove or hide that effect?
Please, check this link for more clear understanding of my problem
Video
Main Class:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml/card.fxml"));
Parent root = (Parent) loader.load();
Scene scene = new Scene(root, 1600, 600);
primaryStage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMaximized(true);
primaryStage.setResizable(true);
primaryStage.getIcons().add(new Image("logo-icon.png"));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Controller where I place All buttons and text. I also have a video here:
public class Controller implements Initializable {
#FXML private AnchorPane mainAnchor, anchorRow, randomCard, randomCardBack, previewCard, bolt1;
#FXML private StackPane hBoxCat0;
#FXML private Button btnPalette, btnFont, btnQuestCards, btnNonQuestCards;
#FXML private ToggleButton btnPref1, btnPref2, btnPref3, btnPref4, btnPref5, btnPref6, btnPref7, btnPref8;
#FXML private Label lb_randomCard, lb_randomCardBack, answerID, lb_previewCard, category1, category2, category3, category4, category5, category6, category7, category8;
#FXML private ToggleGroup group;
#FXML private JFXColorPicker colorPickerCategory;
#FXML private Rectangle rectRandom, rectRandomBack;
#FXML private MediaView media;
private MediaPlayer mp;
private static final String MEDIA_URL = "intro.mp4";
#FXML
public void initialize(URL location, ResourceBundle resources) {
mp = new MediaPlayer(new Media(this.getClass().getResource(MEDIA_URL).toExternalForm()));
media.setMediaPlayer(mp);
media.setSmooth(true);
mp.setAutoPlay(true);
Timeline tm = new Timeline(new KeyFrame(Duration.millis(3000), new KeyValue(media.opacityProperty(), 0.0)));
tm.setDelay(Duration.millis(5500));
tm.play();
addQuestionsToArrayCat1();
addAnswersToArrayCat1();
addSentencesToArray();
matchSentences();
}
}
I'm trying to make TreeView with CheckBoxTreeItems. When I collapse/expand a CheckBoxTreeItems the image I set up does not display correctly. I googled but I couldn't find correct answer. On Stack Overflow, I found a similar problem, but I didn't get a valid answer.
E.g
JavaFX CheckBoxTreeItem graphic disappear when siblings collapse
JavaFX CheckBoxTreeItem: Graphic disappears if graph is extended
Any ideas?
public class ClientApplication extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage) {
ImageView folderIcon = new ImageView();
Image folderImage = new Image("image/folder.png");
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", folderIcon);
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), folderIcon);
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
}
enter image description here
I tried to use the ideas provided by #Jai,But when I click the expand/collapse icon, there is still a problem.Attachment is a screenshot.Thanks in advance.
enter image description here
ImageView is a JavaFX control. This means that each instance represents a unique control you see on your screen. You should never use the same instance for multiple locations in your GUI.
On the other hand, Image represents an image (i.e. an array of pixel data), so it is reusable.
This should work:
#Override
public void start(final Stage stage) {
final Image folderImage = new Image("image/folder.png");
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", createImageView(folderImage));
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), createImageView(folderImage));
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
private ImageView createImageView(Image folderImage) {
ImageView folderIcon = new ImageView();
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
return folderIcon;
}
I try to switch between scenes in same stage. I'm beginner in JavaFX so I don't know how to do it easily without spaghetti code. When I start code below I get null pointer at rootLayout.setCenter(content) in showCarChoosePage method (second scene). I know rootLayout is null and I was trying create new scene with and load it to primaryStage but then I got null pointer too. showCarChoosePage method is calling from LoginController. Thanks for your help
public class MC extends Application {
public Scene scene;
private GridPane grid;
public AnchorPane content;
public BorderPane rootLayout;
public Stage primaryStage;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("VMHT v0.1");
try {
FXMLLoader loader = new FXMLLoader(MC.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
showLoginPage();
//showCarChoosePage();
}
public void showLoginPage(){
try {
FXMLLoader loader = new FXMLLoader(MC.class.getResource("view/LoginView.fxml"));
content = (AnchorPane) loader.load();
rootLayout.setCenter(content);
LoginController controller = loader.getController();
controller.setMC(this);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void showCarChoosePage(){
try {
FXMLLoader loader = new FXMLLoader(MC.class.getResource("view/CarChooseView.fxml"));
AnchorPane content = (AnchorPane) loader.load();
rootLayout.setCenter(content);
CarChooseController controller = loader.getController();
controller.setMC(this);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Here is another way to handle multiple scenes. It uses Controllers for each scene. You must pass the initial stage that was created in Main to each new Controller. You must also pass whatever data you want to share from Controller to Controller. This is all done with methods that are added to your controllers.
In this simple case a Person object was created with name, sex, and age class variables as well as setters and getters for these objects.
Then I created 3 fxml files (using SceneBuilder) that displayed the name, sex, and age values. Of course, I also created 3 controllers, one for each fxml file.
The user was allowed to edit these values. One scene allowed name entry, another allowed sex entry, and the last allowed age entry. This simulated a complex app where data entry and processing was divided among 3 different scenes.
The three fxml files and the 3 controllers look very similar to one another. Here is the NameController. It first has setters for the Stage and Person objects. It also has button event handlers to allow the user to navigate to the other stages.
package multiscene;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import java.net.URL;
import java.util.ResourceBundle;
public class NameController implements Initializable {
#FXML private TextField lblSex;
#FXML private TextField lblAge;
#FXML private TextField txtName;
private Stage myStage;
private Person person;
public void setStage(Stage myStage) {
this.myStage = myStage;
}
public void setPerson(Person person) {
this.person = person;
lblAge.setText(person.getAge());
txtName.setText(person.getName());
lblSex.setText(person.getSex());
}
#FXML
private void ageClicked(ActionEvent event) throws Exception{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(NameController.class.getResource("Age.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Person Editor");
// dialogStage.initModality(Modality.WINDOW_MODAL);
//dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
// Set the person into the controller
person.setName(txtName.getText());
AgeController newController = loader.getController();
newController.setStage(dialogStage);
newController.setPerson(person);
dialogStage.show();
myStage.close();
}
#FXML
private void sexClicked(ActionEvent event) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(AgeController.class.getResource("Sex.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Person Editor");
// dialogStage.initModality(Modality.WINDOW_MODAL);
//dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
// Set the person into the controller
person.setName(txtName.getText());
SexController newController = loader.getController();
newController.setStage(dialogStage);
newController.setPerson(person);
dialogStage.show();
myStage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Main.java must initialize the Stage and the shared data as follows. Both the Stage and the shared data are passed to the first Scene when it is loaded.
package multiscene;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Person person = new Person();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("Name.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Person Editor");
Scene scene = new Scene(page);
dialogStage.setScene(scene);
NameController nameController = loader.getController();
nameController.setStage(dialogStage);
nameController.setPerson(person);
dialogStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Here is one simple method you might try
import javafx.stage.Stage;
public class ManyScenes extends Application {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(final Stage primaryStage) {
primaryStage.setTitle("Hello World");
Group root1 = new Group();
Group root2 = new Group();
Group root3 = new Group();
final Scene scene1 = new Scene(root1, 300, 250);
final Scene scene2 = new Scene(root2, 300, 250);
final Scene scene3 = new Scene(root3, 300, 250);
Button go1 = new Button();
go1.setLayoutX(100);
go1.setLayoutY(80);
go1.setText("Go to scene2");
go1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
primaryStage.setScene(scene2);
}
});
root1.getChildren().addAll(new Label("Scene 1"), go1);
Button go2 = new Button();
go2.setLayoutX(100);
go2.setLayoutY(80);
go2.setText("Go to scene3");
go2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
primaryStage.setScene(scene3);
}
});
root2.getChildren().addAll(new TextField(), go2);
Button go3 = new Button();
go3.setLayoutX(100);
go3.setLayoutY(80);
go3.setText("Back to scene1");
go3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
primaryStage.setScene(scene1);
}
});
root3.getChildren().addAll(new TextArea(), go3);
primaryStage.setScene(scene1);
primaryStage.show();
}
}