How can i make JavaFX filechooser is always on top?
In my application some other dialogs call filechooser and that dialog is set as alwaysonTop, so the filechooser dialog is located behind that dialog.
How can i make the filechooser dialog is alwaysonTop of the window?
I made filechooser like this code.
public static File getSaveFileFX(final String suffix, String title) {
File[] selectedFile = {null};
FileChooser fc = new FileChooser();
fc.setTitle(title);
String root = "*" + suffix;
String fileFormat = suffix + " files";
fc.getExtensionFilters().addAll(new ExtensionFilter(fileFormat, root));
fc.setInitialDirectory(new File(getRecentDirectoryPath()));
PlatformImpl.runAndWait(new Runnable() {
#Override
public void run() {
selectedFile[0] = fc.showSaveDialog(null);
if(selectedFile[0] != null && !title.equals("Sava To .CSV file")) {
//filtering with title
mPreferences.put(RECENT_FILE_PATH, selectedFile[0].getAbsolutePath());
mPreferences.put(RECENT_DIRECTORY_PATH, selectedFile[0].getParent());
}
}
});
if(selectedFile[0] != null && !selectedFile[0].getName().endsWith(suffix)) {
return new File(selectedFile[0].getAbsolutePath()+"."+suffix);
}else {
return selectedFile[0];
}
}
and the other dialog is set as
dialog.alwaysOnTop(true);
You have to set main dialog alwaysOnTop(false);
And the dialog of FileChooser alwaysOnTop(true);
Check this sample, its work.
public void initializationDialog(Stage stage) {
stage.resizableProperty().setValue(false);
stage.setAlwaysOnTop(false);
stage.toBack();
openFile();
}
public File openFile(String descriptionOfFile, String extensionOfFile) {
FileChooser fileChooser = new FileChooser();
Stage stage2 = new Stage();
stage2.initOwner(stage);
stage2.initModality(Modality.WINDOW_MODAL);
stage2.setAlwaysOnTop(true);
FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter(descriptionOfFile, extensionOfFile);
fileChooser.getExtensionFilters().add(filter);
return fileChooser.showOpenDialog(stage2);
}
Related
maybe someone will explain. I have a method, that sets label text if login is successful.
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + globalUser.getUserName()); //works
infoLine.setText("Redirecting to main dashboard..."); //works
}
}
And if I add additional code, which changes the scene after login, the label text is not changing:
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + CurrentUser.getCurrentUser().getUserName());//not working
infoLine.setText("Redirecting to main dashboard..."); //not working
//Changing scene after successful login
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
}
How to solve this problem?
My controller class looks like this. Nothing special. After 2 validations it set texts of labels and changes scenes.
public class LoginController {
#FXML
private TextField username;
#FXML
private PasswordField password;
#FXML
private Label infoLine;
#FXML
private Label welcome;
#FXML
private Button exitBtn;
UserDao userDao = new UserDao();
#FXML
private void initialize() {
close();
}
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + CurrentUser.getCurrentUser().getUserName());
infoLine.setText("Redirecting to main dashboard...");
//Changing scene after successful login
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
}
private boolean validateFields(String userName, String password) {
if (userName.isEmpty() || password.isEmpty()) {
infoLine.setText("Username and password can't be empty!");
return false;
}
return true;
}
private synchronized boolean validateLogin(String userName, String password) {
User user = userDao.getConnectedUser(userName, password);
if (user == null) {
infoLine.setText("User not found!");
return false;
}
CurrentUser.setCurrentUser(user);
return true;
}
private void close() {
exitBtn.setOnAction(SceneController::close);
}
}
Basically, the text is changing. The problem is as soon as the text is changed, you load the next view. This is happening really fast. The solution is to slow things down. Mainly, give the user time to see the text change before loading the new view. This can be done using PauseTransition.
After the text change, try the following code. After the text changes, this code gives a two-second delay before loading the new view.
PauseTransition pause = new PauseTransition(Duration.seconds(2));
pause.setOnFinished(
e -> {
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
);
pause.play();
apologies for the length of my code. I realized last night that I was on the wrong path and now have gotten stuck on an issue that I think relates to JavaFX event handling. Initially I had the logic functioning outside a GUI in a basic loop that depended on interaction through the console. Everything was working great. I've now tried to get this to work in a GUI with interaction from the user.
I have two main problems with the code below.
The first is that the text in textArea is not updating with additional text after the startButton executes the start of my main logic sequence. The first append starts right under the first while loop. I was hoping to have this show up in the GUI as the logic executes. I'm not sure if I need to tell the GUI to update at certain intervals or if there's something else wrong.
Second, I'm not sure how to get the program to wait for the user to type in something into textField before hitting the textButton I created to continue on. I used to have a scanner created which caused the program to wait in the console for input. I realize I need some way of telling it to wait for a button press when it's running inside JavaFX.
I chose not to include the rest of the code to make things easier to read, but I can add it on if it will help resolve this issue.
Thank you everyone for your help!
public class FxApp extends Application {
//Creates FileParser object with methods that alter the incoming Array of Strings into the format we need
FileParser fileParser = new FileParser();
Configure configure = new Configure();
private String text;
private String initialState;
private ArrayList<Machine> machines = new ArrayList<Machine>();
private Map<String, String> initialStates = new HashMap<String, String>();
private Map<String, String> states = new HashMap<String, String>();
private Map<String, ArrayDeque<String>> queues = new HashMap<String, ArrayDeque<String>>();
private Map<Integer, ArrayList<String>> parsedData = new HashMap<Integer, ArrayList<String>>();
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("File Chooser");
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().addAll(new ExtensionFilter("Text Files", "*.txt"));
Button startButton = new Button("Start");
Button openButton = new Button("Click to open a file...");
openButton.setPrefSize(200, 80);
Button textButton = new Button("Enter");
TextArea textArea = new TextArea();
textArea.setWrapText(true);
TextField textField = new TextField();
Label lbl = new Label();
VBox vbox = new VBox(lbl, openButton, startButton, textArea, textField, textButton);
vbox.setSpacing(10);
vbox.setPadding(new Insets(15));
lbl.setText("This tool creates virtual automata based \ron the file.");
Scene scene = new Scene(vbox, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
openButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
File file = fileChooser.showOpenDialog(primaryStage);
if (file != null) {
//Execute the method to convert to string array before sending to file parser
try {
fileParser.convertFile(file);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
textButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
text = textField.getText();
}
});
startButton.setOnAction(new EventHandler <ActionEvent>()
{
public void handle(ActionEvent event)
{
machineCreation();
String exit = "no";
String nextLine = null;
ArrayList<String> listOfCurrentTransitions = new ArrayList<String>();
int nextInt = 0;
states = initialStates;
while(!(exit.toLowerCase().equals("yes"))) {
textArea.appendText("Choose a state to load");
//Print out the states possible for each machine
ArrayList<String> tempTrans = machines.get(nextInt).getTransitions();
//This loops through the list of transitions of the machine and pulls possible transitions from its current state
for(int i = 0; i < tempTrans.size(); i++) {
String pull = tempTrans.get(i);
String[] apart = pull.split(" ");
pull = apart[0];
if(states.get(Integer.toString(nextInt)).equals(pull)) {
listOfCurrentTransitions.add(tempTrans.get(i));
}
}
if(!(listOfCurrentTransitions.isEmpty())) {
textArea.appendText("The following transitions are possible. Choose one: " + listOfCurrentTransitions);
}
else {
textArea.appendText("No transitions for this machine exist from its current state");
}
//Tell GUI to wait for user input in textField and execute textButton which assigns to String text. Resume on button click.
The while loop blocks the JavaFX application thread which prevents updates of the GUI and handling of events.
You need to execute the logic of a single iteration of the loop on each "text commit" instead:
private TextArea textArea;
private void activateState(int nextInt) {
ArrayList<String> listOfCurrentTransitions = new ArrayList<String>();
textArea.appendText("Choose a state to load");
//Print out the states possible for each machine
ArrayList<String> tempTrans = machines.get(nextInt).getTransitions();
//This loops through the list of transitions of the machine and pulls possible transitions from its current state
for(int i = 0; i < tempTrans.size(); i++) {
String pull = tempTrans.get(i);
String[] apart = pull.split(" ");
pull = apart[0];
if(states.get(Integer.toString(nextInt)).equals(pull)) {
listOfCurrentTransitions.add(tempTrans.get(i));
}
}
if(listOfCurrentTransitions.isEmpty()) {
textArea.appendText("No transitions for this machine exist from its current state");
} else {
textArea.appendText("The following transitions are possible. Choose one: " + listOfCurrentTransitions);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
...
textArea = new TextArea();
...
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
machineCreation();
activateState(0);
}
});
textButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// read input and ask for more input...
int nextState = Integer.parseInt(textField.getText()); // TODO: deal with invalid input
activateState(nextState);
}
});
You probably need to fix the logic a bit to verify a transition is valid, change the values of some fields ect...
I am trying to save a screenshot of the current scene using javaFX.
saveMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
WritableImage image = scene.snapshot(new SnapshotParameters(), null);
// TODO: probably use a file chooser here
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save Image");
File file = fileChooser.showSaveDialog(primaryStage);
if(file != null)
{
try {
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
}
catch (IOException e) {
System.out.println("Couldn't Save.");
}
}
}
});
But my compiler NetBeans IDE 8.1 is giving an error:
incompatible types: SnapshotParameters cannot be converted to Callback<SnapshotResult, Void>
Can someone tell me what I am doing wrong?
And your compiler is right. A Scene just does not have a method like the one you are trying to call. Just use
WritableImage image = scene.snapshot(null);
I have a JavaFX app using JRE1.8.0 u40. I converted my Swing JFileChooser Open and Save to the newer JavaFX FileChooser Open and Save, Windows7 style Dialog box. But I have not found an equivalent JavaFX FileChooser method to replace the JFileChooser method I'm using for deleting a file(s) as shown below:
public static void deleteFile() throws IOException {
JFileChooser fileDialog = new JFileChooser("C:\\ProgramData\\L1 Art Files\\");
File[] selectedFiles;
fileDialog.setSelectedFiles(null);
// Set frame properties
fileDialog.setDialogTitle("Delete Pixel Art File(s)");
//fileDialog.setLayout(new FlowLayout());
fileDialog.setSize(400, 400);
fileDialog.setVisible(true);
fileDialog.setMultiSelectionEnabled(true); // Allow multiple selection
fileDialog.setVisible(true);
int option = fileDialog.showDialog(null, "Delete");
if (option != JFileChooser.APPROVE_OPTION)
return; //user canceled the
selectedFiles = fileDialog.getSelectedFiles();
if (selectedFiles != null) { //ask the user to replace this file
int response = JOptionPane.showConfirmDialog(null, "Are you sure want to delete this file?",
"Confirm Delete",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (response != JOptionPane.YES_OPTION) return;
}
for (File f : selectedFiles) {
Files.delete(f.toPath());
}
Is there a similar solution to the above for JavaFX using FileChooser or do I use the showOpenDialog(null) with setTitle("Delete Pixel Art File")?
You can easily perform that task using javafx like below :
#FXML
private void onDeleteAction(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Your_title_here");
List<File> selectedFiles = fileChooser.showOpenMultipleDialog(null);
if (selectedFiles != null) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
alert.setHeaderText("Warning !");
alert.setContentText("Are you sure you want to delete these files ?");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
for (File selectedFile : selectedFiles) {
selectedFile.delete();
}
}
} else {
System.out.println("Error Selection");
}
}
The above code was very helpful and works best with the other suggestion of checking for null and adding throws IOException to the deleteFile() method.
Everything works fine until I create a new tab. Then when I go to the previous and try to use any of the buttons they affect the latest tab not the one I have selected. But if I go to the latest tab it works like normal. Here is the class that I use to make my tabs. So, why is the previous tabs affecting the lastest? And how do I fix it?
public class JTab {
private javafx.scene.control.Tab tab;
private ImageView imgView;
private Image logo;
private BorderPane root;
private Button reloadButton, backButton, forwardButton;
private TextField field;
private WebView view;
private WebEngine engine;
private static JTab instance;
private JBrowser jBrowser;
private JTab(JBrowser jBrowser) {
this.jBrowser = jBrowser;
}
public static JTab getInstance(JBrowser browser) {
if(instance == null)
instance = new JTab(browser);
return instance;
}
public javafx.scene.control.Tab addTab() {
tab = new Tab();
tab.setText("New Tab");
tab.setOnClosed(event2 -> {
if(jBrowser.getTabPane().getTabs().size() == 1) {
jBrowser.getTabPane().setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
}
});
logo = new Image("unknown-document.png");
imgView = new ImageView(logo);
tab.setGraphic(imgView);
HBox hBox = new HBox(5);
hBox.setAlignment(Pos.CENTER);
reloadButton = new Button("Reload");
backButton = new Button("<");
forwardButton = new Button(">");
reloadButton.setOnAction(event1 -> engine.reload());
backButton.setOnAction(event1 -> loadData(goBack()));
forwardButton.setOnAction(event1 -> loadData(goForward()));
//The TextField for entering web addresses.
field = new TextField("Enter URL");
field.setPrefColumnCount(50); //make the field at least 50 columns wide.
field.focusedProperty().addListener((ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) -> { //When click on field entire thing selected
Platform.runLater(() -> {
if (field.isFocused() && !field.getText().isEmpty()) {
field.selectAll();
}
});
});
field.setOnKeyPressed(event -> { //When ENTER is pressed it will load page
if (event.getCode() == KeyCode.ENTER) {
if (!field.getText().isEmpty()) {
loadData(field.getText());
}
}
});
//Add all out navigation nodes to the vbox.
hBox.getChildren().addAll(backButton, forwardButton, reloadButton, field);
view = new WebView();
engine = view.getEngine();
engine.setJavaScriptEnabled(true);
engine.getLoadWorker().stateProperty().addListener(
(ov, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
tab.setText(getTitle());
//TODO setGraphic
}
});
loadData("google.com");
root = new BorderPane();
root.setPrefSize(1024, 768);
root.setTop(hBox);
root.setCenter(view);
tab.setContent(root);
return tab;
}
public void loadData(String URL) {
if(!URL.startsWith("http://")) {
URL = "http://" + URL;
}
field.setText(URL);
tab.setText(URL);
engine.load(URL);
}
private String getTitle() {
Document doc = engine.getDocument();
NodeList heads = doc.getElementsByTagName("head");
String titleText = engine.getLocation() ; // use location if page does not define a title
if (heads.getLength() > 0) {
Element head = (Element)heads.item(0);
NodeList titles = head.getElementsByTagName("title");
if (titles.getLength() > 0) {
Node title = titles.item(0);
titleText = title.getTextContent();
}
}
return titleText;
}
private String goBack() {
final WebHistory history = engine.getHistory();
ObservableList<WebHistory.Entry> entryList = history.getEntries();
int currentIndex=history.getCurrentIndex();
Platform.runLater(() -> history.go(-1));
return entryList.get(currentIndex>0?currentIndex-1:currentIndex).getUrl();
}
private String goForward() {
final WebHistory history = engine.getHistory();
ObservableList<WebHistory.Entry> entryList=history.getEntries();
int currentIndex=history.getCurrentIndex();
Platform.runLater(() -> history.go(1));
return entryList.get(currentIndex<entryList.size()-1?currentIndex+1:currentIndex).getUrl();
}
}
Remove getInstance(jBrowser) method
Make the constructor public.
Then to add a tab to a tabPane do
tabPane.getTabs().add(new JTab(jBrowser).addTab());