FXML Custom Chart - javafx-2

I've been using custom fitting chart from Ensemble Test, which works great.
Problem is I cannot use it in FXML. Someone else seemed to do that successfully.
Error: Instances of curvefittedareachartappfxml.CurvedFittedAreaChart cannot be created by FXML Loader.
FXMLDocument.fxml
<?import javafx.scene.chart.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import curvefittedareachartappfxml.CurveFittedAreaChart?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="curvefittedareachartappfxml.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="128.0" layoutY="25.0" text="Click Me!" />
<AreaChart layoutX="56.0" layoutY="131.0" prefHeight="200.0" prefWidth="444.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="60.0">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</AreaChart>
<CurveFittedAreaChart layoutX="10.0" layoutY="160.0" prefHeight="200.0" prefWidth="444.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="250.0">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</CurveFittedAreaChart>
</children>
</AnchorPane>
CurveFittedAreaChart.java Original from Oracle Ensemble
/*
* Copyright (c) 2008, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* - Neither the name of Oracle Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package curvefittedareachartappfxml;
import javafx.collections.ObservableList;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.util.Pair;
public class CurveFittedAreaChart extends AreaChart<Number, Number> {
public CurveFittedAreaChart(NumberAxis xAxis, NumberAxis yAxis) {
super(xAxis, yAxis);
}
#Override protected void layoutPlotChildren() {
super.layoutPlotChildren();
for (int seriesIndex = 0; seriesIndex < getDataSize(); seriesIndex++) {
final XYChart.Series<Number, Number> series = getData().get(seriesIndex);
final Path seriesLine = (Path) ((Group) series.getNode()).getChildren().get(1);
final Path fillPath = (Path) ((Group) series.getNode()).getChildren().get(0);
smooth(seriesLine.getElements(), fillPath.getElements());
}
}
private int getDataSize() {
final ObservableList<XYChart.Series<Number, Number>> data = getData();
return (data != null) ? data.size() : 0;
}
private static void smooth(ObservableList<PathElement> strokeElements, ObservableList<PathElement> fillElements) {
// as we do not have direct access to the data, first recreate the list of all the data points we have
final Point2D[] dataPoints = new Point2D[strokeElements.size()];
for (int i = 0; i < strokeElements.size(); i++) {
final PathElement element = strokeElements.get(i);
if (element instanceof MoveTo) {
final MoveTo move = (MoveTo) element;
dataPoints[i] = new Point2D(move.getX(), move.getY());
} else if (element instanceof LineTo) {
final LineTo line = (LineTo) element;
final double x = line.getX(), y = line.getY();
dataPoints[i] = new Point2D(x, y);
}
}
// next we need to know the zero Y value
final double zeroY = ((MoveTo) fillElements.get(0)).getY();
// now clear and rebuild elements
strokeElements.clear();
fillElements.clear();
Pair<Point2D[], Point2D[]> result = calcCurveControlPoints(dataPoints);
Point2D[] firstControlPoints = result.getKey();
Point2D[] secondControlPoints = result.getValue();
// start both paths
strokeElements.add(new MoveTo(dataPoints[0].getX(), dataPoints[0].getY()));
fillElements.add(new MoveTo(dataPoints[0].getX(), zeroY));
fillElements.add(new LineTo(dataPoints[0].getX(), dataPoints[0].getY()));
// add curves
for (int i = 1; i < dataPoints.length; i++) {
final int ci = i - 1;
strokeElements.add(new CubicCurveTo(
firstControlPoints[ci].getX(), firstControlPoints[ci].getY(),
secondControlPoints[ci].getX(), secondControlPoints[ci].getY(),
dataPoints[i].getX(), dataPoints[i].getY()));
fillElements.add(new CubicCurveTo(
firstControlPoints[ci].getX(), firstControlPoints[ci].getY(),
secondControlPoints[ci].getX(), secondControlPoints[ci].getY(),
dataPoints[i].getX(), dataPoints[i].getY()));
}
// end the paths
fillElements.add(new LineTo(dataPoints[dataPoints.length - 1].getX(), zeroY));
fillElements.add(new ClosePath());
}
/**
* Calculate open-ended Bezier Spline Control Points.
*
* #param dataPoints Input data Bezier spline points.
* #return The spline points
*/
public static Pair<Point2D[], Point2D[]> calcCurveControlPoints(Point2D[] dataPoints) {
Point2D[] firstControlPoints;
Point2D[] secondControlPoints;
int n = dataPoints.length - 1;
if (n == 1) { // Special case: Bezier curve should be a straight line.
firstControlPoints = new Point2D[1];
// 3P1 = 2P0 + P3
firstControlPoints[0] = new Point2D(
(2 * dataPoints[0].getX() + dataPoints[1].getX()) / 3,
(2 * dataPoints[0].getY() + dataPoints[1].getY()) / 3);
secondControlPoints = new Point2D[1];
// P2 = 2P1 – P0
secondControlPoints[0] = new Point2D(
2 * firstControlPoints[0].getX() - dataPoints[0].getX(),
2 * firstControlPoints[0].getY() - dataPoints[0].getY());
return new Pair<Point2D[], Point2D[]>(firstControlPoints, secondControlPoints);
}
// Calculate first Bezier control points
// Right hand side vector
double[] rhs = new double[n];
// Set right hand side X values
for (int i = 1; i < n - 1; ++i) {
rhs[i] = 4 * dataPoints[i].getX() + 2 * dataPoints[i + 1].getX();
}
rhs[0] = dataPoints[0].getX() + 2 * dataPoints[1].getX();
rhs[n - 1] = (8 * dataPoints[n - 1].getX() + dataPoints[n].getX()) / 2.0;
// Get first control points X-values
double[] x = GetFirstControlPoints(rhs);
// Set right hand side Y values
for (int i = 1; i < n - 1; ++i) {
rhs[i] = 4 * dataPoints[i].getY() + 2 * dataPoints[i + 1].getY();
}
rhs[0] = dataPoints[0].getY() + 2 * dataPoints[1].getY();
rhs[n - 1] = (8 * dataPoints[n - 1].getY() + dataPoints[n].getY()) / 2.0;
// Get first control points Y-values
double[] y = GetFirstControlPoints(rhs);
// Fill output arrays.
firstControlPoints = new Point2D[n];
secondControlPoints = new Point2D[n];
for (int i = 0; i < n; ++i) {
// First control point
firstControlPoints[i] = new Point2D(x[i], y[i]);
// Second control point
if (i < n - 1) {
secondControlPoints[i] = new Point2D(2 * dataPoints[i + 1].getX() - x[i + 1], 2
* dataPoints[i + 1].getY() - y[i + 1]);
} else {
secondControlPoints[i] = new Point2D((dataPoints[n].getX() + x[n - 1]) / 2,
(dataPoints[n].getY() + y[n - 1]) / 2);
}
}
return new Pair<Point2D[], Point2D[]>(firstControlPoints, secondControlPoints);
}
/**
* Solves a tridiagonal system for one of coordinates (x or y) of first
* Bezier control points.
*
* #param rhs Right hand side vector.
* #return Solution vector.
*/
private static double[] GetFirstControlPoints(double[] rhs) {
int n = rhs.length;
double[] x = new double[n]; // Solution vector.
double[] tmp = new double[n]; // Temp workspace.
double b = 2.0;
x[0] = rhs[0] / b;
for (int i = 1; i < n; i++) {// Decomposition and forward substitution.
tmp[i] = 1 / b;
b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
x[i] = (rhs[i] - x[i - 1]) / b;
}
for (int i = 1; i < n; i++) {
x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
}
return x;
}
}
Controller and App files are default NetBeans generated.

What's going wrong
There are multiple issues in your code.
If you want to instantiate a instance of a class by referencing it in FXML, the class needs to a have default (no-arg) constructor.
Unfortunately, this isn't very well document in the Introduction to FXML document.
If you wish to set properties of an instantiated class via FXML, that class needs to have appropriate getters and setters. Refer to the property naming conventions used in the JavaFX properties and binding tutorial. Adhere to the conventions for lower camel case method naming or FXML won't pick up your methods as settable properties.
You are trying to assign a CategoryAxis to the XAxis of your custom chart, but the custom chart type you supplied requires that the XAxis be a NumberAxis.
An exception to the first two rules is if you supply a builder class (a sample builder class is provided below).
Sample builder class
Here is the builder code for the AreaChart class, which allows it to be used in the FXML in the way in which you have used it. If you wish to use your custom chart in the same way, you need to create your own builder.
package javafx.scene.chart;
/**
Builder class for javafx.scene.chart.AreaChart
#see javafx.scene.chart.AreaChart
#deprecated This class is deprecated and will be removed in the next version
* #since JavaFX 2.0
*/
#javax.annotation.Generated("Generated by javafx.builder.processor.BuilderProcessor")
#Deprecated
public class AreaChartBuilder<X, Y, B extends javafx.scene.chart.AreaChartBuilder<X, Y, B>> extends javafx.scene.chart.XYChartBuilder<X, Y, B> {
protected AreaChartBuilder() {
}
/** Creates a new instance of AreaChartBuilder. */
#SuppressWarnings({"deprecation", "rawtypes", "unchecked"})
public static <X, Y> javafx.scene.chart.AreaChartBuilder<X, Y, ?> create() {
return new javafx.scene.chart.AreaChartBuilder();
}
private javafx.scene.chart.Axis<X> XAxis;
/**
Set the value of the {#link javafx.scene.chart.AreaChart#getXAxis() XAxis} property for the instance constructed by this builder.
*/
#SuppressWarnings("unchecked")
public B XAxis(javafx.scene.chart.Axis<X> x) {
this.XAxis = x;
return (B) this;
}
private javafx.scene.chart.Axis<Y> YAxis;
/**
Set the value of the {#link javafx.scene.chart.AreaChart#getYAxis() YAxis} property for the instance constructed by this builder.
*/
#SuppressWarnings("unchecked")
public B YAxis(javafx.scene.chart.Axis<Y> x) {
this.YAxis = x;
return (B) this;
}
/**
Make an instance of {#link javafx.scene.chart.AreaChart} based on the properties set on this builder.
*/
public javafx.scene.chart.AreaChart<X, Y> build() {
javafx.scene.chart.AreaChart<X, Y> x = new javafx.scene.chart.AreaChart<X, Y>(this.XAxis, this.YAxis);
applyTo(x);
return x;
}
}
Sample code modifications
I did a minor refactoring of your FXML and the Oracle custom chart code to allow you to reference it in FXML. This code is just a sample to get you started, you will need to make more modifications to plot a useful chart in the manner you wish.
The sample does not take the custom builder class approach, instead it uses a default constructor and exposes the axes as properties.
In your CurveFittedAreaChart class, replace:
public CurveFittedAreaChart(NumberAxis xAxis, NumberAxis yAxis) {
super(xAxis, yAxis);
}
with:
public CurveFittedAreaChart() {
super(new NumberAxis(), new NumberAxis());
}
If you need to modify the axes (e.g., change their auto ranging capabilities), then you can inject the chart in your controller using #FXML, retrieve the axes from it in the controller initialize method, and modify the axes in code there.
In your FXML remove your axes specification, e.g., the chart is just referenced as below:
<CurveFittedAreaChart layoutX="10.0" layoutY="160.0" prefHeight="200.0" prefWidth="444.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="250.0">
</CurveFittedAreaChart>
Related info on usage in SceneBuilder
If you also want to use your custom component in SceneBuilder (which admittedly is not what your question asks), there are additional tasks you should perform:
How to create an FXML file for an already created new component in java than add it to scene builder?

Related

is there a way i can animate a polyline?

Something similar to a pulsing ring around a marker. What I want to achieve is this...
I have many polylines all having Lat/Lng. At a time t, a user can decide to pick any polyline of their choosing. I get their current real-time location coordinates via Bluetooth. I want to use that location to determine how far they are from the polyline they have selected and depending on the distance, change/animate that polyline. I am using google maps API, android studio, kotlin
Here's a simple example - a method which takes a Polyline instance and a handler (must be on main looper) and begins a repeating update to the polyline width.
(Added the Kotlin)
private lateinit var polyline: Polyline;
private lateinit var handler : Handler;
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
var ptlist = ArrayList<LatLng>();
// add polyline
ptlist.add(LatLng(40.437761, -3.704751));
ptlist.add(LatLng( 40.405072, -3.678678));
ptlist.add(LatLng( 40.397158, -3.742706));
ptlist.add(LatLng(40.437761, -3.704751));
handler = Handler(Looper.getMainLooper());
polyline = mMap.addPolyline(PolylineOptions().addAll(ptlist));
val runnableCode = object: Runnable {
override fun run() {
var w = polyline.width;
w = w + 0.5f;
if (w > 25.0) {
w = 1.0f;
}
polyline.setWidth(w);
handler.postDelayed(this, 50);
}
}
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(40.415521, -3.700995), 12f));
handler.postDelayed(runnableCode, 50);
}
In this example, the witdh of polyline p will vary from [25.0 1.0] incrementing by 0.5 every 200 milliseconds. When it reaches the maximum width it is reset to a width of 1.0. The original width is ignored.
Obviously change the parameters as needed - or make it pulse in and out.
(Java equivalent - animation parameters different.)
public void pulsePolyline(final Polyline p, final Handler h)
{
h.postDelayed(new Runnable() {
#Override
public void run() {
float w = p.getWidth();
w = (w + 0.1);
if (w > 10.0) w = 1.0;
p.setWidth(w);
h.postDelayed(this, 200);
}
}, 200);
}
Note the handler must be from the main thread (or looper) as in:
new Handler(Looper.getMainLooper())

Google cast receiver framework (CAF) queueing images

I am having trouble getting CAF framework to work with queueing jpeg images. I use SDK v3 to send QueueItem array to the receiver. I expect the cast framework to show me the images one by one and not just one image only. In my test, the input 'loadRequestData' has 4 images. But the cast receiver (on TV) shows only one image (whichever is pointed to by queueData.startIndex).
Here is the javascript code for initializing the queue:
/**
* Initializes the queue.
* #param {!cast.framework.messages.LoadRequestData} loadRequestData
* #return {!cast.framework.messages.QueueData}
* or non-null Promise containing nullable cast.framework.messages.QueueData
* THE loadRequestData (input parameter to initialize) ALREADY CONTAINS 4 ITEMS (jpeg images)
* BUT IT SHOWS **ONLY ONE IMAGE** DEFINED BY queueData.startIndex.
* IT DOES NOT SHOW OTHER IMAGES AT ALL (PLAYBACK DURATION ETC DO NOT SEEM TO HAVE ANY EFFECT)
*/
initialize( loadRequestData) {
const queueData = new cast.framework.messages.QueueData();
const items = [];
for (const requestItem of loadRequestData.queueData.items) {
const item = new cast.framework.messages.QueueItem();
item.media = new cast.framework.messages.MediaInformation();
item.media.contentId = requestItem.media.contentId;
item.media.contentUrl = requestItem.media.contentUrl;
item.media.contentType = requestItem.media.contentType ;
item.media.metadata = requestItem.media.metadata;
item.autoplay = true;
item.playbackDuration = 2;
item.preloadTime = 10;
item.startTime = 0;
items.push(item);
}
queueData.startIndex = 2;
queueData.items = items;
queueData.repeatMode = cast.framework.messages.RepeatMode.REPEAT_ALL;
return queueData;
}

How to represent Dependency Triplets in .arff file format?

I'm developing a classifier for text categorisation using Weka java libraries. I've extracted a number of features using Stanfords' CoreNLP package, including a dependency parse of the text which returns a string "(rel, head, mod)".
I was wanting to use the dependency triplets returned from this as features for classification but I cannot figure out how to properly represent them in the ARFF file. Basically, I'm stumped; for each instance, there are an arbitrary number of dependency triplets, so I can't define them explicitly in the attributes, for example:
#attribute entityCount numeric
#attribute depTriple_1 string
#attribute depTriple_2 string
.
.
#attribute depTriple_n string
Is there a particular way to go about this? I've spent the better part of the day searching and have not found anything yet.
Thanks a lot for reading.
Extracted from Weka Wiki:
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
/**
* Generates a little ARFF file with different attribute types.
*
* #author FracPete
*/
public class SO_Test {
public static void main(String[] args) throws Exception {
FastVector atts;
FastVector attsRel;
FastVector attVals;
FastVector attValsRel;
Instances data;
Instances dataRel;
double[] vals;
double[] valsRel;
int i;
// 1. set up attributes
atts = new FastVector();
// - numeric
atts.addElement(new Attribute("att1"));
// - nominal
attVals = new FastVector();
for (i = 0; i < 5; i++)
attVals.addElement("val" + (i+1));
atts.addElement(new Attribute("att2", attVals));
// - string
atts.addElement(new Attribute("att3", (FastVector) null));
// - date
atts.addElement(new Attribute("att4", "yyyy-MM-dd"));
// - relational
attsRel = new FastVector();
// -- numeric
attsRel.addElement(new Attribute("att5.1"));
// -- nominal
attValsRel = new FastVector();
for (i = 0; i < 5; i++)
attValsRel.addElement("val5." + (i+1));
attsRel.addElement(new Attribute("att5.2", attValsRel));
dataRel = new Instances("att5", attsRel, 0);
atts.addElement(new Attribute("att5", dataRel, 0));
// 2. create Instances object
data = new Instances("MyRelation", atts, 0);
// 3. fill with data
// first instance
vals = new double[data.numAttributes()];
// - numeric
vals[0] = Math.PI;
// - nominal
vals[1] = attVals.indexOf("val3");
// - string
vals[2] = data.attribute(2).addStringValue("This is a string!");
// - date
vals[3] = data.attribute(3).parseDate("2001-11-09");
// - relational
dataRel = new Instances(data.attribute(4).relation(), 0);
// -- first instance
valsRel = new double[2];
valsRel[0] = Math.PI + 1;
valsRel[1] = attValsRel.indexOf("val5.3");
dataRel.add(new Instance(1.0, valsRel));
// -- second instance
valsRel = new double[2];
valsRel[0] = Math.PI + 2;
valsRel[1] = attValsRel.indexOf("val5.2");
dataRel.add(new Instance(1.0, valsRel));
vals[4] = data.attribute(4).addRelation(dataRel);
// add
data.add(new Instance(1.0, vals));
// second instance
vals = new double[data.numAttributes()]; // important: needs NEW array!
// - numeric
vals[0] = Math.E;
// - nominal
vals[1] = attVals.indexOf("val1");
// - string
vals[2] = data.attribute(2).addStringValue("And another one!");
// - date
vals[3] = data.attribute(3).parseDate("2000-12-01");
// - relational
dataRel = new Instances(data.attribute(4).relation(), 0);
// -- first instance
valsRel = new double[2];
valsRel[0] = Math.E + 1;
valsRel[1] = attValsRel.indexOf("val5.4");
dataRel.add(new Instance(1.0, valsRel));
// -- second instance
valsRel = new double[2];
valsRel[0] = Math.E + 2;
valsRel[1] = attValsRel.indexOf("val5.1");
dataRel.add(new Instance(1.0, valsRel));
vals[4] = data.attribute(4).addRelation(dataRel);
// add
data.add(new Instance(1.0, vals));
// 4. output data
System.out.println(data);
}
}
Your problem is in particular a "relational" attribute. This code segment has dealt with such relational attribute.
Alright, I did it! Just posting this as an answer incase anyone else has a similar problem. Previously I was following the guide found on the Weka Wiki (as posted below by Rushdi), but I was having a lot of trouble following as the guide is creating static instances of the relational attribute, where as I required dynamic declarations of an arbitrary amount. So I decided to re-evaluate how I was generating the attributes, and I managed to get it to work with slight changes to the above guide:
//1. Set up attributes
FastVector atts;
FastVector relAtts;
Instances relData;
atts = new FastVector();
//Entity Count - numeric
atts.addElement(new Attribute("entityCount"));
//Dependencies - Relational (Multi-Instance)
relAtts = new FastVector();
relAtts.addElement(new Attribute("depTriplet", (FastVector) null));
relData = new Instances("depTriples", relAtts, 0);
atts.addElement(new Attribute("depTriples", relData, 0));
atts.addElement(new Attribute("postTxt", (FastVector) null));
//2. Create Instances Object
Instances trainSet = new Instances("MyName", atts, 0);
/* 3. Fill with data:
Loop through text docs to extract features
and generate instance for train set */
//Holds the relational attribute instances
Instances relAttData;
for(Object doc: docList) {
List<String> depTripleList = getDepTriples(doc);
int entCount = getEntityCount(doc);
String pt = getText(doc);
//Create instance to be added to training set
Instance tInst = new Instance(trainSet.numAttributes());
//Entity count
tInst.setValue( (Attribute) atts.elementAt(0), entCount);
//Generate Instances for relational attribute
relAttData = new Instances(trainSet.attribute(1).relation(), 0);
//For each deplist entry, create an instance and add it to dataset
for(String depTriple: depTripleList) {
Instance relAttInst = new Instance(1);
relAttInst.setDataset(relAttData);
relAttInst.setValue(0, depTriple);
relAttData.add(relAttInst);
}
//Add relational attribute (now filled with a number of Instances of attributes) to the main Instance
tInst.setValue( (Attribute) atts.elementAt(1), trainSet.attribute(1).addRelation(relAttData));
//Finally, add the instance to the relational attribute
trainSet.add(tInst)
}
//4. Output data
System.out.println(trainSet);
I realise this could probably be done differently, but this works well with my situation. Please keep in mind this is not my actual code, but an excerpt of multiple parts stitched together to demonstrate the process used to fix the problem.

JavaFX Tab positioning on mouse drag/drop

I have a Tabpane with multiple tabs.
I want to re-position tabs by just dragging them at a particular position(just like the way we are able to arrange tabs in browser.)
Is there any way i can achieve it?
We achieved it in a slightly different way.Instead of drag/drop feature we provided the move left/move right functionality on tab context menu which in turns moves the tab.
We wanted to have this feature on priority so implemented it with this workaround for now.
Code snippet for MoveRight:
public void moveRight() {
protected TabPane workBook;
int cTabIndex = bem.workBook.getTabs().indexOf(bem.activeSheet);
int tabCount = workBook.getTabs().size();
if (tabCount > 1 && cTabIndex > 0) {
workBook.getTabs().remove(bem.activeSheet);
workBook.getTabs().add(cTabIndex - 1, bem.activeSheet);
}
}
I've implemented a class that handles both draggable and detachable tabs - more details here. The implementation is not the tidiest, nor the most resilient but works pretty well for me in the simple cases I've tried so far. I've deliberately kept everything in the one class to make it easier for others to copy / use / modify as they see fit.
The basic concept that I'm using (arguably mis-using) is that the graphic you can set on a tab can be any node, not just an ImageView (or similar.) So instead of using the setText() on Tab directly, I'm not adding any text at all, just setting the graphic to be a Label containing the desired text. Now that the label is present in the tab header (and is pretty much the tab header spacially), that makes it much easier (and skin-independant) to grab the global co-ordinates of each tab header in the pane. From then it's just a case of some relatively simple positioning logic to work out when to detach tabs into a new window, when to re-add them and when to reorder them.
Of course, this isn't an ideal solution but unfortunately I haven't seen much else on the subject!
import java.util.HashSet;
import java.util.Set;
import javafx.collections.ListChangeListener;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
/**
* A draggable tab that can optionally be detached from its tab pane and shown
* in a separate window. This can be added to any normal TabPane, however a
* TabPane with draggable tabs must *only* have DraggableTabs, normal tabs and
* DrragableTabs mixed will cause issues!
* <p>
* #author Michael Berry
*/
public class DraggableTab extends Tab {
private static final Set<TabPane> tabPanes = new HashSet<>();
private Label nameLabel;
private Text dragText;
private static final Stage markerStage;
private Stage dragStage;
private boolean detachable;
static {
markerStage = new Stage();
markerStage.initStyle(StageStyle.UNDECORATED);
Rectangle dummy = new Rectangle(3, 10, Color.web("#555555"));
StackPane markerStack = new StackPane();
markerStack.getChildren().add(dummy);
markerStage.setScene(new Scene(markerStack));
}
/**
* Create a new draggable tab. This can be added to any normal TabPane,
* however a TabPane with draggable tabs must *only* have DraggableTabs,
* normal tabs and DrragableTabs mixed will cause issues!
* <p>
* #param text the text to appear on the tag label.
*/
public DraggableTab(String text) {
nameLabel = new Label(text);
setGraphic(nameLabel);
detachable = true;
dragStage = new Stage();
dragStage.initStyle(StageStyle.UNDECORATED);
StackPane dragStagePane = new StackPane();
dragStagePane.setStyle("-fx-background-color:#DDDDDD;");
dragText = new Text(text);
StackPane.setAlignment(dragText, Pos.CENTER);
dragStagePane.getChildren().add(dragText);
dragStage.setScene(new Scene(dragStagePane));
nameLabel.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
dragStage.setWidth(nameLabel.getWidth() + 10);
dragStage.setHeight(nameLabel.getHeight() + 10);
dragStage.setX(t.getScreenX());
dragStage.setY(t.getScreenY());
dragStage.show();
Point2D screenPoint = new Point2D(t.getScreenX(), t.getScreenY());
tabPanes.add(getTabPane());
InsertData data = getInsertData(screenPoint);
if(data == null || data.getInsertPane().getTabs().isEmpty()) {
markerStage.hide();
}
else {
int index = data.getIndex();
boolean end = false;
if(index == data.getInsertPane().getTabs().size()) {
end = true;
index--;
}
Rectangle2D rect = getAbsoluteRect(data.getInsertPane().getTabs().get(index));
if(end) {
markerStage.setX(rect.getMaxX() + 13);
}
else {
markerStage.setX(rect.getMinX());
}
markerStage.setY(rect.getMaxY() + 10);
markerStage.show();
}
}
});
nameLabel.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
markerStage.hide();
dragStage.hide();
if(!t.isStillSincePress()) {
Point2D screenPoint = new Point2D(t.getScreenX(), t.getScreenY());
TabPane oldTabPane = getTabPane();
int oldIndex = oldTabPane.getTabs().indexOf(DraggableTab.this);
tabPanes.add(oldTabPane);
InsertData insertData = getInsertData(screenPoint);
if(insertData != null) {
int addIndex = insertData.getIndex();
if(oldTabPane == insertData.getInsertPane() && oldTabPane.getTabs().size() == 1) {
return;
}
oldTabPane.getTabs().remove(DraggableTab.this);
if(oldIndex < addIndex && oldTabPane == insertData.getInsertPane()) {
addIndex--;
}
if(addIndex > insertData.getInsertPane().getTabs().size()) {
addIndex = insertData.getInsertPane().getTabs().size();
}
insertData.getInsertPane().getTabs().add(addIndex, DraggableTab.this);
insertData.getInsertPane().selectionModelProperty().get().select(addIndex);
return;
}
if(!detachable) {
return;
}
final Stage newStage = new Stage();
final TabPane pane = new TabPane();
tabPanes.add(pane);
newStage.setOnHiding(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
tabPanes.remove(pane);
}
});
getTabPane().getTabs().remove(DraggableTab.this);
pane.getTabs().add(DraggableTab.this);
pane.getTabs().addListener(new ListChangeListener<Tab>() {
#Override
public void onChanged(ListChangeListener.Change<? extends Tab> change) {
if(pane.getTabs().isEmpty()) {
newStage.hide();
}
}
});
newStage.setScene(new Scene(pane));
newStage.initStyle(StageStyle.UTILITY);
newStage.setX(t.getScreenX());
newStage.setY(t.getScreenY());
newStage.show();
pane.requestLayout();
pane.requestFocus();
}
}
});
}
/**
* Set whether it's possible to detach the tab from its pane and move it to
* another pane or another window. Defaults to true.
* <p>
* #param detachable true if the tab should be detachable, false otherwise.
*/
public void setDetachable(boolean detachable) {
this.detachable = detachable;
}
/**
* Set the label text on this draggable tab. This must be used instead of
* setText() to set the label, otherwise weird side effects will result!
* <p>
* #param text the label text for this tab.
*/
public void setLabelText(String text) {
nameLabel.setText(text);
dragText.setText(text);
}
private InsertData getInsertData(Point2D screenPoint) {
for(TabPane tabPane : tabPanes) {
Rectangle2D tabAbsolute = getAbsoluteRect(tabPane);
if(tabAbsolute.contains(screenPoint)) {
int tabInsertIndex = 0;
if(!tabPane.getTabs().isEmpty()) {
Rectangle2D firstTabRect = getAbsoluteRect(tabPane.getTabs().get(0));
if(firstTabRect.getMaxY()+60 < screenPoint.getY() || firstTabRect.getMinY() > screenPoint.getY()) {
return null;
}
Rectangle2D lastTabRect = getAbsoluteRect(tabPane.getTabs().get(tabPane.getTabs().size() - 1));
if(screenPoint.getX() < (firstTabRect.getMinX() + firstTabRect.getWidth() / 2)) {
tabInsertIndex = 0;
}
else if(screenPoint.getX() > (lastTabRect.getMaxX() - lastTabRect.getWidth() / 2)) {
tabInsertIndex = tabPane.getTabs().size();
}
else {
for(int i = 0; i < tabPane.getTabs().size() - 1; i++) {
Tab leftTab = tabPane.getTabs().get(i);
Tab rightTab = tabPane.getTabs().get(i + 1);
if(leftTab instanceof DraggableTab && rightTab instanceof DraggableTab) {
Rectangle2D leftTabRect = getAbsoluteRect(leftTab);
Rectangle2D rightTabRect = getAbsoluteRect(rightTab);
if(betweenX(leftTabRect, rightTabRect, screenPoint.getX())) {
tabInsertIndex = i + 1;
break;
}
}
}
}
}
return new InsertData(tabInsertIndex, tabPane);
}
}
return null;
}
private Rectangle2D getAbsoluteRect(Control node) {
return new Rectangle2D(node.localToScene(node.getLayoutBounds().getMinX(), node.getLayoutBounds().getMinY()).getX() + node.getScene().getWindow().getX(),
node.localToScene(node.getLayoutBounds().getMinX(), node.getLayoutBounds().getMinY()).getY() + node.getScene().getWindow().getY(),
node.getWidth(),
node.getHeight());
}
private Rectangle2D getAbsoluteRect(Tab tab) {
Control node = ((DraggableTab) tab).getLabel();
return getAbsoluteRect(node);
}
private Label getLabel() {
return nameLabel;
}
private boolean betweenX(Rectangle2D r1, Rectangle2D r2, double xPoint) {
double lowerBound = r1.getMinX() + r1.getWidth() / 2;
double upperBound = r2.getMaxX() - r2.getWidth() / 2;
return xPoint >= lowerBound && xPoint <= upperBound;
}
private static class InsertData {
private final int index;
private final TabPane insertPane;
public InsertData(int index, TabPane insertPane) {
this.index = index;
this.insertPane = insertPane;
}
public int getIndex() {
return index;
}
public TabPane getInsertPane() {
return insertPane;
}
}
}
I just found out that this has been implemented in JavaFX 10.
tabPane.tabDragPolicy = TabPane.TabDragPolicy.REORDER
...does the trick.
Update Feb 2016
There is an open feature request you can use to track implementation:
JDK-8092098 [TabPane] Support for draggable tabs
The feature request is currently scheduled for implementation in Java 9. Patches for obtaining drag and drop functionality are attached to the feature request.
Drag and Drop for tab headers is not implemented in the base JavaFX 2.2 platform.
Until that is implemented in the standard JDK, you will need to implement the feature yourself using JavaFX's Drag and Drop functionality. A similar feature is implemented for dragging table column headers, so perhaps you could look to the TableColumnHeader.java code for inspiration in implementing your feature.
Should you implement it (if you wish) you can contribute the modifications back to OpenJFX via patches to the TabSkin.java source.
A very descriptive answer can be found where you can create custom tabs for the same:
http://0divides0.wordpress.com/2010/10/21/movable-tabbed-panes-in-javafx/
A JavaFX cooked solution is hard to find as dev blog for the same states that such functionality is not present for Tabs and they plan to incorporate later.
http://grokbase.com/p/openjdk/openjfx-dev/123fq9k310/draggable-tabs
The following code shows how to solve the problem in a very simple way without tricks.
.....
.....
Tab tab1 = new Tab("Tab1");
Tab tab2 = new Tab("Tab21");
TabPane tabPane = new TabPane(tab1, tab21);
root.getChildren().add(tabPane);
....
....
System.out.println("Tabs size()= " + tabPane.lookupAll(".tab").size());
tabPane.lookupAll(".tab").forEach(t -> {
System.err.println("tab.bounds = " + t.getLayoutBounds());
});
You can get an access to other areas of TabPane by using style classes such as tab-content-area, tab-header-area, tab-header-background, headers-region, control-buttons-tab. Just use lookup or lookupAll methods of TabPane

Actionscript 3.0: Accessing Dynamic text from AS3 class to Game

I have here a bubble popping game where bubbles fall from top of the game to the bottom and the player tries to pop as many bubbles as possible in 30 seconds. It is a 3 frame game, 1st frame is the start button, 2nd frame is the game, 3rd frame is the score and play again.
1st frame: Buttons to go to the second frame
2nd Frame: timer to count 30 seconds of play time
3rd frame: buttons to play again.
ScoreValue is a dynamic textbox in the last frame of the game. It records the points based on size the size scale of the bubble, and should be change based on the amount of bubbles the player has popped.
scoreValue.text = score.toString();
Error 1120: Access of unidentified property scoreValue
Anyways here the full package of the code.
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.media.Sound;
import flash.geom.ColorTransform;
public class Ball extends MovieClip{
static public var burstCounter: uint;
private var vx: Number;
private var vy: Number;
private var gravity: Number;
private var stageWidth;
private var stageHeight;
private var bubble:Ball = new Ball();
private var score: uint=0;
public function Ball() {
bubble.addEventListener(Event.ADDED_TO_STAGE, initialize)
bubble.addEventListener(MouseEvent.CLICK, burst)
bubble.addEventListener(Event.ENTER_FRAME, dropping)
}
public function initialize (e:Event):void
{
bubble.x = Math.random() * stageWidth;
bubble.y = 0;
stageWidth = stage.stageWidth;
stageHeight = stage.stageHeight;
bubble.vx = Math.random() * 2 - 1;
bubble.vy = Math.random() * 2 + 1;
gravity = 0.1;
var sizeScale = Math.random() * 1.2 + .6;
bubble.scaleX = bubble.scaleY = sizeScale;
score = (10 / sizeScale);
scoreValue.text = score.toString();
var colorTran = new ColorTransform();
colorTran.color = Math.random() * 0xFFFFFF;
transform.colorTransform = colorTran;
addChild(bubble);
}
function dropping(e: Event) :void
{
x += vx;
y += vy;
vy += gravity;
if((x<0) || (x>stageWidth) || (y<0) || (y>stageHeight))
{
if(parent != null)
{
parent.removeChild(this);
}
removeEventListener(Event.ENTER_FRAME, dropping)
}
}
function burst (e:Event):void
{
var ballonPopping: Sound = new BalloonPopping();
bubble.removeEventListener(Event.ADDED_TO_STAGE, initialize);
bubble.removeEventListener(Event.ENTER_FRAME, dropping);
removeChild(bubble);
ballonPopping.play();
burstCounter += score;
}
}
}
Im getting this as output in my program, does any one know why?
Fonts should be embedded for any text that may be edited at runtime, other than text with the "Use Device Fonts" setting. Use the Text > Font Embedding command to embed fonts.
Thanks for your time.
you need to import the MouseEvent class to fix the 'Access undefined property of MouseEvent'
add this to your import statements:
import flash.events.MouseEvent;
Firstly, in a class, functions should be defined as public or private. Second, your burst function is expecting an Event while you are assigning a MouseEvent to it. Its an easy mistake that I use to often do.
Change it to:
private function burst (e:MouseEvent):void
The font thing in the output panel means you have a dynamic text field somewhere. Simply go to your FLA, open up that textfield and on the properties panel, hit the embed button and choose the Basic Latin checkbox...or numerals if its just numbers
edit: Also change your import to
import flash.events.*;
or add
import flash.events.MouseEvent;

Resources