JavaFX chart: proper way to switch series data - javafx-8

We have a java program that takes a CSV file and processes it into multiple sets of data. The data is displayed one at a time on an XYChart with a ComboBox to choose between them. However we keep running into problems updating / changing the data:
First we had a bunch of ObservableList objects for each data series, e.g.
ObservableList<XYChart.Data<T,V>> data = FXCollections.observableArrayList();
and whenever the ChoiceBox selection was changed we would clear the series and add the one corresponding to the different selection, e.g.
theChart.getData().clear();
theChart.getData().add(new XYChart.Series<T,V>(data));
However, we would get errors when data was updated saying something about same data added to multiple charts. I think this would occur if theChart.getData().add(new XYChart.Series<T,V>(data)); had been called twice for the same data beforehand.
So I wrapped it up like
XYChart.Series<T,V> series = new XYChart.Series<>(data);
and changed the chart data like:
theChart.getData().clear();
theChart.getData().add(series);
Works fine on my computer but on another when data is cleared and then added to we get a null pointer exception during the series onChanged event, which suggests some kind of race condition.
Questions:
What is the proper what to change the series that a JavaFX chart is displaying?
Is there a way to 'pause' onChanged events so that an entire data series can be updated before the chart tries to redraw.

You can't do a clear(), that will throw an UnsupportedOperationException. The proper way to update the chart is setting a new empty ObservableList and then add the new XYChart.Series with the proper XYChart.Data objects into.
chart.setData(FXCollections.observableArrayList());
XYChart.Series<T, V> series = new XYChart.Series<T, V>();
XYChart.Data<T, V> data = new XYChart.Data<T, V>(t_type_Value, v_type_Value);
series.getData().add(data);
chart.getData().add(series);

Related

Drools Business Central Workbench - Test Scenario: List subproperty on object

Is there a way to populate a List property on an object being tested under the "new style" test scenario?
I see some "legacy" test cases which seem to achieve this so am wondering if the new style test scenario handles this.
I added the List model to my test case, which enabled me to expand the sub-property on the object, however there is only one field available there, "empty" (boolean). Is there a way to add an object here? If it makes any difference, the model is an external java dependency.
Update
The reason I wasn't able to add the List of objects was because I didn't explicitly import that object dependency into the test. Once you import it you can follow the steps given in the answer below.
It's definitely possible to manage a List property under the Test Scenario Editor.
Please consider the following example: A Book class with a List<String> property named topics.
Creating a new Test Scenario assets, please select the column where you need to add the List property, and in the right part of the editor select the property expanding the Book class, as shown below:
Pressing Insert Data Ojbect button will assign the selected List property to the selected column:
To fill the data in the List property, please double click on the Insert value cell, in the first scenario data row. A popup will appear. Its aim is to fill data inside a collection
To add a value, please press the Add list value link in the bottom part of the popup. Here, you'll be able to fill a single item on the list
Repeat this step for all the items you need to add to the list. When completed, simply press to Save button
The popup will close and you should see the previously selected data cell filled with a label similar to List(2), the number represents the number of the items in the list.

What is the best way to handle deleting rows in Ag-Grid when using Redux?

Adding rows is pretty straightforward - just have to add a new row in my Redux store, which then updates my table.
However if I delete a row from my Redux store the row data still seems to hang around somewhere - I have a few custom cell renderers which will then trigger errors as the data gets passed to them from Ag-Grid, but the row no longer exists in my store creating the errors.
Code example would be helpful here to figure out the source of issue- in meantime please check if after manipulating your store, you do refresh the grid data - something like:
gridOptions.api.setRowData(gridOptions.rowData)
More about ag-grid row data updating can be found here:
https://www.ag-grid.com/javascript-grid-data-update/
https://www.ag-grid.com/react-redux-integration-pt1/
Data binding in React can be achieved by using a controlled input. A controlled input is achieved by binding the value to a state variable and a onChange event to change the state as the input value changes.
See the below snippet:
onRemoveSelected() {
var selectedData = this.gridApi.getSelectedRows();
var res = this.gridApi.updateRowData({ remove: selectedData });
this.props.actions.delete(selectedData.id);
}
Unfortunately neither of these suggestions worked in my case.
Setting a debugger in my custom cellRenderer showed that the row had been removed from this.props.api.gridOptionsWrapper.gridOptions.rowData, yet the cellRenderer was still called for the deleted row.
The quick fix solution I came up with was just to test if the row (this.props.data) using the cellRenderer existed in this.props.api.gridOptionsWrapper.gridOptions.rowData in a shouldComponentUpdate within the cellRenderer.
shouldComponentUpdate(nextProps) {
const { api, data } = nextProps;
const gridRowDataIds = api.gridOptionsWrapper.gridOptions.rowData.map(
row => {
return JSON.parse(row.rowMetadata).id;
}
);
const dataPropsId = JSON.parse(data.rowMetadata).id;
return gridRowDataIds.includes(dataPropsId);
}
Note: rowMetadata is just a hidden column used to hold various properties regarding the row, such as an id, visibility, if it has been edited, etc.

AgGrid "serverSide" rowModel doesn't recognize custom overlay components (loading and noRows)

The problem is that I can not make ag-grid-react to show custom components for loadingOverlay and noRowsOverlay automatically (meaning managed by the grid itself). I've done all like described in the docs.
These are my options:
frameworkComponents={{
customOverlayLoading: CustomOverlayLoading,
customOverlayNoRows: CustomOverlayNoRows,
}}
loadingOverlayComponent="customOverlayLoading"
noRowsOverlayComponent="customOverlayNoRows"
Interesting thing is that it works for "clientSide" row model, e.g. when using prop rowData={undefined} - loading or rowData={[]} - noRows.
But when I replace rowData with rowModelType="serverSide" the grid then does not recognize new components for overlay.
There is no mention in the docs that this thing only works with clientSide row model. So I expect it should work. The way I can make it work is through the grid API. But I expect from that feature it should handle loading and noRows automatically for each of row models. The problem with the API usage is that there is no flag that points whether it is loading or not
there is the stackblitz reproduction. To check serverSide rowModel enterprise version needed
https://stackblitz.com/edit/ag-grid-ro-model?embed=1&file=index.js
When you're using rowModelType='serverSide', you need to call overlays yourself inside getRows() where you're implementing datasource.
gridApi.showNoRowsOverlay(); // show NoRowsOverlay
params.successCallback([], 0); // Pass empty array, Zero for lastRow
It will work. :)

Bar Chart and Stacked Bar Chart using similar data on one page

I am trying to show some data in a bar chart and stacked bar chart using JavaFx. I am using 4 series into which I populate the data, using eclipse oxygen.
I use series1 and series2 in the Bar Chart.
I use series1, series2, series3, and series4 in the Stacked Bar Chart.
I have created my screen using the JavaFx Scene Builder. Populate the scenes and displaying the data. My problem is that I am not able to show both the graphs at the same time. Only the latter gets populated, depending on the order of the population. The extra bit I have added is that the graphs expand on a mouse enter event and then reduces to the orginal size on the mouse exit event.
Can anyone help me by pointing out what I am doing wrong?
My code is as follows
#FXML
private void bcsbg_mouseentered() {
if (!clickEntered) {
clickEntered = true;
prefWidth = bcByGroup.getPrefWidth();
prefHeight = bcByGroup.getPrefHeight();
bcByGroup.setPrefSize(1500, 900);
gXAxis.setPrefHeight(Region.USE_COMPUTED_SIZE);
gXAxis.setPrefWidth(Region.USE_COMPUTED_SIZE);
gYAxis.setPrefHeight(Region.USE_COMPUTED_SIZE);
gYAxis.setPrefWidth(Region.USE_COMPUTED_SIZE);
gXAxis.setVisible(true);
gYAxis.setVisible(true);
gXAxis.setLabel("Value");
gYAxis.setLabel("Question");
gXAxis.setTickLabelsVisible(true);
gYAxis.setTickLabelsVisible(true);
gXAxis.setTickMarkVisible(true);
gYAxis.setTickMarkVisible(true);
sbcByAll.setVisible(false);
} else {
clickEntered = false;
bcByGroup.setPrefSize(prefWidth, prefHeight);
gXAxis.setPrefHeight(0);
gXAxis.setPrefWidth(0);
gYAxis.setPrefHeight(0);
gYAxis.setPrefWidth(0);
gXAxis.setVisible(false);
gYAxis.setVisible(false);
gXAxis.setLabel("");
gYAxis.setLabel("");
gXAxis.setTickLabelsVisible(false);
gYAxis.setTickLabelsVisible(false);
gXAxis.setTickMarkVisible(false);
gYAxis.setTickMarkVisible(false);
sbcByAll.setVisible(true);
sbcByAll.getData().clear();
sbcByAll.getData().addAll(series1, series2, series3, series4);
}
bcByGroup.getData().clear();
bcByGroup.getData().addAll(series1, series2);
}
The problem here is not in your code, but in the way the chart API is written. (I'm not normally a fan of criticizing languages or standard libraries, but parts of this API appear to have been written by an unsupervised intern with a particularly bad hangover.)
The XYChart.Data class keeps a reference to the node that displays the data. (This fairly obviously violates the most basic tenets of MVC, and makes separating the data into a different class completely redundant.)
Consequently, if you try to use the same data in two charts, the same node tries to appear in two parents, which is not allowed, and you only see the visualization of the data in one place. Unfortunately, you need to replicate the data for each chart.
Thank you, Dave. You are right. I did not go through the standard documentation on the XYData.Chart to notice that this object would be attached to the node in which the data was going to be displayed.
I was really hoping to avoid replication but the code does work as soon as the data series is replicated and attached to the different charts.
As mentioned by Dave,
The XYChart.Data class keeps a reference to the node that displays the data. (This fairly obviously violates the most basic tenets of MVC, and makes separating the data into a different class completely redundant.)
Please go through the standard documentation provided in Dave's link.

How to dynamically insert and remove rows

I'm looking for a widget which can be dynamically resized. I need to append and remove rows.
There are a methods coming with Grid, like gtk_grid_insert_row or gtk_grid_insert_next_to, but I don't find any xxx_remove_xxx method.
I'm developing a simple http client (to test an api). And I'm adding the possibility to append and remove "GET" variables dynamically.
The UI is made with rows containing a combobox (for variable selection), an entry (for its value) and on the last row a remove button.
Every time I set a variable, a new line (new available variable) is appended.
And every time I unset a variable, the corresponding line is removed.
thanks.
Gtk.Grid doesn't have a remove method; but Gtk.Container does. Since Grid is a Container, you can use gtk_container_remove.
The docs for this are here:
https://developer.gnome.org/gtk3/3.8/GtkContainer.html#gtk-container-remove
I think the widget you are looking for is Gtk.ListBox. It's a container so you can add and remove rows easily.