I have the following controller that is instantiated many times on my gui. The reason is beacause it has a tableview that gets filled with different kind of data. Looks like this
class Controller {
#FXML
TableView<Map<String, String> myTable;
private Manager manager;
//Each TableView has different ammount of columns with different names that get dynamically added to the table view using this function
public void setUpColumns(List<TableColumn<Map<String, String>, String>> columns){
myTable.getColumns().addAll(columns);
addContextMenuToColumnHeaders();
}
private addContextMenuToColumnHeaders(){
for (TableColumn<Map<String, String>, ?> tc : myTable.getColumns()){
ContextMenu addToGraphContextMenu = createAddToGraphContextMenu(tc);
tc.setContextMenu(addToGraphContextMenu);
}
}
private ContextMenu createAddToGraphContextMenu(TableColumn<Map<String, String> String> tc){
for (MangerHandledObject mHO : manager.getHandledObjects()){
MenuItem menuItem = new MenuItem(mHO.getName());
menuItem.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event){
//I want each menu item to have access to the column that is added to get the name of the column. Even after dynamically adding new menuItems
manager.callMethod(tc.getName());
}
});
}
}
}
The manager handled objects are not static. So the are added and deleted from the list that the manager keeps. I tried this
contextMenu.setOnShowing(......)
and before showing it will always check for the list from the manager and re-make the context menu items. But the problems is that when this executes I don't have access to the columns anymore. Is there any way to bypass this? Should I implement my own context menu to have a field of the column Name?
It worked. But I had to add at least one dummy MenuItem on my context menu in order for it to appear.
Related
I am trying to display a scene with a TableView where a user can click to select teams, which are then stored in an ObservableList. The selected teams should be highlighted and clicking a selected team should unselect them. Selecting multiple teams should not require holding down ctrl etc. The problem that I'm having is actually displaying the selected teams. I'm very confused with JavaFX's SelectionModel and FocusModel. I'd also need a functionality where if the user opens the view again to make changes to the selection, the selected teams should appear highlighted again.
Here's a sample of the code I've been working with. So far the selection works but the UI doesn't reflect the actual selection. In the image [1] is shown what I'm trying to achieve, the selection has been done holding ctrl and clicking the items. Again that doesn't reflect the actual selection and having to hold down keys to select multiple items is not viable in this case.
//for the sake of simplicity the Team objects are set here as a placeholder instead of fetching from the database
private Team[] teams = new Team[] {new Team("team1", 0), new Team("team2", 1), new Team("team3", 2), new Team("team4", 3)
private ObservableList<Team> selectedTeams = FXCollections.observableArrayList();
#FXML
private TableView<Team> teamsTableView;
#FXML
private TableColumn<Team, String> teamNameColumn;
#FXML
private TableColumn<Team, Integer> teamIdColumn;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
teamNameColumn.setCellValueFactory(new PropertyValueFactory<Team, String>("teamName"));
teamIdColumn.setCellValueFactory(new PropertyValueFactory<Team, Integer>("id"));
teamsTableView.setItems(teams);
teamsTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
teamsTableView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Team>() {
#Override
public void changed(ObservableValue<? extends Team> observable, Team oldValue, Team newValue) {
if(selectedTeams.contains(newValue)) {
selectedTeams.remove(newValue);
} else {
selectedTeams.add(newValue);
}
}
});
}
What approach should I try to take? Could the SelectionModel reference an ObservableList somehow?
I've been working on this for over two weeks now and I'm completely stumped. This is clearly beyond my abilities and some hand-holding might be necessary.
I am building an application using JavaFX. What I am trying to do is generate a message according to the user input values. So there are one text-field and one combo-box and one check-box per row and there are many rows like the following.
Let's say I will generate three different messages according to the user values. So I need to check whether those fields are empty or not and check each field's value to generate a specific message. Checking fields are okay for just three rows like the above. But I have 10 fields. So I have to check each and generate or append my own message. And also if the user checked the check-box need to group all checked row values. So what I am asking is there any good way (best practice) to achieve what I need or an easy one also? I have tried with HashMap and ArrayList. But those are not working for this.
Really appreciate it if anybody can help me. Thanks in advance.
I would probably recommend a custom node that you create on your own like below. This example is not supposed to have the same functionality as your application but just to show how to create and use custom nodes. I kept your idea in mind when creating this example it has your textfield combobox and checkbox and they are a little easier to manage. Give it a run and let me know if you have any questions
public class Main extends Application {
#Override
public void start(Stage stage) {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
ArrayList<String> itemList = new ArrayList<>(Arrays.asList("Dog", "Cat", "Turkey"));
ArrayList<HBoxRow> hBoxRowArrayList = new ArrayList<>();
for (int i = 0; i<3; i++) {
HBoxRow hBoxRow = new HBoxRow();
hBoxRow.setComboBoxValues(FXCollections.observableList(itemList));
hBoxRowArrayList.add(hBoxRow);
vBox.getChildren().add(hBoxRow.gethBox());
}
Button printTextfieldsButton = new Button("Print Textfields");
printTextfieldsButton.setOnAction(event -> {
for (HBoxRow hBoxRow : hBoxRowArrayList) {
System.out.println("hBoxRow.getTextFieldInput() = " + hBoxRow.getTextFieldInput());
}
});
vBox.getChildren().add(printTextfieldsButton);
stage.setScene(new Scene(vBox));
stage.show();
}
//Below is the custom Node
public class HBoxRow {
HBox hBox = new HBox();
ComboBox<String> comboBox = new ComboBox<>();
TextField textField = new TextField();
CheckBox checkBox = new CheckBox();
public HBoxRow(){
hBox.setAlignment(Pos.CENTER);
textField.setPrefWidth(150);
comboBox.setPrefWidth(150);
checkBox.setOnAction(event -> {
textField.setDisable(!textField.isDisabled());
comboBox.setDisable(!comboBox.isDisabled());
});
hBox.getChildren().addAll(checkBox, textField, comboBox);
}
public void setComboBoxValues(ObservableList observableList) {
comboBox.setItems(observableList);
}
public HBox gethBox(){
return hBox;
}
public String getTextFieldInput(){
return textField.getText();
}
}
}
I have a group of ToggleButtons that need to find out their id. Currently I can check the id in the getSource() and toString() method like this:
#FXML
public void btnCell(ActionEvent actionEvent) {
System.out.println(actionEvent.getSource());
}
Prints: ToggleButton[id=btn00, styleClass=toggle-button]''
Can I extract the id without relying on some shady substring busniess on that string?
hope it helps:
import javafx.scene.Node;
....
#FXML
public void btnCell(ActionEvent actionEvent) {
final Node source = (Node) actionEvent.getSource();
String id = source.getId();
Scene scene = source.getScene();
scene.lookup("#"+id).getStyleClass() ;
}
In case this is still relevant, I use a whole bunch of programmatically generated buttons (representing menu items in a POS application), identified through MyButton.setUserData(MyProdID), which is loaded from the product IDs in a database table. Then you can get that with MyButton.getUserData() in the ActionEvent handler.
My TableView is not updating, do i need a listener ?
(m is my Model)
#FXML
private TableView<Mitarbeiter> mitarbeiter;
ObservableList<Mitarbeiter> data =
FXCollections.observableArrayList(m.getMitarbeiterListe()
);
mitarbeiter.setItems(data);
public ArrayList getMitarbeiterListe(){
return mitarbeiterliste;
}
In a new Stage i add some Mitarbeiter to the List in my Model
m.addMitarbeiterToList(mitarbeiter)
public void addMitarbeiterToList(Mitarbeiter mitarbeiter){
mitarbeiterliste.add(mitarbeiter);
}
But the TableView in the other Stage is not updating the new data.
In the end, is the ObservableList not pointed to the ArrayList from the Model ?
Instead of adding items to mitarbeiterliste (which is an ArrayList, and is not observable), add them to data, which is the ObservableList holding the items for the table. The TableView observes this list and automatically updates the view when the list contents changes.
The context of your code snippets is not very clear, but you would do something like
public ArrayList getMitarbeiterListe(){
return data;
}
or instead of
mitarbeiterliste.add(mitarbeiter);
do
data.add(mitarbeiter);
I'm trying to set a variable value when a MenuItem i chosen in a MenuButton object.
I've tried to search for this but I've came up empty handed.
Here's the code to set the MenuItems:
private ObservableList<MenuItem> templateMenuItems = FXCollections.observableArrayList();
#FXML private MenuButton menu = new MenuButton();
#FXML
protected void getTemplates() throws IOException {
CaspReturn tls = this.socket.runCmd(new Tls(""));
String tlsList = tls.getResponse();
String[] tlsListSplitt = tlsList.split("\\n");
for (int i = 0; i < tlsListSplitt.length; i++) {
String[] tlsLine = tlsListSplitt[i].split("\"");
this.templateMenuItems.add(new MenuItem(tlsLine[1]));
}
this.menu.getItems().setAll(this.templateMenuItems);
}
I'm not sure how to write the code to get the text from a menuItem or which field in scenebuilder the method should be in.
It's not clear what your asking, but I'll assume that you want to know the text of a menu item when it is clicked. To do that, you need to add an event handler onto the menu item. The following is clipped from the JavaDoc for ContextMenu:
MenuItem item1 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("About");
}
});
You can get the event source, cast in to MenuItem and then get the text from that.
There's a real problem with your code the way it's written, though. You have calls to an external database in getTemplates, and as it's implemented as an #FXML element that almost guarantees that it'll be run on the FXAT, which is really, really bad.
I'd refactor that so that the database access is in a Task, and then the MenuItem creation is a handler for the onSucceeded event of the Task. Then you need instantiate a ContextMenu and install the MenuItem's on it in that event handler.
The getTemplates() method should be called as the onAction event for the button.