I have a custom object FermentableInRecipe, which populates a TableView. In order to respond to changes to items in the list, as well as the list itself, I have decided to employ an extractor. Here is my declaration and instantiation of my ObservableList:
private ObservableList<FermentableInRecipe> fermentablesInRecipe =
FXCollections.observableArrayList(item -> new Observable[]{item.WeightProperty()});
Here are the relevant segments of my custom class:
public class FermentableInRecipe {
private DoubleProperty weight;
...
public Double getWeight() {
return this.weight.getValue();
}
public void setWeight(Double value) {
this.weight.setValue(value);
}
public DoubleProperty WeightProperty() {
if (weight == null) {
weight = new SimpleDoubleProperty(0.0);
}
return weight;
}
...
}
In the links I've provided below, this approach worked. But Netbeans is telling me "DoubleProperty cannot be converted to Observable". I can see why this is the case, but I cannot understand why it worked in the links below and not for me, and how I should create extractor and link it to the weightProperty() function if this approach doesn't work.
Links:
JavaFX 2.0 Choice Box Issue. How to update a choiceBox, which represents a list of objects, when an object is updated?
JavaFX, ObservableList: How to fire an InvalidationListener whenever an object of the list gets modified?
Thanks in advance. Let me know if I've missed any crucial information.
There's nothing wrong with your code as written, this compiles just fine for me:
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
public class JavaFXApplication1 extends Application {
class FermentableInRecipe {
private DoubleProperty weight;
public Double getWeight() {
return this.weight.getValue();
}
public void setWeight(Double value) {
this.weight.setValue(value);
}
public DoubleProperty WeightProperty() {
if (weight == null) {
weight = new SimpleDoubleProperty(0.0);
}
return weight;
}
}
private ObservableList<FermentableInRecipe> fermentablesInRecipe = FXCollections.observableArrayList(item -> new Observable[]{item.WeightProperty()});
#Override
public void start(Stage primaryStage) throws Exception {
}
}
I'd suggest double checking imports, and make sure you haven't imported java.util.Observable or similar by mistake.
Related
I have a ChoiceBox where I can select the language for my program. When I select another language, the label gets translated as desired (because it is recomputed using ChoiceBoxSkin#getDisplayText and my StringConverter takes the language into account), but the elements in the popup list stay the same.
Now, I could do something like
public void updateStrings() {
var converter = getConverter();
setConverter(null);
setConverter(converter);
var selected = valueProperty().getValue();
valueProperty().setValue(null);
valueProperty().setValue(selected);
}
in my ChoiceBox-subclass. This will re-populate the popup list with the correctly translated texts. Setting the value again is necessary beacause ChoiceBoxSkin#updatePopupItems (which is triggered when changing the converter) also resets the toggleGroup. That means that the selected item would no longer be marked as selected in the popup list.
Despite being kind of ugly, this actually works for my current use case. However, it breaks if any listener of the valueProperty does something problematic on either setting it to null or selecting the desired item a second time.
Am I missing a cleaner or just all-around better way to achieve this?
Another approach might be to use a custom ChoiceBoxSkin. Extending that, I'd have access to ChoiceBoxSkin#getChoiceBoxPopup (although that is commented with "Test only purpose") and could actually bind the text properties of the RadioMenuItems to the corresponding translated StringProperty. But that breaks as soon as ChoiceBoxSkin#updatePopupItems is triggered from anywhere else...
A MRP should be:
import javafx.scene.control.ChoiceBox;
import javafx.util.StringConverter;
public class LabelChangeChoiceBox extends ChoiceBox<String> {
private boolean duringUpdate = false;
public LabelChangeChoiceBox() {
getItems().addAll("A", "B", "C");
setConverter(new StringConverter<>() {
#Override
public String toString(String item) {
return item + " selected:" + valueProperty().getValue();
}
#Override
public String fromString(String unused) {
throw new UnsupportedOperationException();
}
});
valueProperty().addListener((observable, oldValue, newValue) -> {
if(duringUpdate) {
return;
}
duringUpdate = true;
updateStrings();
duringUpdate = false;
});
}
public void updateStrings() {
var converter = getConverter();
setConverter(null);
setConverter(converter);
var selected = valueProperty().getValue();
valueProperty().setValue(null);
valueProperty().setValue(selected);
}
}
And an Application-class like
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import ui.LabelChangeChoiceBox;
public class Launcher extends Application {
#Override
public void start(Stage stage) {
Scene scene = new Scene(new LabelChangeChoiceBox());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
This works but needs the duringUpdate variable and can break if there is another change listener.
I’m not sure if this meets your needs, as your description of the problem is unclear in a few places.
Here’s a ChoiceBox which updates its converter using its own chosen language, and also retains its value when that change occurs:
import java.util.Locale;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.layout.BorderPane;
import javafx.util.StringConverter;
public class FXLocaleSelector
extends Application {
#Override
public void start(Stage stage) {
ChoiceBox<Locale> choiceBox = new ChoiceBox<>();
choiceBox.getItems().addAll(
Locale.ENGLISH,
Locale.FRENCH,
Locale.GERMAN,
Locale.ITALIAN,
Locale.CHINESE,
Locale.JAPANESE,
Locale.KOREAN
);
choiceBox.converterProperty().bind(
Bindings.createObjectBinding(
() -> createConverter(choiceBox.getValue()),
choiceBox.valueProperty()));
BorderPane pane = new BorderPane(choiceBox);
pane.setPadding(new Insets(40));
stage.setScene(new Scene(pane));
stage.setTitle("Locale Selector");
stage.show();
}
private StringConverter<Locale> createConverter(Locale locale) {
Locale conversionLocale =
(locale != null ? locale : Locale.getDefault());
return new StringConverter<Locale>() {
#Override
public String toString(Locale value) {
if (value != null) {
return value.getDisplayName(conversionLocale);
} else {
return "";
}
}
#Override
public Locale fromString(String s) {
return null;
}
};
}
public static void main(String[] args) {
launch(FXLocaleSelector.class, args);
}
}
Not entirely certain whether or not I understand your requirement correctly, my assumptions:
there's a ChoiceBox which contains the "language" for your ui, including the itself: lets say it contains the items Locale.ENGLISH and Locale.GERMAN, the visual representation of its items should be "English", "German" if its value is Locale.ENGLISH and "Englisch", "Deutsch" if its value is Locale.GERMAN
the visual representation is done by a StringConverter configurable with the value
If so, the solution is in separating out concerns - actually, it's not: the problem described (and hacked!) in the question is JDK-8088507: setting the converter doesn't update the selection of the menu items in the drop down. One hack is as bad or good as another, my personal preferenced would go for a custom skin which
adds a change listener to the converter property
reflectively calls updateSelection
Something like:
public static class MyChoiceBoxSkin<T> extends ChoiceBoxSkin<T> {
public MyChoiceBoxSkin(ChoiceBox<T> control) {
super(control);
registerChangeListener(control.converterProperty(), e -> {
// my local reflection helper, use your own
FXUtils.invokeMethod(ChoiceBoxSkin.class, this, "updateSelection");
});
}
}
Note: the hacks - this nor the OP's solution - do not solve the missing offset of the popup on first opening (initially or after selecting an item in the popup).
Not a solution to the question, just one way to have a value-dependent converter ;)
have a StringConverter with a fixed value (for simplicity) for conversion
have a converter controller having that a property with that value and a second property with a converter configured with the value: make sure the converter is replaced on change of the value
bind the controller's value to the box' value and the box' converter to the controller's converter
In (very raw) code:
public static class LanguageConverter<T> extends StringConverter<T> {
private T currentLanguage;
public LanguageConverter(T language) {
currentLanguage = language;
}
#Override
public String toString(T object) {
Object value = currentLanguage;
return "" + object + (value != null ? value : "");
}
#Override
public T fromString(String string) {
return null;
}
}
public static class LanguageController<T> {
private ObjectProperty<StringConverter<T>> currentConverter = new SimpleObjectProperty<>();
private ObjectProperty<T> currentValue = new SimpleObjectProperty<>() {
#Override
protected void invalidated() {
currentConverter.set(new LanguageConverter<>(get()));
}
};
}
Usage:
ChoiceBox<String> box = new ChoiceBox<>();
box.getItems().addAll("A", "B", "C");
box.getSelectionModel().selectFirst();
LanguageController<String> controller = new LanguageController<>();
controller.currentValue.bind(box.valueProperty());
box.converterProperty().bind(controller.currentConverter);
this is my first question here so bear with me please.
I'm trying to use the Oracle Java docs, but when I try to compile example 6 on this page it doesn't work. I've tried everything I can think of. It's an old example, so that may be the issue, but it's disheartening that I can't figure out what should be a minor problem.
Example 6 Using an InvalidationListener
package bindingdemo;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.binding.NumberBinding;
import javafx.beans.binding.Bindings;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
class Bill {
// Define the property
private DoubleProperty amountDue = new SimpleDoubleProperty();
// Define a getter for the property's value
public final double getAmountDue(){return amountDue.get();}
// Define a setter for the property's value
public final void setAmountDue(double value){amountDue.set(value);}
// Define a getter for the property itself
public DoubleProperty amountDueProperty() {return amountDue;}
}
public class Main {
public static void main(String[] args) {
Bill bill1 = new Bill();
Bill bill2 = new Bill();
Bill bill3 = new Bill();
NumberBinding total = Bindings.add(bill1.amountDueProperty().add(bill2.amountDueProperty()),
bill3.amountDueProperty());
total.addListener(new InvalidationListener() {
#Override public void invalidated(Observable o) {
System.out.println("The binding is now invalid.");
}
});
// First call makes the binding invalid
bill1.setAmountDue(200.00);
// The binding is now invalid
bill2.setAmountDue(100.00);
bill3.setAmountDue(75.00);
// Make the binding valid...
System.out.println(total.getValue());
// Make invalid...
bill3.setAmountDue(150.00);
// Make valid...
System.out.println(total.getValue());
}
}
Thanks
I am trying to add sentiment analysis program to Spark pipeline. When doing it, I have class which extends org.apache.spark.ml.PredictionModel. When extending this PredictionModel class, I have to override predict() method which predicts the label for given feature. But, I get either 0 or 1 all the time when I execute this code.For example, if there are 10 movie reviews, five are negative reviews and other five are negative, it classifies all reviews as negative. I have attached the code below.
import org.apache.spark.ml.PredictionModel;
import org.apache.spark.ml.param.ParamMap;
import org.apache.spark.mllib.linalg.DenseVector;
import org.apache.spark.mllib.linalg.Vector;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.nd4j.linalg.api.buffer.DataBuffer;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import java.io.*;
//Model produced by a ProbabilisticClassifier
public class MovieReviewClassifierModel extends PredictionModel<Object, MovieReviewClassifierModel> implements Serializable{
private static final long serialVersionUID = 1L;
private MultiLayerNetwork net;
MovieReviewClassifierModel (MultiLayerNetwork net) throws Exception {
this.net=net;
}
#Override
public MovieReviewClassifierModel copy(ParamMap args0) {
return null;
}
#Override
public String uid() {
return "MovieReviewClassifierModel";
}
public double raw2prediction(Vector rawPrediction) {//Given a vector of raw predictions, select the predicted label
return rawPrediction.toArray()[0];
}
#Override
public double predict(Object o) {
int prediction=0;
DenseVector v=(DenseVector)o;
double[] a=v.toArray();
INDArray arr=Nd4j.create(a);
INDArray array= net.output(arr,false);
DataBuffer ob = array.data();
double[] d=ob.asDouble();
double zeroProbability=d[0];
double oneProbability=d[1];
if (zeroProbability > oneProbability) {
prediction=0;
}
else{
prediction=1;
}
return prediction;
}
}
Can you give me reasons for the wrong predictions?
In public double predict(Object o) you have a following if statement:
if (zeroProbability > oneProbability) {
prediction=0;
}
else{
prediction=1;
}
which causes the return of 0 or 1. Change this method in order to have some other prediction values.
I have a code in javafx like this,
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author deb-l-ana
*/
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
Group root=new Group();
Scene scene=new Scene(root,500,500,true);
int ctr=0;
Button b1=new Button("b1");
b1.setTranslateX(90);
root.getChildren().add(b1);
b1.setOnAction(e -> {
ctr=1;
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
This gives me a compilation error
Local variables referenced from a lambda expression must be final or effectively final
But if I declare ctr as final I cannot modify it. What can I do so that I can modify a local variable from a lambda expression? But if I use an array, ctr1[]={0} with a single element and then I could reference it from the lambda expression and this works fine.
Why is this happening and how can I update the value of ctr from a mouse click event?
I can't explain better than him : https://stackoverflow.com/a/12750186/5677103
"An Integer is immutable [...] but you can design your own class to embed an integer and use it instead of an Integer."
public class MutableInteger {
private int value;
public MutableInteger(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
An instance of a final object can't be modified, but his attributes can be. Moreover, int is a privitive type and Integer an object that wraps this type.
I wanted to add simple getters and setters on a class that implements VertexFrame and I used JavaHandlers for those. For those methods I didn't want to have any interaction with the database. Unfortunately there is not something like #Ignore so I don't have unexpected annotation exceptions. When I set something on the proxy and immediately I do a get after it goes through reflection, nothing is stored. Could be that I shouldn't be using JavaHandlers but something else.. Btw manager.frame returns Java Dynamic Proxy objects (java.lang.reflect.Proxy). Here is the failing test:
package com.tests.testbed;
import org.springframework.util.Assert;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory;
import com.tinkerpop.frames.FramedGraph;
import com.tinkerpop.frames.FramedGraphFactory;
import com.tinkerpop.frames.modules.javahandler.JavaHandlerModule;
public class testProxy {
public static void main(String args[]){
TinkerGraph graph = TinkerGraphFactory.createTinkerGraph();
FramedGraphFactory framedFactory = new FramedGraphFactory(new JavaHandlerModule());
FramedGraph<TinkerGraph> manager = framedFactory.create(graph);
Vertex vertex = manager.getVertex(1);
IVert vert = manager.frame(vertex, IVert.class);
int testVal = 231;
vert.setTestVar(231);
Assert.state(vert.getTestVar() != testVal, "int was not stored!");
}
}
---------------------
package com.tests.testbed;
import com.tinkerpop.frames.Property;
import com.tinkerpop.frames.VertexFrame;
import com.tinkerpop.frames.modules.javahandler.JavaHandler;
import com.tinkerpop.frames.modules.javahandler.JavaHandlerClass;
#JavaHandlerClass(Vert.class)
public interface IVert extends VertexFrame {
#Property("id")
public int getId();
#Property("id")
public void setId(int id);
#JavaHandler
public void setTestVar(int testVar);
#JavaHandler
public int getTestVar();
}
--------------------
package com.tests.testbed;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
import com.tinkerpop.blueprints.impls.tg.TinkerGraphFactory;
public class Vert implements IVert {
private Vertex vertex;
private int id;
private int testVar;
public void setTestVar(int testVar){
this.testVar = testVar;
}
public int getTestVar(){
return this.testVar;
}
#Override
public Vertex asVertex() {
if (this.vertex == null){
TinkerGraph graph = TinkerGraphFactory.createTinkerGraph();
Vertex v = graph.getVertex(this.getId());
this.vertex = v;
}
return this.vertex;
}
#Override
public int getId() {
return this.id;
}
#Override
public void setId(int id) {
this.id = id;
}
}
Thank you very much.
P.S I have already added this as an issue in case it is a bug: https://github.com/tinkerpop/frames/issues/109
I tried getting the TargetObject but I couldn't. Please let me know if there is any solution for adding non-database data that can persist on Proxies.
You've gone wrong in a couple of places, first of all:
Property key is reserved for all elements: id
Basically you can't use the property value "id" in your #Property("id") annotations.
Secondly, although it doesn't fail, your Vert class should:
implement JavaHandlerContext<Vertex>
be abstract
persist values using the Vertex's properties (local variables are NOT stored in the graph db!)
only implement/override the methods annotated with #JavaHandler
Additionally, you don't need to store the Vertex. Because your IVert interface extends VertexFrame, you have access to the Vertex using the asVertex() method.
You should definitely re-read the documentation, refer to the examples - https://github.com/tinkerpop/frames/wiki/Java-Handler
Here are the re-written/working classes. N.B. I was using Groovy - it should be exactly the same/very similar for Java.
IVert
#JavaHandlerClass(Vert.class)
public interface IVert extends VertexFrame {
#Property("xxid")
public int getId();
#Property("xxid")
public void setId(int id);
#JavaHandler
public void setTestVar(int testVar);
#JavaHandler
public int getTestVar();
}
Vert
abstract class Vert implements JavaHandlerContext<Vertex>, IVert {
public void setTestVar(int testVar){
asVertex().setProperty('foobar', testVar);
}
public int getTestVar(){
return (int)asVertex().getProperty('foobar');
}
}
Main method (Groovy)
def g = TinkerGraphFactory.createTinkerGraph()
FramedGraphFactory factory = new FramedGraphFactory(new JavaHandlerModule())
FramedGraph framedGraph = factory.create(g)
IVert vert = framedGraph.addVertex('myuniqueid', IVert)
vert.setId(123)
vert.setTestVar(456)
IVert vert2 = framedGraph.getVertex('myuniqueid', IVert)
assert vert2.id == 123
assert vert2.testVar == 456