JavaFX Initialize function and things in there - java

Is it a proper way to locate ContextMenu, setCellValueFactory, setRowFactory, etc. in initialize function?
public void initialize() {
ContextMenu contextMenu = new ContextMenu();
MenuItem cut = new MenuItem("Cut");
MenuItem copy = new MenuItem("Copy");
MenuItem paste = new MenuItem("Paste");
contextMenu.getItems().addAll(cut, copy, paste);
empId.setCellValueFactory(cellData -> cellData.getValue().employeeIdProperty().asObject());
empName.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
empLastName.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
//Show info when double clicked
employeeTable.setRowFactory(tv -> {
TableRow<Employee> row = new TableRow<>();
row.setOnMouseClicked(event -> {
if(!row.isEmpty() && event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2) {
Employee emp = row.getItem();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getClassLoader().getResource("view/ViewEmployeeView.fxml"));
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
ViewEmployeeController viewEmployee = loader.getController();
viewEmployee.setText(emp.getFirstName(), emp.getLastName(), emp.getEmail(), emp.getPhoneNumber(), String.valueOf(emp.getSalary()), String.valueOf(emp.getManagerId()), String.valueOf(emp.getDepartmentId()));
Parent root = loader.getRoot();
Stage stage = new Stage();
stage.setTitle("View employee");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(addBtn.getScene().getWindow());
stage.setScene(new Scene(root));
stage.show();
stage.setResizable(false);
} else if (event.getButton() == MouseButton.SECONDARY) {
row.setContextMenu(contextMenu);
}
});
return row;
});
I don't know If I clarified my thoughts right but here is the example to understand me better:
I create FXML with different buttons(with OnClicked methods), fields, labels, etc. Then I generate FXML controller where OnClicked methods are generated as well. But what If I need to add additional things as ContextMenu, rowFactory, make dynamic columns for TableView or add setOnAction event, let's say for MenuItem in ContextMenu. Where should I write those things? Is initialize function acceptable for this need?

Related

JavaFX - Deselect text in TextField when open new stage

I have designed a simple form with a TextField and a Button.
When the stage is created, with the scene containing the form, the TextField must be preloaded with a character. The problem is that, when the form shows up, the character is selected, as shown in the image.
I tried textfield.deselect() or textfield.positionCaret(1) (or both) but nothing has changed.
I don't want to remove the focus on the textfield, but deselect the text and move the caret at the end (so that if the user write something, the first character will not be overwritten).
This is the code I wrote:
try {
Stage primaryStage = new Stage();
FXMLLoader loader = new FXMLLoader();
Pane root = loader.load(getClass().getResource("/resources/view/quick-search.fxml").openStream());
QuickSearchCtrl quickSearchCtrl = (QuickSearchCtrl) loader.getController();
quickSearchCtrl.text_tf.setText(text);
quickSearchCtrl.text_tf.deselect();
primaryStage.setTitle("");
primaryStage.setScene(new Scene(root, 230, 54));
primaryStage.show();
primaryStage.setResizable(false);
} catch (IOException e) {
e.printStackTrace();
}
This is an evil crutch, but this work.
quickSearchCtrl.text_tf.setText(text);
deselect(quickSearchCtrl.text_tf);
private void deselect(TextField textField) {
Platform.runLater(() -> {
if (textField.getText().length() > 0 &&
textField.selectionProperty().get().getEnd() == 0) {
deselect(textField);
}else{
textField.selectEnd();
textField.deselect();
}
});
}

Change scene within the same window

How can I change the scene within the same window, rather than it opening a new window entirely.
Below is where the selectable options are added to a choicebox, with a listener at the end to "observe" when a selection is made, which, when clicked, changes the scene.
private void formulaOption2(){
list2.removeAll(list2);
String a = "Current Ratio";
String b = "Working Capital Ratio";
String c = "Debt to Equity Ratio";
String d = "Gross Profit Margin";
list2.addAll(a,b,c,d);
ChoiceBox2.getItems().addAll(list2);
//A LISTENER TO OBSERVE WHEN USER SELECTS ITEM
ChoiceBox2.getSelectionModel().selectedItemProperty().addListener( (v, oldValue, newValue) -> {
try {
comboSelect2();
} catch (IOException ex) {
Logger.getLogger(Tab1FXMLController.class.getName()).log(Level.SEVERE, null, ex);
}
} );
}
Below is the code that loads the FXML file:
public void comboSelect2() throws IOException {
if("Current Ratio".equals(ChoiceBox2.getSelectionModel().getSelectedItem())){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Tab2FXML.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Current Ratio");
stage.setScene(new Scene(root1));
stage.show();
}
}
Just replace the root of the current scene with the new root you want:
public void comboSelect2() throws IOException {
if("Current Ratio".equals(ChoiceBox2.getSelectionModel().getSelectedItem())){
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Tab2FXML.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
ChoiceBox2.getScene().setRoot(root1);
}
}

Communicating with an FXML Controller that's already open

I have searched again and again on this to no avail. I have a JavaFX FXML window which is connected to a Controller; this window is open. Clicking a button on the window triggers the opening of another FXML file, linked to its respective controller.
The second window (optionsUI.fxml and optionsController) has a few radio buttons. When one is clicked, I want the location of an image/button to change in the mainUI window. How do I go about doing that?
mainController:
public void assetPressed(MouseEvent event) {
//Get the source of Handler
HUDButton button = (HUDButton) event.getSource();
//Check if an asset is already selected
//----do a thing
//Open stage
openStage(currentAsset);
} else {
//if the current asset selected and the new asset clicked are the same
//----do something
closeStage();
}
//if the current asset selected and the new asset clicked are different
else {
//----do something else
assetIsSelected = true;
openStage(currentAsset);
}
}
}
//opening optionsUI.fxml
public void openStage(Asset asset) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("optionsUI.fxml"));
Parent root = null;
try {
root = fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
optionsController controller = fxmlLoader.getController();
Scene scene = new Scene(root, 300, 450);
stage.setScene(scene);
if (alreadyExecuted == false) {
stage.initStyle(StageStyle.UNDECORATED);
stage.initOwner(stageControls); //Making the mainUI the owner of the optionsUI
stage.setTitle("HUDEdit Version 3.0.0");
alreadyExecuted = true;
}
The main issue I am having is adding an event handler on the radio buttons which will change a property of the Button that was pressed (currentButton). I searched on this issue, but what I got was what I have already done: to open a new stage with the new values present in the other FXML file.
You can do something like this in your OptionsController (I am going to rename things to conform to standard naming conventions, btw.)
The basic idea here is just to expose a property representing what the user has selected via the radio buttons.
public class OptionsController {
#FXML
private RadioButton radioButton1 ;
#FXML
private RadioButton radioButton2 ;
private SomeType someValue1 = new SomeType();
private SomeType someValue2 = new SomeType();
private final ReadOnlyObjectWrapper<SomeType> selectedThing = new ReadOnlyObjectWrapper<>();
public ReadOnlyObjectProperty<SomeType> selectedThingProperty() {
return selectedThing.getReadOnlyProperty() ;
}
public final SomeType getSelectedThing() {
return selectedThingProperty().get();
}
public void initialize() {
radioButton1.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
selectedThing.set(someValue1);
}
});
radioButton2.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
selectedThing.set(someValue2);
}
});
}
// ...
}
And now when you load Options.fxml you can just observe that property and do whatever you need when it's value changes:
public void openStage(Asset asset) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("optionsUI.fxml"));
Parent root = null;
try {
root = fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
OptionsController controller = fxmlLoader.getController();
controller.selectedThingProperty().addListener((obs, oldSelection, newSelection) -> {
// do whatever you need with newSelection....
});
// etc...
}

How to add a button to another class

I have a class called Restaurant, that has an FXML file, in that class, I have a button that when pressed opens another window called tables, that also has an FXML file, I have a minimize button in tables window.
What I want is when I press the minimize button in table, a new button will be added to the Restaurant window.
But I'm getting a null exception.
Can someone help me solve this.
This is the code for my minimize button:
#FXML
public void minimiza(ActionEvent event) {
Button Tables = new Button("Mesas");
try {
Stage mesa = (Stage) ((Button) event.getSource()).getScene().getWindow();
mesa.setIconified(true);
FXMLLoader loader = new FXMLLoader();
RestauranteController controle = loader.getController();
controle.adicionaBotao(Tables);
} catch (Exception e) {
System.out.println("Not working " + e.getMessage());
}
}
It's probably better to just listen to the iconified property of the Stage from the Restaurant class. If the minimized state does not match the iconified state, you could create this property in the controller for the tables window yourself.
private int windowCount;
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Show new Window");
VBox buttonContainer = new VBox(btn);
btn.setOnAction((ActionEvent event) -> {
// create new window
windowCount++;
Label label = new Label("Window No " + windowCount);
Stage stage = new Stage();
Scene scene = new Scene(label);
stage.setScene(scene);
// button for restoring from main scene
Button restoreButton = new Button("Restore Window " + windowCount);
// restore window on button click
restoreButton.setOnAction(evt -> {
stage.setIconified(false);
});
// we rely on the minimize button of the stage here
// listen to the iconified state to add/remove button form main window
stage.iconifiedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
buttonContainer.getChildren().add(restoreButton);
} else {
buttonContainer.getChildren().remove(restoreButton);
}
});
stage.show();
});
Scene scene = new Scene(buttonContainer, 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
BTW: Note that without loading a fxml, FXMLLoader will never create a controller instance, let alone without the fxml being specified. Furthermore under no circumstances would it return the same controller instance as the one used with your Restaurant window.

How to know caret coordinates (not position) in JavaFX?

I would like to draw autocomplete-like drop-down box near caret in JavaFX controls like TextField and TextArea.
Is it possible to know double numeric coordinates of the caret in node coordinate system?
You can use the inputMethodRequests property to retrieve the position. You can specify a index relative to the start of the selection to get the screen coordinates for the char.
private static ContextMenu createMenu(String... text) {
ContextMenu menu = new ContextMenu();
EventHandler<ActionEvent> handler = evt -> {
TextInputControl control = (TextInputControl) menu.getUserData();
String t = ((MenuItem) evt.getSource()).getText();
control.replaceSelection(t);
};
for (String s : text) {
MenuItem item = new MenuItem(s);
item.setOnAction(handler);
menu.getItems().add(item);
}
return menu;
}
#Override
public void start(Stage primaryStage) {
ContextMenu menu = createMenu("Hello World", "42", "foo", "bar");
TextArea textArea = new TextArea();
TextField textField = new TextField();
VBox root = new VBox(textArea, textField);
root.setPadding(new Insets(10));
EventHandler<KeyEvent> handler = evt -> {
if (evt.isControlDown() && evt.getCode() == KeyCode.SPACE) {
evt.consume();
TextInputControl control = (TextInputControl) evt.getSource();
Point2D pos = control.getInputMethodRequests().getTextLocation(0);
menu.setUserData(control);
menu.show(control, pos.getX(), pos.getY());
menu.requestFocus();
}
};
textArea.addEventFilter(KeyEvent.KEY_PRESSED, handler);
textField.addEventFilter(KeyEvent.KEY_PRESSED, handler);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Categories

Resources