0

I'm trying to implement a TableView containing 2 columns. Each table cell contains a different player's data. Once a player is clicked, a custom FlowPane containing data corresponding to the clicked player is shown below the row that the player is in. Using James_D's code that answered my previous question:

JavaFx - String and FlowPane (row?) within tableView?

I've managed to make a FlowPane appear at the required spot using a custom TableRowFactory(skin):

Before:

Before clicking

After clicking a player (bg player 0 or 1, doesn't matter - entire row is selected):

After clicking

However, while it is true that I need the FlowPane visually below the selected row, the FlowPane depends on the actual individual cell that was clicked - not the row that was clicked. Specifically, if I click a cell in a row, causing the FlowPane to show up, and then click another cell in the same row, the FlowPane should change its data to reflect the newest click. If the same player is clicked again, the FlowPane should disappear. Furthermore, selecting a cell should not select the entire row and the FlowPane should not be colored (blue or any other color) because of the selecting...But the Player's name should be!

I'm having a hard time implementing this. I think I need:

table.getSelectionModel().setCellSelectionEnabled(true);

This allows for individual cell selection. But enabling that disables the listeners of the TableRowSkin, rendering the entire code pointless. I tried a workaround: The below code can get the required row/column TablePosition by listening to the changes to the list of selectedCells. Great - but I don't know how to proceed. What is the point of row/column positions if I can't then access the TableCell's flowpane, or even the Cell itself? The only thing I seem to be able to access is the (property of the) String that the cell contains. That's useful, but I doubt I'm supposed do getItems() and then iterate through them to see which underlying Player was actually selected, to then update the flowPane somehow.

ObservableList<TablePosition> selectedCells = table.getSelectionModel().getSelectedCells();
        selectedCells.addListener((ListChangeListener.Change<? extends TablePosition> change) ->
        {
            if (selectedCells.size() > 0)
            {
                TablePosition selectedCell = selectedCells.get(0);
                TableColumn column = selectedCell.getTableColumn();
                int rowIndex = selectedCell.getRow();

                //now adjust row/flowpane somehow
            }
        }); 

In pseudocode, all I want to do is:

Cell playerClicked = mouseEvent.clickedCell();
int i = mouseEvent.getChildren().getClickedIndex();
String name = playerClicked.getName();

PlayerData data = dataset.getItem(name);
FlowPane flow = new CustomFlowPane(data);

if(i % 2 == 0) //even table position: FlowPane should show up after the second column's position
    table.getChildren().add(i+2, flow);
else
    table.getChildren().add(i+1,flow);

Can anybody point me in the right direction? Please see (at the top) the link to James_D's code. If you can help me get it working in there, that would be amazing :)

fabian
  • 80,457
  • 12
  • 86
  • 114
Simon
  • 67
  • 6
  • Are you sure a table view is the control you want to use here? It sounds like you aren't really using any of its actual functionality and you're trying to do things it's not designed to do. Maybe you just want, say, a `GridPane` with every other row empty unless you are showing the "additional content" in a flow pane inside it. – James_D Mar 13 '18 at 19:20
  • The reason I began looking at the ListView / TableView is that I originally had 2000 TextFields and an injectFlowPane() function in a ScrollPane, which was working wonderfully except it was using ~1.5 GB of ram memory :-) Which is problematic since I want it to scale - real-world functionality might require loading as much as 50k or more players, and therefore textFields. I do believe I need some kind of dynamic control thingy. Can a GridPane handle something like that? Not familiar with it yet. – Simon Mar 13 '18 at 20:10
  • 1
    Ah, yes. So then you are definitely using the functionality of a `TableView` :). This probably gets a bit tricky - the basic approach I think is to create some observable property which represents either the selected player, or the index of the selected player, or the index of the row containing the selected player. Then modify the previous solution to observe that property instead of the table row's own `selectedProperty()`. Finally, you probably want to use a cell factory which installs a mouse listener on the cell it creates, and in that mouse listener update the property you defined. – James_D Mar 13 '18 at 20:23

0 Answers0