How can I clear all data in a JavaFX graph? - graph

I get this weird exception and I think that it is a bug. I am trying to clear a Series, which contains a list of points to plot in the graph. However, after clearing I want to add new Data and this gives me a nul pointer exception. My code:
public static void main(String[] args) {
Series<String, Number> series = new Series<String, Number>();
Number value1 = new Integer(5);
Number value2 = new Integer(6);
Data<String, Number> point1 = new Data<String, Number>("Something", value1);
Data<String, Number> point2 = new Data<String, Number>("Something", value2);
series.getData().add(point1);
series.getData().add(point2);
series.getData().clear();
Number value3 = new Integer(7);
Data<String, Number> point3 = new Data<String, Number>("Something", value3);
**series.getData().add(point3);**
}
I get a null pointer exception at the marked code line. I just need a way to reset this series, but to me it seems like a bug in JavaFX. I use Java 8, which has JavaFX as an integration.
Can someone help me?

The technical reason is a NPE in the listener on the data list, installed by series:
if (c.getAddedSize() > 0) {
for (Data<X,Y> itemPtr = begin; itemPtr != null; itemPtr = itemPtr.next) {
if (itemPtr.setToRemove) {
getChart().dataBeingRemovedIsAdded(itemPtr, Series.this);
itemPtr.setToRemove = false;
}
}
}
This will throw on the next addition if an item had been deleted while the chart is null.
The deeper reason is the slightly convoluted delete mechanism: the series doesn't delete the item itself but only marks it as ready for deletion. Then it delegates the change to its chart which then calls back into the series to do the actual delete. And that mechanism breaks if there is no chart.
Real solutions might be hard from the outside, because everything is so tightly and secretly knitted - no way to hook your own listener to do the actual remove. If you really have to manipulate (remove items) the series without a chart attached, you might try to implement a dummy chart and set that to the series.

Related

The button in nattable is covering half of my table, can someone explain why?

i have used the following code for the button
natTable.addOverlayPainter(new NatTableBorderOverlayPainter());
Composite panel = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 5;
layout.marginWidth = 8;
panel.setLayout(layout);
GridDataFactory.fillDefaults().grab(true, true).applyTo(panel);
Composite gridPanel = new Composite(panel, SWT.NONE);
gridPanel.setLayout(layout);
GridDataFactory.fillDefaults().grab(true, true).applyTo(gridPanel);
Composite buttonPanel = new Composite(panel, SWT.NONE);
buttonPanel.setLayout(new RowLayout());
GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonPanel);
Button addButton = new Button(gridPanel, SWT.PUSH);
addButton.setText("Export");
addButton.setSize(1, 1);
addButton.setLocation(450, 150);
addButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
natTable.doCommand(new ExportCommand(natTable
.getConfigRegistry(), null, editable));
natTable.updateResize();
}
but at the end i am getting this as a result
https://imgur.com/EFcPaqo
Your layout is broken. Probably because the NatTable instance is not created on one of your Composites. But hard to tell without seeing the creation of it.
Either have a look at Understanding layouts in SWT or even check the NatTable examples PrintExample that shows exactly the same. There you can see that NatTable is created on the gridPanel.

My JavaFX Tooltip isn't showing up on a chart data node

I'm playing around with JavaFX and wanted to add a tooltip that pops up with the data value when the mouse is hovering over the node. I found several links and answers out there describing CSS methods for doing it, or using Tooltip.install(node, tooltip) and while I could get a tooltip working on a dummy example, I was still having no luck with the chart, using code like so :
LineChart<Number, Number> chart = new LineChart(xaxis, yaxis);
ObservableList<Data<Number, Number>> data = FXCollections.observableArrayList();
Data<Number, Number> d1 = new XYChart.Data<Number, Number>(5, 15);
Tooltip tooltip = new Tooltip("15");
Tooltip.install(d1.getNode(), tooltip);
data.add(d1);
Data<Number, Number> d2 = new XYChart.Data<Number, Number>(10, 25);
Tooltip tooltip2 = new Tooltip("25");
Tooltip.install(d2.getNode(), tooltip2);
data.add(d2);
chart.setData(data);
//add chart to scene etc etc etc
After some digging, the issue here is that a data element (XYChart.Data) does not have a node created at construction time. chart.setData(data) will populate the node field - I believe this is to allow the user to create and set their own nodes if so desired. So d1.getNode() is actually returning null, and Tooltip.install() is silently failing.
Moving the Tooltip.install call after chart.setData solves the issue.

JavaFX architecture in building dynamic "rows"

I have an application that I am building that has a table in it, I'm not using a tableview to build this table because I need each row to be able to expand similar to an accordion. I was able to achieve what I need by using a timeline and looping through the data and building each row (its kind of crude right now since I'm still working with dummy data eventually it will be a list iterator and not just a for loop) but I'm not happy with how its done. There are a lot of default values that will never change so I don't really need to set them in my worker class every time, I decided to just add them to the object class that I put together. So basically, at a high level it looks something like this:
for (int i = 0; i < 30; i++) {
RowBuilder builder = new RowBuilder(tableBox, i);
try {
builder.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I'm passing it the parent which is a VBox - tableBox, then I'm passing the count for later use.
Inside the RowBuilder I'm getting a new instance of the object DashboardRow which has all the defaults set in it, then I'm setting the data for each row and returning the DashboardRow.
Here is an example of a getter setting values in the DashboardRow
public HBox getMainRow() {
mainRow.setAlignment(Pos.CENTER_LEFT);
mainRow.setPrefHeight(60);
mainRow.setMinHeight(60);
mainRow.setMaxHeight(60);
mainRow.setPrefWidth(-1);
mainRow.setStyle("-fx-background-color:#FFFFFF;");
return mainRow;
}
Inside the DashboardRow class I have a ton of new objects being created for every element I need in the row. There are 21 for each row, mostly VBox, HBox and StackPane to build the actual row, the rest are just labels and buttons.
This is what is looks like so far. Opened and closed states.
Is there a better way to dynamically build things like this in javafx? I'm basically pulling data from a database and looping through that data to populate a row.
I can't comment but it may be an answer anyway. Why can't you use the setGraphic method of a custom table cell and put the accordion node in a table. setGraphic takes any kind of node.
It sounds simpler than what you're doing.
I just tried it out with the Oracle sample and it works great.
I added
Callback<TableColumn<Person, String>, TableCell<Person, String>> accCellFactory
= new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {
#Override
public TableCell call(TableColumn p) {
TitledPane t1 = new TitledPane("T1", new Button("B1"));
TitledPane t2 = new TitledPane("T2", new Button("B2"));
TitledPane t3 = new TitledPane("T3", new Button("B3"));
Accordion accordion = new Accordion();
accordion.getPanes().addAll(t1, t2, t3);
TableCell tc = new TableCell();
tc.setGraphic(accordion);
return tc;
}
};
and changed this line firstNameCol.setCellFactory(accCellFactory);
and I get
Of course you might want something other than buttons but I just copied the Accordion sample from the javadoc.

HierarchicalCollectionView: One time sort?

I have an AdvancedDataGrid that relies on a HierarchicalCollectionView as it's dataProvider. What I'd like to do is sort the data when it is first loaded, but then disable the sort so that anything that is added after the initial load doesn't cause the grid to auto-sort again. I tried something like this:
this._myDataProvider = new HierarchicalCollectionView(
new HierarchicalData(this._model.rootTasks));
var mySort:Sort = new Sort();
mySort.fields = [new SortField("startDate")];
this._tasksDataProvider.sort = taskSorting;
this._tasksDataProvider.refresh();
this._tasksDataProvider.sort = null;
But setting the sort to null just leaves the data unsorted. I guess what I'm asking is: how can I sort the underlying hierarchical data since it seems setting the sort property will keep it dynamically sorting. Thanks for any help you can provide.
Personally, I would change the sort order when you're getting the data. Either it's done on the server side or when you parse the data (ie. in your model). You can do a one time sort using Array with sortOn.
you can
1. sort the original data with sort function,
2. clone content and put it to a new collection with no sort (be careful do and make a manual clone),
3. just use the new data collection.
I had the same kind of problem until I realized that the sorting with Sort object does not change the "physical" ordering of the items within the Collection, so when you remove the Sort, the next refresh reverts the view to the actual "physical" ordering.
Similarily as stated above, I solved by it by cloning the sub-collections into sorted order this way:
public static function buildPositionSort():Sort
{
var dataSortField:SortField = new SortField();
dataSortField.name = "position";
dataSortField.numeric = true;
dataSortField.descending = false;
var sort:Sort = new Sort();
sort.fields = [ dataSortField ];
return sort;
}
/**
* This method is used to create a clone of ArrayCollection, because sorting does not
* actually change the physical ordering of the items.
*/
public static function createSortedArrayCollectionCopy(source:ArrayCollection):ArrayCollection
{
var target:ArrayCollection = new ArrayCollection();
source.sort = buildPositionSort();
source.refresh();
for each (var item:Object in source)
{
if (item.children != null) item.children = createSortedArrayCollectionCopy(item.children);
target.addItem(item);
}
return target;
}

Factory Method implementation in actionscript

Hey folks, i ve got this issue implementing the Factory method.
Following is the snippet of the the main chart class which calls ChartFactory's method to attain the proper object. I Type Cast chartobject so as to be able to call the Show method;i m apprehensive about that as well.
container = new VBox();
container.percentWidth = 100;
container.percentHeight = 100;
super.media.addChild(container);
chartObject = new ChartBase();
chartObject = ChartFactory.CreateChartObject(chartType);
IChart(chartObject).Show(o);
container.addChild(chartObject);
legend = new Legend();
legend.dataProvider = IChart(chartObject);
container.addChild(legend);
Following is the snippet of ChartFactory's method:
public static function CreateChartObject(subType:String):ChartBase
{
switch(subType)
{
case ChartFactory.AREA_CHART:
return new AreaCharts();
break;
case ChartFactory.COLUMN_CHART:
return new ColumnCharts();
break;
case ChartFactory.PIE_CHART:
return new PieCharts();
break;
default:
throw new ArgumentError(subType + ": Chart type is not recognized.");
}
}
And following is Show method of one of the several Charts type classes: AreaCharts, PieCharts etc. All of which implements IChart Interface.
public function Show(o:ObjectProxy):void
{
var grids:GridLines;
var stroke:SolidColorStroke;
var horizontalAxis:CategoryAxis;
var verticalAxis:LinearAxis;
var horizontalAxisRenderer:AxisRenderer;
var verticalAxisRenderer:AxisRenderer;
grids = new GridLines();
if(WidgetStylesheet.instance.LineChart_ShowGrid)
grids.setStyle("gridDirection", "both");
else
grids.setStyle("gridDirection", "");
stroke = new SolidColorStroke(WidgetStylesheet.instance.LineChart_GridLineColor, WidgetStylesheet.instance.LineChart_GridLineThickness);
grids.setStyle("horizontalStroke", stroke);
grids.setStyle("verticalStroke", stroke);
horizontalAxis = new CategoryAxis();
horizontalAxis.categoryField = o.LargeUrl.Chart.xField;
horizontalAxis.title = o.LargeUrl.Chart.xAxisTitle.toString();
verticalAxis = new LinearAxis();
verticalAxis.title = o.LargeUrl.Chart.yAxisTitle.toString();
horizontalAxisRenderer = new AxisRenderer();
horizontalAxisRenderer.axis = horizontalAxis;
horizontalAxisRenderer.setStyle("tickLength", 0);
horizontalAxisRenderer.setStyle("showLine", false);
horizontalAxisRenderer.setStyle("showLabels", true);
horizontalAxisRenderer.setStyle("fontSize", WidgetStylesheet.instance.ComputeChartAxisFontSize(o.HeadlineFontSize));
verticalAxisRenderer = new AxisRenderer();
verticalAxisRenderer.axis = verticalAxis;
verticalAxisRenderer.setStyle("tickLength", 0);
verticalAxisRenderer.setStyle("showLine", false);
verticalAxisRenderer.setStyle("fontSize", WidgetStylesheet.instance.ComputeChartAxisFontSize(o.HeadlineFontSize));
this.series = this.m_createSeries(o);
this.horizontalAxis = horizontalAxis;
this.horizontalAxisRenderers = [horizontalAxisRenderer];
this.verticalAxis = verticalAxis;
this.verticalAxisRenderers = [verticalAxisRenderer];
this.backgroundElements = [grids];
}
I'm afraid that there is more than one issue with this code. Unfortunately it is not obvious why your chart doesn't show up so you may apply some of advices below and use debugger to analyse the issue.
There is no point in creating ChartBase instance if you are going to change value of chartObject reference in the next line
chartObject = new ChartBase();
chartObject = ChartFactory.CreateChartObject(chartType);
If the API of your charts is IChart your factory should return IChart instead of casting.
public static function CreateChartObject(subType:String):IChart
Make sure that you are returning instances of the correct class from the factory. i.e. that you are returning your subclass of standard PieChart. Generally it's not the best idea to extend the class keeping the same name and just changing the package.
Once again, if you are not sure if the program enters some function use the Flash Builder debugger to check this. I can't imagine development without debugger.
Some thoughts:
you call the Show method, pass it some object but nowhere in that method is any child added to a displayObject. What exactly is Show supposed to do?
a lot of member variables in your classes start with UpperCase. The compiler can easily confuse those with class names, in case your classes are named the same. Bad practice to start variable and function names with capitals.
If your casting an instance to another class or interface fails, you will get a runtime error. Those are easy to debug using the Flash Builder debugger.
Hey ppl..
i found out wat wnt wrng..as olwys it wa "I".
I ve a habit of mkin mock ups secluded from the main project n dn integrate it. So in mock up i hd used an xml whch hd a format slightly diff dn d one being used in the main project.
N i hd a conditional chk to return from the prog if certain value doesnt match, n due to faulty xml i did'nt.
So this more a lexical error than a logical one.
Sorry n Thanx evryone for responding.

Resources