JavaFX 9 - inserting flowpane below row depending on clicked tablecell, part 2 - javafx

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:
After clicking a player (bg player 0 or 1, doesn't matter - entire row is selected):
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 :)

Related

Check whether there are no tabs in TabPane on close JAVAFX

I tried a few methods:
tabPane.getSelectionModel().selectedItemProperty().addListener((e, o, n)
if (tabPane.getTabs().isEmpty()) someButton.setDisable(false);
and this when creating the tab:
tab.setOnCloseRequest(e ->
if (tabPane.getTabs().isEmpty()) someButton.setDisable(false);
But both are not working. The second method is definitly wrong as it is checking if there are tabs before actually closing the tab. Any solutions? Many thanks
Create isNotEmpty BooleanBinding on TabPane ObservableList<Tab>.
TabPane tp = new TabPane(new Tab("A"),new Tab("B"));
final BooleanBinding empty = Bindings.isNotEmpty(tp.getTabs());
Button someButton = new Button();
someButton.disableProperty().bind(empty);
I'm not sure if the below is what you want, but you can check that the size of the matched tab list in the tabpane <= 1 rather than empty.
tab.setOnCloseRequest(event -> {
TabPane tabPane = tab.getTabPane();
if (tabPane.getTabs().size() <= 1) {
// don't allow the last tab to be closed.
event.consume();
return;
}
});
Consuming the close request will prevent closure, but you could do other work in that event as well or instead (such as manipulating the disable property of your button) if you wish.
Usually button disable properties are well controlled via a binding, so perhaps something like MBec's solution might be a good idea in that case if that is all you need to accomplish.

tornadofx EventBus expand table row using tableview object

Background:
Suppose I have multiple fragments of a single table in a view, each with a rowExpander.
Expected Behaviour:
If in one table fragment I expand a row, other fragments same indexed row should get expanded. Same for collapse
My Progress:
Sample Fragment:
tableview(dataset) {
column("First Name", Person::firstNameProperty)
column("Last Name", Person::lastNameProperty)
rowExpander(true) {
selectedData.item?.apply {
fire(ExpandDataEvent(dataset.indexOf(this)))
}
column("Mobile Nos.", Person::mobileNumProperty)
column("Email Ids", Person::emailIdProperty)
}
bindSelected(selectedData)
subscribe<ExpandDataEvent> { event ->
selectionModel.select(event.index)
}
}
Event Class:
class ExpandDataEvent(val index: Int) : FXEvent()
What I understand from "subscribe" is that it gets called when an event is fired (currently I am firing the event whenever the user expands the row by either double-click/clicking the plus sign); and since the subscribe is placed inside tableview, it gets called for all the table fragments present (which is what I want). But in the subscribe method I am doing a selectionModel.select(event.index) which only selects the corresponding index row. I want to expand the row (preferably by using the selectionModel)
Question 2:
Is it possible to remove the plus sign column? For rowExpand, if I have set expandOnDoubleClick to true, I dont want the plus sign column in my tableview.
The rowExpander builder returns the actual ExpanderColumn which is basically a normal TableColumn. Save a reference to the expander so that you can operate on it later:
val expander = rowExpander(true) { ... }
Directly below, you can now hide the expander column:
expander.isVisible = false
Now it's easy to toggle the expanded state of a specific row from the event subscriber as well:
subscribe<ExpandDataEvent> { event ->
expander.toggleExpanded(event.index)
selectionModel.select(event.index)
}
You might want to double check that you don't toggle the expander for the tableview that fired the event, so consider including the event source in your event and discriminate on that in the subscriber.
I will investigate if we can add a visible boolean parameter to the rowExpander builder function so you don't need to call isVisible manually :)

Disabling a row in a DOJO / Gridx grid

I have a grid I created in Gridx which lists a bunch of users. Upon clicking a ROW in the grid (any part of that row), a dialog pops up and shows additional information about that user and actions that can be done for that user (disable user, ignore user, etc.) - when one of these options is selected from the pop up, I want to DISABLE that row. The logic for getting the row, etc. I can take care of, but I can't figure out how to make a grid row actually "appear" disabled and how to make that row no longer clickable.
Is there a simple way to do this? If you aren't familiar with gridx, solutions that apply to EnhancedGrids or other Dojo grids are also appreciated.
Alright now that I have a little more information here is a solution:
Keep a list of all the rows you have disabled so far either inside the Grid widget or in its parent code. Then on the onRowClick listener I would write code like this:
on(grid, "onRowClick", function(e) {
if(disabledRows[rowIndex]) {
return;
}
// Do whatever pop up stuff you want and after
// a user selects the value, you can "disable"
// your row afterwards by adding it to the disabled
// list so that it can no longer be clicked on.
var rowIndex = e.rowIndex;
disabledRows[rowIndex] = true;
// This is just some random class I made up but
// you can use css to stylize the row however you want
var rowNode = e.rowNode;
domClass.add(rowNode, "disabled");
});
Note that domClass is what I named "dojo/dom-class". Hope this helps!
This is perhaps not exactly what you are seaching for:
If you want to hide one or more rows by your own filterfunction you could just add to these rows in the DOM your own class for nodisplay. Here I show you a function for display only those rows which have in a choiceable field/column a value inside your filterlist.
function hideRowFilter(gridId, fieldName, filterList)
{
var store = gridId.store;
var rowId;
store.query(function(object){
rowId = gridId.row(object.id,true).node();
if (filterList.indexOf(object[fieldName]) == -1)
domClass.add(rowId, "noDisplay"); // anzeigen
else
domClass.remove(rowId, "noDisplay"); // verstecken
});
}
CSS:
.noDisplay { display: none; }
So I can for example display only the entries with a myState of 3 or 4 with this call:
hideRowFilter(gridId, 'myState', [3, 4]);
Note that domClass is what I named "dojo/dom-class"

Showing a Hidden QTableView Column

I'm trying to do something that seems like it should be very simple, but the more I look into it I wonder if it's a Qt bug.
So, I have a QTableView that has columns that can be shown/hidden as the user likes. After I initialize the table, I call a custom restoreColumns() method that hides the columns (using QTableView::hideColumn()) that the user had hidden the last time the GUI was open.
The problem then comes when the user tries to show the columns that were hidden by the user the last time the GUI was ran. The appropriate signal/slot gets called and run through but for some reason the QTableView isn't updating to display the column.
What's weird is that any column that is already displayed (was not hidden by the user the last time the GUI was ran) has no problems with getting hidden/shown.
Any thoughts? Thanks!
Here's how I initialize the table...
m_tableModel = new mytablemodel();
m_tableView = new mytableview();
m_tableView->setItemDelegate(m_tableDelegate);
m_tableView->setModel(m_tableModel);
Meat of restoreColumns() method:
for (int i=0; i<horizontalHeader()->count(); i++) {
// load size to restore previous width
...
horizontalHeader()->resizeSection(i, width); // restore width
// load previous column position
...
// restore column order
int currentVisualIndex = horizontalHeader()->visualIndex(i);
if (currentVisualIndex != visualIndex)
horizontalHeader()->moveSection(currentVisualIndex, visualIndex);
// load previous hidden/shown state
...
if (columnHidden) {
hideColumn(i);
} else {
showColumn(i);
}
}
Below is some sample code to show/hide one of the columns.
void mytableview::showAColumn(bool checked) {
// mytableview is a subclass of qtableview
if (checked)
showColumn(COLUMN_A); // COLUMN_A is an enum for the column
else
hideColumn(COLUMN_A);
}
Which is connected to a QAction that can be accessed from the Menu and Context Menu of the QHeaderView of the QTableView.
connect(action, SIGNAL(toggled(bool)), this, SLOT(showAColumn(bool)));
When you are loading the previous width of the hidden columns, the width that was saved was 0.
So, when resizing the column make sure that the width is greater than 0.
Do this and then the columns will show/hide as expected.

Array Objects and Datagrid with Link Button (Clear Button) in Adobe Flex

I have an an array of objects. I populate the datagrid from the array. The nmber of columns in the datagrid is fix i.e.5 and the first column always shows serial number (0,1,2,3,4).
I have a link button called 'CLEAR' in the last column of the datagrid.
1> How do I make the clear button visible only when the row is particularly clicked ?
2> When the clear button is clicked, how do I make the contents of that particular row cleared. Not deleted, only cleared to insert data again. Also, the serial number (0,1,2,3,4) should not be cleared, nor deleted. How to do this ?
To make your clear button visible something like this would work.
may have to play around with it a bit.
private function onDatagridClick(event:ListEvent):void {
if ( event.rowIndex == -1 ) {
return;
}
clearBTN[event.RowIndex].visible = true;
}
If you don't want to delete your column you need to place some data in there as the datagrid is bound by the data provider you can always add dummy data i.e. blank string, "Enter data" or a custom item renderer for when data is required.

Resources