Selecting multiple objects and displaying selection in JavaFX TableView - javafx

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.

Related

How to Generate Message According to Values in Multiple Fields?

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();
}
}
}

Getting id from a ActionEvent in JavaFX

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.

javafx/ fxml - Switching Screens/ add a new Tab in controller

Firstly, sorry for my English. I hope, you unterstand it.
Last Month I started developing a little programm with FXML/ JavaFX.
I have two screens, and I'm switching between them. This is not the problem.
The problem is: On one Screen i have a listview, where i can choose an item. When i have chosen an item, i want to open a new tab on the other screen with the content of the item. Therefore, i have to click on a button.
When i have chosen an item, i can print out the selected item, but how do I open a new tab on the other screen. Both Screens a two different FXML and are activited from the controller. How can I add a Tab, although loading fxml?
public class Controller{
#FXML
private ListView<String> lv;
#FXML
private Button check;
#FXML
public void projectview (Event e3) throws Exception{
Stage stage = null;
Parent root = null;
if(e3.getSource()==check){
//Check is the declaration for the Button on the screen with the listview
String projectview= lv.getSelectionModel().getSelectedItem();
stage = (Stage) check.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("FXML1.fxml"));
//Here I want to add a tab in FXML1.fxml
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
}
If something is missing or not clear, please ask. I read other similar questions, but i don't know, what to do.
Thanks for help

Dynamically Adding context menu items to tableview columns

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.

JavaFX FXML menuItem action

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.

Resources