I am building an application in Java where I need to represent a predefined directory in any kind of view in my window. Imagine something like a backup application where the main window displays all of the files under a specific directory.
Is there a way to do so using JavaFX? I do not care if files are going to be displayed as a tree or icons or anything really.
Thanks
edit: what I tried so far with no luck. This is my Controller class:
import javafx.scene.control.*;
import java.io.IOException;
public class ViewController {
public ListView listView;
public ViewController() throws IOException {
listView = new ListView();
listView.getItems().addAll("Iron Man", "Titanic", "Contact", "Surrogates");
}
}
and my fxml contains:
<ListView fx:id="listView" prefHeight="200.0" prefWidth="200.0" />
I wrote up a brief program that displays a tree of files and directories chosen by the user.
The result:
How it works:
When the user clicks the "Load Folder" button,
getNodesForDirectory is called, and recursively walks through the file tree, making tree items along the way.
Here is the code:
import java.io.File;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class DirectoryViewer extends Application {
#Override
public void start(Stage primaryStage) {
TreeView<String> a = new TreeView<String>();
BorderPane b = new BorderPane();
Button c = new Button("Load Folder");
c.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
DirectoryChooser dc = new DirectoryChooser();
dc.setInitialDirectory(new File(System.getProperty("user.home")));
File choice = dc.showDialog(primaryStage);
if(choice == null || ! choice.isDirectory()) {
Alert alert = new Alert(AlertType.ERROR);
alert.setHeaderText("Could not open directory");
alert.setContentText("The file is invalid.");
alert.showAndWait();
} else {
a.setRoot(getNodesForDirectory(choice));
}
}
});
b.setTop(c);
b.setCenter(a);
primaryStage.setScene(new Scene(b, 600, 400));
primaryStage.setTitle("Folder View");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public TreeItem<String> getNodesForDirectory(File directory) { //Returns a TreeItem representation of the specified directory
TreeItem<String> root = new TreeItem<String>(directory.getName());
for(File f : directory.listFiles()) {
System.out.println("Loading " + f.getName());
if(f.isDirectory()) { //Then we call the function recursively
root.getChildren().add(getNodesForDirectory(f));
} else {
root.getChildren().add(new TreeItem<String>(f.getName()));
}
}
return root;
}
}
Good luck with your project!
Related
I try to use vlcj-javafx-demo to develop a video player, and I put the progress bar(Slider) on the StackPane over the video layer. In the beginning, it looks work well, but when I set maximum or full screen the app, it looks some components UI did not update correctly. How can I correct it?
Thanks a lot!
normally:
[1]: https://i.stack.imgur.com/bbE51.png
normally:
[2]: https://i.stack.imgur.com/Plsb1.png
the red color is the sence background color.
the code :
package my.javafx.myplayer;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Slider;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.base.MediaPlayer;
import uk.co.caprica.vlcj.player.base.MediaPlayerEventAdapter;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import java.util.ArrayList;
import java.util.List;
import static uk.co.caprica.vlcj.javafx.videosurface.ImageViewVideoSurfaceFactory.videoSurfaceForImageView;
/**
*
*/
public class VlcjJavaFxApplication extends Application {
private final MediaPlayerFactory mediaPlayerFactory;
private final EmbeddedMediaPlayer embeddedMediaPlayer;
private ImageView videoImageView;
Slider progress=new Slider();
public VlcjJavaFxApplication() {
this.mediaPlayerFactory = new MediaPlayerFactory();
this.embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
this.embeddedMediaPlayer.events().addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
#Override
public void mediaPlayerReady(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
Platform.runLater(()->{
progress.setValue(0);
progress.setMax(embeddedMediaPlayer.media().info().duration());
progress.setMin(0);
});
}
#Override
public void playing(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
}
#Override
public void paused(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
}
#Override
public void stopped(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer) {
}
#Override
public void timeChanged(uk.co.caprica.vlcj.player.base.MediaPlayer mediaPlayer, long newTime) {
Platform.runLater(()->{
progress.setValue(newTime);
});
}
});
}
#Override
public void init() {
this.videoImageView = new ImageView();
this.videoImageView.setPreserveRatio(true);
embeddedMediaPlayer.videoSurface().set(videoSurfaceForImageView(this.videoImageView));
}
#Override
public final void start(Stage primaryStage) throws Exception {
List<String> params = new ArrayList<String>();
params.add("/Users/baixq/Downloads/妙味课堂xhtml+css2/妙味课堂-XHTMLCSS2整站视频教程-4.avi");
if (params.size() != 1) {
System.out.println("Specify a single MRL");
System.exit(-1);
}
StackPane root=new StackPane();
//BorderPane root = new BorderPane();
root.setStyle("-fx-background-color: black;");
videoImageView.fitWidthProperty().bind(root.widthProperty());
videoImageView.fitHeightProperty().bind(root.heightProperty());
root.widthProperty().addListener((observableValue, oldValue, newValue) -> {
// If you need to know about resizes
});
root.heightProperty().addListener((observableValue, oldValue, newValue) -> {
// If you need to know about resizes
});
Scene scene = new Scene(root, 1200, 675, Color.RED);
primaryStage.setTitle("vlcj JavaFX");
primaryStage.setScene(scene);
AnchorPane contrlBox=new AnchorPane();//操作面板上的控制模块
contrlBox.prefWidthProperty().bind(root.widthProperty());
contrlBox.prefHeightProperty().bind(root.heightProperty().multiply(0.1));
BorderPane controlBar=new BorderPane();
controlBar.setStyle("-fx-background-color: #130c0e;");
controlBar.prefWidthProperty().bind(root.widthProperty());
controlBar.prefHeightProperty().bind(root.heightProperty().multiply(0.1));
controlBar.setCenter(progress);
Button fullScreen=new Button("全屏");
controlBar.setRight(fullScreen);
contrlBox.getChildren().add(controlBar);
contrlBox.setBottomAnchor(controlBar, 0.0);
root.getChildren().addAll(videoImageView,contrlBox);
primaryStage.show();
embeddedMediaPlayer.media().play(params.get(0));
fullScreen.setOnAction(event->{
primaryStage.setFullScreen(true);
});
root.setOnMouseEntered(event->{
Platform.runLater(()->{
FadeTransition ft = new FadeTransition(Duration.millis(500), contrlBox);
ft.setFromValue(0.0);
ft.setToValue(1);
//ft.setCycleCount(Timeline.INDEFINITE);
ft.setAutoReverse(false);
ft.play();
contrlBox.setVisible(true);
});
});
root.setOnMouseExited(event->{
Platform.runLater(()->{
FadeTransition ft = new FadeTransition(Duration.millis(500), contrlBox);
ft.setFromValue(1);
ft.setToValue(0.0);
ft.setAutoReverse(false);
ft.play();
contrlBox.setVisible(false);
});
});
//embeddedMediaPlayer.controls().setPosition(0.4f);
}
#Override
public final void stop() {
embeddedMediaPlayer.controls().stop();
embeddedMediaPlayer.release();
mediaPlayerFactory.release();
}
public static void main(String[] args) {
launch(args);
}
}
You appear to be using a Linux OS, try passing one or more of these system properties when you start your JVM:
-Dprism.dirtyopts=false
-Dprism.forceUploadingPainter=true
This is mentioned under "Linux notes" here: https://github.com/caprica/vlcj-javafx-demo/tree/vlcj-5.x
I have seen similar painting glitches on Linux before and in all cases using these properties, at least for me, clears the issue with only a small hit to performance - even when doing something like a full-screen grid of nine concurrent media players, where each one had an animating video controls overlay.
I am making a Editable ComboBox which show any values contain the input and it works fine.
But the problem is in the input field, whenever i typed Space or arrow buttons the input field keep reseting.
I tried setonKeyPressed and setonKeyTyped too but it isn't solve the problem.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
ObservableList<String> fruit = FXCollections.observableArrayList();
fruit.add("apple");
fruit.add("orange");
fruit.add("banana");
ComboBox myComboBox = new ComboBox();
myComboBox.setEditable(true);
myComboBox.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
myComboBox.getItems().clear();
myComboBox.show();
String input = myComboBox.getEditor().getText();
for ( int i = 0 ; i < fruit.size(); i++) {
if(fruit.get(i).contains(input)) { //Check if the list contains the input
myComboBox.getItems().add(fruit.get(i));
}
}
}
});
HBox hbox = new HBox(myComboBox);
primaryStage.setScene(new Scene(hbox, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I am begging with JavaFx, and I realized that I need some help to update a TreeView with some TreeItems in runtime, and it should be updated in the main window.
Here, you can see a screenshot of the two windows:
The bigger is the main window and it calls (by clicking in File >> New Project), new smaller. In the smaller window, I could get the String that is typed and than the enter button is clicked.
The trouble is: How can I show the new items created by the "new project window" (the smaller window in the pic) in the TreeView in the main window(the bigger)?
The treeview is in the left side of the main window.
I hope I was clear.
Here is the code of the controllers of these windows:
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeItem.TreeModificationEvent;
import javafx.scene.control.TreeView;
import javafx.stage.Modality;
import javafx.stage.Stage;
/**
* this class handles with the main window of our LDF Tool
* #author Vinicius
* #version 1.0
*/
public class MainController implements Initializable{
#FXML
TreeView<String> treeView;
#FXML
MenuItem newProject;
private boolean flag = false;
private NewProjectWindowController npwc;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#FXML
public void newProjectClicked(ActionEvent event){
try{
flag = true;
FXMLLoader fxml = new FXMLLoader(getClass().getResource("newProjectWindow.fxml"));
Parent root = (Parent) fxml.load();
Stage newWindow = new Stage();
newWindow.setTitle("New Project");
newWindow.initModality(Modality.APPLICATION_MODAL);
newWindow.setScene(new Scene(root));
newWindow.show();
} catch (Exception e) {
System.out.println("caiu na exceção");
}
}
/**
* to this method, choose the project's name as argument, and it will be put on the
* tree with the archives that should be created together
* #param projectName
*/
public void doTree(String projectName){
TreeItem<String> root = new TreeItem<>("projectName");
root.setExpanded(true);
//TreeItem<String> folha1 = new TreeItem<String>(projectName + " arquivo 1");
//root.getChildren().add(folha1);
treeView.setRoot(root);
}
The other controller class:
package application;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class NewProjectWindowController implements Initializable{
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#FXML
Button cancelButton;
#FXML
Button enterButton;
#FXML
TextField textInput;
private String input;
public String getInput(){
return this.input;
}
#FXML
public void cancelButtonClicked(ActionEvent event) {
Stage window = (Stage) this.cancelButton.getParent().getScene().getWindow();
window.close();
}
#FXML
public void enterButtonClicked(ActionEvent event) {
input = hasString();
Stage window = (Stage) this.enterButton.getParent().getScene().getWindow();
window.close();
}
private String hasString(){
if (this.textInput.getText().isEmpty())
return null;
return this.textInput.getText();
}
}
Please, assume that I mapped everything ok in the FXML file.
thanks
#FXML
public void newProjectClicked(ActionEvent event){
try{
flag = true;
FXMLLoader fxml = new FXMLLoader(getClass().getResource("newProjectWindow.fxml"));
Parent root = (Parent) fxml.load();
Stage newWindow = new Stage();
newWindow.setTitle("New Project");
newWindow.initModality(Modality.APPLICATION_MODAL);
newWindow.setScene(new Scene(root));
// showAndWait blocks execution until the window closes:
newWindow.showAndWait();
NewProjectWindowController controller = fxml.getController();
String input = controller.getInput();
if (input != null) {
TreeItem<String> currentItem = treeView.getSelectionModel().getSelectedItem();
if (currentItem == null) currentItem = treeView.getRoot();
currentItem.getChildren().add(new TreeItem<>(input));
}
} catch (Exception e) {
System.out.println("caiu na exceção");
}
}
So I do not get any errors when I execute my code.
I also have setup controller in my fxml and code that I post below is of controller and main class.Since I already posted fxml in previous post.
package realEstateApplication;
import javafx.application.Application;
//import javafx.fxml.FXMLLoader;
//import javafx.scene.Parent;
//import javafx.scene.Scene;
import javafx.stage.Stage;
import realEstateApplication.controllers.loginViewController;
public class Main extends Application {
public Main() {
System.out.println("Main invoked ... \n");
}
#Override
public void start(Stage primaryStage) throws Exception{
// Parent loginRoot = FXMLLoader.load(getClass().getResource("views/loginView.fxml"));
loginViewController loginMVC = new loginViewController();
// Parent login = FXMLLoader.load(getClass().getResource("views/loginView.fxml"));
/* Parent admin = FXMLLoader.load(getClass().getResource("views/adminView.fxml"));
Parent registerAdmin = FXMLLoader.load(getClass().getResource("views/registerAdminView.fxml"));
Parent registerCustomer = FXMLLoader.load(getClass().getResource("views/registerCustomerView.fxml"));
Parent registerCompany = FXMLLoader.load(getClass().getResource("views/registerCompanyView.fxml"));
Parent registerFlat = FXMLLoader.load(getClass().getResource("views/registerFlatView.fxml"));*/
// Stage firstStage = new Stage();
// firstStage.setTitle("Login");
// firstStage.setScene(new Scene(loginRoot, 600, 400));
//firstStage.show();
/*Stage secondaryStage = new Stage();
secondaryStage.setTitle("Administrator");
secondaryStage.setScene(new Scene(admin, 600, 399));
secondaryStage.show();
Stage ternaryStage = new Stage();
ternaryStage.setTitle("For new admins");
ternaryStage.setScene(new Scene(registerAdmin, 600, 400));
ternaryStage.show();
Stage forthStage = new Stage();
forthStage.setTitle("New customers register here");
forthStage.setScene(new Scene(registerCustomer, 600, 400));
forthStage.show();
Stage pentaStage = new Stage();
pentaStage.setTitle("Register new company here");
pentaStage.setScene(new Scene(registerCompany, 600, 400));
pentaStage.show();
Stage hexaStage = new Stage();
hexaStage.setTitle("Create flats here");
hexaStage.setScene(new Scene(registerFlat, 600, 400));
hexaStage.show();*/
}
public static void main(String[] args) {
launch(args);
}
}
Below I have included my controller code:
package realEstateApplication.controllers;
import javafx.fxml.FXML;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Modality;
import javafx.stage.Stage;
/**
* Created by PriteshJ on 4/16/16.
*/
public class loginViewController extends Application {
#FXML private TextField username_tField;
#FXML private PasswordField password_tField;
#FXML private Button login_Button;
#FXML private Button signUp_Button;
public loginViewController() {
System.out.println("Login Controller constructor invoked ...\n");
}
#Override
public void start(Stage loginStage) throws Exception {
Parent loginRoot = FXMLLoader.load(getClass().getResource("views/loginView.fxml"));
if(loginRoot == null)
System.out.println("something weird happened .... ");
loginStage.setTitle("Login");
loginStage.setScene(new Scene(loginRoot, 600, 400));
loginStage.initModality(Modality.WINDOW_MODAL);
loginStage.show();
}
}
(So I tried to pass a reference to Parent variable which points to my fxml file which is within scope of start method since my Main class extends Application (javafx), that gave me NullPointerException.
Tried to make it static but that didn't work either.
Then tried approach I posted now , it gives no errors but neither it works.)
Well I am trying to think from MVC perspective in JavaFX. So I got a loginViewController which I rely to completely own login.fxml and do any operations on it. I got a main class where JavaFX application starts but it can only construct my view from an object of my viewController. I went through lots of examples, but so far I never came across an example that shows how to do above stuff that I want to.
Looking forward to suggestions.
EDIT:
I have an alert box that pops up if the user clicks "Delete" for removing an item in a ListView. It works, but I would like it to pop over the original stage. It showed up in my first monitor. Is there any way to set the position of the alert when it's shown?
Note, the "owner" is in a different class, and I created everything with Scenebuilder/FXML. I cannot figure out how to get initOwner() to work. Here is the "Main" class:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Assignment_5 extends Application {
public Stage primaryStage;
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("Assignment_5.fxml"));
primaryStage.setTitle("Plant Pack");
primaryStage.setScene(new Scene(root, 1200, 500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Here is the working code within the Controller class. It's not necessary to implement the modality of this alert, but it would be a nice addition to make it more convenient. I simply don't know how to pass the main Window from the Main class to this:
protected void handleDeleteButtonClick(ActionEvent event) {
Alert alertBox = new Alert(Alert.AlertType.CONFIRMATION, "Confirm Delete", ButtonType.OK, ButtonType.CANCEL);
alertBox.setContentText("Are you sure you want to delete this " + plantType.getValue().toString().toLowerCase() + "?");
alertBox.showAndWait();
if(alertBox.getResult() == ButtonType.OK) {
int selectedPlant = plantList.getSelectionModel().getSelectedIndex();
observablePlantList.remove(selectedPlant);
}
else {
alertBox.close();
}
}
I understand this is fairly new, so it's difficult to find many resources. If anyone knows any info I may have missed, please let me know. Thanks for any help offered.
I am using Java 8 with IntelliJ 14.1.5.
As #jewelsea suggests, setting the modality and owner for the alert box will assure that the alert will appear over the stage, even if the stage is moved.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class DeleteAlertDemo extends Application {
Stage owner;
ObservableList<String> observablePlantList;
ListView<String> plantList;
protected void handleDeleteButtonClick(ActionEvent event) {
String item = plantList.getSelectionModel().getSelectedItem();
Alert alertBox = new Alert(Alert.AlertType.CONFIRMATION, "Confirm Delete",
ButtonType.OK, ButtonType.CANCEL);
alertBox.setContentText("Are you sure you want to delete this "
+ item.toLowerCase() + "?");
alertBox.initModality(Modality.APPLICATION_MODAL); /* *** */
alertBox.initOwner(owner); /* *** */
alertBox.showAndWait();
if (alertBox.getResult() == ButtonType.OK) {
int selectedPlant = plantList.getSelectionModel().getSelectedIndex();
observablePlantList.remove(selectedPlant);
} else {
alertBox.close();
}
}
#Override
public void start(Stage primaryStage) {
owner = primaryStage; /* *** */
Button deleteBtn = new Button();
deleteBtn.setText("Delete");
deleteBtn.setOnAction(this::handleDeleteButtonClick);
observablePlantList = FXCollections.observableArrayList("Begonia",
"Peony", "Rose", "Lilly", "Chrysanthemum", "Hosta");
plantList = new ListView<>(observablePlantList);
plantList.getSelectionModel().select(0);
BorderPane root = new BorderPane();
root.setCenter(plantList);
root.setRight(deleteBtn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Delete Alert Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}