I have a chart. A double click on a table row opens a window in which I can edit the information of the row. Double-clicking on another line opens the corresponding window. Everything works as it should, except that each window should open only once. If it is already open, the window should return to the foreground. Unfortunately I can't see what's wrong here and would be grateful for a hint
private void loadTable() {
// I omitted the part where the table is populated.
mytable.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.isPrimaryButtonDown() && event.getClickCount() == 2) {
TableItem table_item = table_view.getSelectionModel().getSelectedItem();
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("/application/Popup.fxml"));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.setScene(scene);
MyController controller = fxmlLoader.<MyController>getController();
boolean result = controller.init(stage, table_item);
if (stage.isShowing()) {
stage.toFront();
System.out.println("Show this popup.");
} else {
if (result) {
stage.show();
System.out.println("Open this popup.");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
Try adding
stage.initModality(Modality.WINDOW_MODAL);
after
Stage stage = new Stage();
This will make the Parent stage unclickable until this stage is closed.
Related
SO, I have a JavaFX application with an already implemented Tray that needs 1 option to reopen the window/stage minimized by this GuiController function, which is called by the fxml:
`public void minimizeImageViewClick(MouseEvent mouseEvent) {
if (mouseEvent.getSource() == minimizeImageView) {
stage = (Stage) ((ImageView) mouseEvent.getSource()).getScene().getWindow();
stage.setIconified(true);
}
if(mouseEvent.getSource() == minimizePane){
stage = (Stage) ((Pane) mouseEvent.getSource()).getScene().getWindow();
stage.setIconified(true);
}
}`
There is also one to maximize, implemented by the same means:
public void maximizeImageViewClick(MouseEvent mouseEvent) {
if (mouseEvent.getSource() == maximizeImageView) {
if (ExamAlertStateController.getInstance().getWindowSizeState() == WindowSizeState.INIT) {
stage = (Stage) ((ImageView) mouseEvent.getSource()).getScene().getWindow();
stage.setMaximized(true);
update();
ExamAlertStateController.getInstance().setWindowSizeState(WindowSizeState.MAXIMIZED);
} else {
stage = (Stage) ((ImageView) mouseEvent.getSource()).getScene().getWindow();
stage.setMaximized(false);
update();
ExamAlertStateController.getInstance().setWindowSizeState(WindowSizeState.INIT);
}
}
}`
A piece of the Tray, with the Open (Abrir) option I need to implement and another which only change the screen and the state, as all the other after that:
# SpringBootApplication
public class Application {
//private final MenuItem menuItemSelectedFile;
//Stage stage;
private SystemTray systemTray;
public static final URL MULTI_LOGO = Application.class.getResource("source.png");
private Timer evaluatorTimer;
public static void main(String[] args) {
* code *
}
public Application() {
Log.i(this.getClass().getName(),"Text");
SystemTray.FORCE_GTK2=true;
SystemTray.DEBUG = true;
CacheUtil.clear();
this.systemTray = SystemTray.get();
if (systemTray == null) {
throw new RuntimeException("text!");
}
systemTray.setTooltip("text");
systemTray.setImage(MULTI_LOGO);
systemTray.setStatus("TEXT");
Menu mainMenu = systemTray.getMenu();
MenuItem openMenuItem = new MenuItem("Abrir", new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
}
});
openMenuItem.setTooltip("Abrir programa");
mainMenu.add(openMenuItem);
mainMenu.add(new Separator());
MenuItem loginMenuItem = new MenuItem("Login", new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
ExamAlertStateController.getInstance().setWindowState(WindowState.LOGIN);
}
});
loginMenuItem.setTooltip("Login Text");
mainMenu.add(loginMenuItem);
mainMenu.add(new Separator());
The stage creation in the View file:
public class eaView extends Application {
private static final long ONE_SECOND = 1000;
private static double xOffset = 0;
private static double yOffset = 0;
private boolean ignore;
private Timer updaterTimer;
#Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader();
URL urlLoadingScreen = getClass().getResource("/fxml/source.fxml");
loader.setLocation(urlLoadingScreen);
GridPane gridLoadingScreen = loader.load();
Scene scene = new Scene(gridLoadingScreen);
stage.initStyle(StageStyle.UTILITY);
stage.setOpacity(0);
stage.setHeight(0);
stage.setWidth(0);
stage.show();
Stage mainStage = new Stage();
//stage.setResizable(false);
//mainStage.setResizable(false);
mainStage.initOwner(stage);
mainStage.initStyle(StageStyle.UNDECORATED);
mainStage.setScene(scene);
mainStage.show();
So, I wasn't able to to call the maximizeImageViewClick function to it - I can by making it static, but it calls an update() method which contains a lot of FXML objects which cannot be altered, couldn't found the proper stage way of doing it (the attempts:
stage.setScene(scene);
stage.setMaxHeight(0);
stage.setMaxWidth(0);
stage.setOpacity(0);
stage.setIconified(true);
//ExamAlertView.
System.out.println("foi");
//ExamAlertView.
//System.out.println(stage.getProperties());
stage.show();
//if (ExamAlertStateController.getInstance().getWindowSizeState() == WindowSizeState.INIT) {
//stage = (Stage) ((ImageView) e.getSource()).getScene().getWindow();
//stage.setIconified(false);
//stage.setMaximized(true);
//stage.show();
//ImageView
//ExamAlertGuiController.setMinimizeImageView(ExamAlertGuiController.maximizeImageView);
System.out.println("foi2");
//ExamAlertGuiController.update();
ExamAlertStateController.getInstance().setWindowSizeState(WindowSizeState.MAXIMIZED);
/* } else {
stage = (Stage) ((ImageView) e.getSource()).getScene().getWindow();
stage.setMaximized(false);
stage.setIconified(false);
//ExamAlertGuiController.update();
ExamAlertStateController.getInstance().setWindowSizeState(WindowSizeState.INIT);
}*/
//System.out.println(stage.isIconified());
) which was only possible by making
public static Stage stage;
public static Scene scene;
in the GuiController file.
Really out of ideas here. Already did read the javafx.stage class the best I could.
Maybe I'm trying to access the wrong stage - stage UTILITY to remove taskbar button, mainStage UNDECORATED is the real deal, yet can't reach it - but I dont know....
How do I do this?
Thanks in advance.
I'm trying to open a stage by clicking a button, but before opening it, I want to check if the stage is already opened, then popup the opened stage to the front instead of opening a new one(no multi open of the same Stage).
#FXML
private void btn_Validate(ActionEvent event) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/scontrols/students/StudentManagement.fxml"));
Parent root = (Parent) loader.load();
StudentManagementController sendTo = loader.getController();
sendTo.receiveFromCamera(txtPictureName.getText());
Stage stage = new Stage();
stage.setScene(new Scene(root));
if(!stage.isShowing())
{
stage.show();}
} catch (IOException ex) {
Logger.getLogger(WebCamController.class.getName()).log(Level.SEVERE, null, ex);
}
}
You're checking !stage.isShowing() on the newly created Stage. This will never do what you want. You need to keep a reference to the other Stage and keep using that reference.
public class Controller {
private Stage otherStage;
#FXML
private void btn_Validate(ActionEvent event) {
if (otherStage == null) {
Parent root = ...;
otherStage = new Stage();
otherStage.setScene(new Scene(root));
otherStage.show();
} else if (otherStage.isShowing()) {
otherStage.toFront();
} else {
otherStage.show();
}
}
}
If you don't want to keep the Stage in memory when it's closed, then you can alter the above slightly.
public class Controller {
private Stage otherStage;
#FXML
private void btn_Validate(ActionEvent event) {
if (otherStage == null) {
Parent root = ...;
otherStage = new Stage();
otherStage.setOnHiding(we -> otherStage = null);
otherStage.setScene(new Scene(root));
otherStage.show();
} else {
otherStage.toFront();
}
}
}
You may want to store a reference to the loaded controller as well, depending on your needs.
all the questions I found around here answered how to send data from one controller to another. However, I don't know how to return another value from the second controller to the first one. Basically, send data back and forth while the first controller is still opened.
Main class:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Screen1.fxml"));
Scene scene = new Scene(loader.load());
primaryStage.setScene(scene);
primaryStage.setTitle("Screen 1");
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Screen 1 controller:
public class Screen1Controller {
#FXML
TextField textFieldScreen1;
#FXML
Button buttonScreen1;
#FXML
Label labelScreen1;
#FXML
private void initialize() {
buttonScreen1.setOnAction((event) -> {
try{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Screen2.fxml"));
Scene scene = new Scene(loader.load());
Stage stage = new Stage();
//Send data to Screen 2
Screen2Controller controller2 = loader.getController();
controller2.receiveTextFromScreen1(textFieldScreen1.getText());
stage.setTitle("Screen 2");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
Screen 2 controller:
public class Screen2Controller {
#FXML
TextField textFieldScreen2;
#FXML
Button buttonScreen2;
#FXML
Label labelScreen2;
#FXML
private void initialize() {
buttonScreen2.setOnAction((event) -> {
Stage currentStage = (Stage) buttonScreen2.getScene().getWindow();
currentStage.close();
});
}
public void receiveTextFromScreen1(String stringScreen1){
labelScreen2.setText(stringScreen1);
}
}
I have tried to use the same strategy (create a method in Screen1Controller and instantiate Screen1Controller in the second controller) with the following code but it didn't work.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Screen2.fxml"));
//Send data to Screen 1
Screen1Controller controller1 = loader.getController();
controller1.receiveTextFromScreen2(textFieldScreen2.getText());
Also, related to this matter (I'm assuming) a second question: how would I update the second view while I change the TextField in controller 1 without creating a new window everytime I click the button (i.e using the same second view instance)?
Any help will be greatly appreciated!
Create a constructor
public Screen1Controller {
Arrow the parameters
}
and when you call the controller, you parse the parameter:
void on2players(ActionEvent event) throws IOException {
client.out.println("ACTION NEWGAME 2 4");
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/boardscreen.fxml"));
loader.setController(new Screen1Controller(parameter);
Parent root = loader.load();
Scene scene= new Scene(root);
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.setScene(scene);
window.show();
}
public class Screen1Controller implements Initializable {
public Screen1Controller() {
//parameters
}
#Override
public void initialize(URL location, ResourceBundle resources) {
switch(numberOfPlayers){
case 2:
//TODO...creating board for 2 players
case 3:
//TODO creatinf board for 3 players
}
}
If you do this, you force the fxml loader to call the controller. NOTE: You should get the controller inside .FXML
User clicks on a button that opens a popup second scene that allows the user to select some values, then close and pass the selection to the first scene.
First Controller
Set<String> set;
public void initialize(URL url, ResourceBundle rb){
set = new TreeSet<String>():
}
#FXML
public Set<String> addValue (MouseEvent e) throws IOException {
Stage stage = new Stage ();
root = FXMLoader.load(getClass).getResources(2ndFXML.fxml);
stage.initModality(Modality.APPLICATION_MODAL);
stage.iniOwner(clickedButton.getScene().getWindow();
stage.showAndWait():
return set;
}
2nd Controller
#FXML
public void addSelection (MouseEvent e) throws IOException {
if (event.getSource() == button){
stage = (Stage) button.getScene().getWindow();
set.addAll(listSelection)
stage.close
}
But the value never makes it back to the first controller.
Since you're using showAndWait(), all you need to do is define an accessor method for the data in the second controller:
public class SecondController {
private final Set<String> selectedData = new TreeSet<>();
public Set<String> getSelectedData() {
return selectedData ;
}
#FXML
private void addSelection (MouseEvent e) {
// it almost never makes sense to define an event handler on a button, btw
// and it rarely makes sense to test the source of the event
if (event.getSource() == button){
stage = (Stage) button.getScene().getWindow();
selectedData.addAll(listSelection)
stage.close();
}
}
}
Then retrieve it in the first controller when the window has been closed:
#FXML
public void addValue(MouseEvent e) throws IOException {
Stage stage = new Stage ();
FXMLLoader loader = new FXMLLoader(getClass().getResource(2ndFXML.fxml));
Parent root = loader.load();
// I guess you forgot this line????
stage.setScene(new Scene(root));
stage.initModality(Modality.APPLICATION_MODAL);
stage.iniOwner(clickedButton.getScene().getWindow();
stage.showAndWait();
SecondController secondController = loader.getController();
Set<String> selectedData = secondController.getSelectedData();
// do whatever you need to do with the data...
}
I am fairly new to JAVAFX so please bear with me. Any help is greatly appreciated. Firstly, i have a Main app that loads addItems.fxml and addItemsController.
public class UncookedApp extends Application {
private Stage stage;
#Override
public void start(Stage primaryStage) {
stage = primaryStage;
try {
FXMLLoader loader=new FXMLLoader();
loader.setLocation(getClass().getResource("/uncooked/view/addItems.fxml"));
AnchorPane root=loader.load();
addItemsController itemsCtrl=loader.getController();
itemsCtrl.setMainApp(this);
Scene scene=new Scene(root,1024,768);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e){
e.printStackTrace();
}
}
public Stage getStage() {
return stage;
}
public static void main(String[] args) {
launch(args);
}
}
This is part of the addItemsController:
private UncookedApp mainApp;
public UncookedApp getMainApp() {
return mainApp;
}
public void setMainApp(UncookedApp mainApp) {
this.mainApp = mainApp;
}
public void toMeat(ActionEvent event) {
Stage stage1=mainApp.getStage();
try {
FXMLLoader loader=new FXMLLoader();
loader.setLocation(getClass().getResource("/uncooked/view/addMeat.fxml"));
Parent root=loader.load();
addMeatCtrl itemsCtrl=loader.getController();
// itemsCtrl.setMainApp(this);
Scene scene=new Scene(root,1024,768);
stage1.setScene(scene);
stage1.show();
} catch(Exception e){
e.printStackTrace();
}
}
The addItemsController will load a different page, addMeat. I got that to work but when I try to go back from addMeat to addItems with a button handle, it doesn't work. Is it something to do with retrieving the mainApp's stage? How can I solve this?
This is what I've tried.
public void handleBackFromMeat(ActionEvent event) {
try{
Stage stage=mainApp.getStage();
FXMLLoader loader=new FXMLLoader();
loader.setLocation(getClass().getResource("/uncooked/view/addItems.fxml"));
Parent root=loader.load();
addItemsController itemsCtrl=loader.getController();
Scene scene=new Scene(root,1024,768);
stage.setScene(scene);
stage.show();
}catch (Exception e){
e.printStackTrace();
}
}
I also had posted a similar question and then i went ahead with my way
I need to create a back button functionality in javafx?
What you can do as i did for my application was make two static list at the start of the application and then fill it with the Stage and the Fxml page name if you are using fxml and then have a central back button method on each page to move the previous page by iterating on the last item added to the list .
Two static lists in the main class
public static List<Stage>stageval = new ArrayList<Stage>();
public static List<String>fxmlval = new ArrayList<String>();
When ever i switch my fxml view i added the stage and the fxml file name to their respective lists.
fxmlval.add("Instance.fxml");
stage = (Stage)validate.getScene().getWindow();
stageval.add((Stage) delete.getScene().getWindow());
And a central back button method when ever the user clicked the back button i iterated to last item of both the lists and then after changing the stage deleted the values from the list .
public class BackButton {
public void back(String instance,Stage stage) throws IOException{
Parent parent = FXMLLoader.load(getClass().getResource(instance));
Scene scene = new Scene(parent);
scene.getStylesheets().add("/css/Style.css");
stage.setResizable(false);
stage.setScene(scene);
stage.show();
}
}
#FXML
public void back() throws IOException {
BackButton bb = new BackButton();
bb.back(fxmlval.get(fxmlval.size() - 1),
stageval.get(stageval.size() - 1));
fxmlval.remove(fxmlval.size() - 1);
stageval.remove(stageval.size() - 1);
}
Hope this helps its a work around but the solution works.