i have a dialog to show some values. Now I need to know if the user has changed something.
All fields are wrapped in an eclipse DatabindingContext.
...
bindingContext.bindValue(process_observable_milage, process_bean_mileage, new UpdateValueStrategy(), null);
...
If I change some fields, the propertyChangeSupport listener inside the model gets fired. (Setter of the property is called).
this.firePropertyChange(SignalEntity.SIGNALNAME, this.signalname, this.signalname = name);
Now I need a global Listener to detect if any value was changed.
I tried it with the following without success:
IObservableValue globalValidity = new WritableValue();
globalValidity.addChangeListener(new IChangeListener() {
#Override
public void handleChange(ChangeEvent event) {
dirty = true;
}
});
bindingContext.bindValue(globalValidity, new AggregateValidationStatus(bindingContext.getBindings(), AggregateValidationStatus.MAX_SEVERITY), null, null);
This is from another class with some afterConvertValidators added.
So I thought I have to use "addValueChangeListener" instead but even this is not working.
IObservableValue globalValidity = new WritableValue();
globalValidity.addValueChangeListener(new IValueChangeListener() {
#Override
public void handleValueChange(ValueChangeEvent event) {
dirty = true;
}
});
bindingContext.bindValue(globalValidity, new AggregateValidationStatus(bindingContext.getBindings(), AggregateValidationStatus.MAX_SEVERITY), null, null);
Any ideas how to achieve this?
Best regards
I use:
IObservableValue setError = PojoProperties.value("error").observe(new SetError());
bindingContext.bindValue(setError, new AggregateValidationStatus(bindingContext.getBindings(), AggregateValidationStatus.MAX_SEVERITY));
private class SetError
{
public IStatus getError()
{
return ValidationStatus.ok();
}
public void setError(final IStatus status)
{
final String msg = status.isOK() ? null : status.getMessage();
// TODO deal with message / status
}
}
Related
I am building an app that will be submitting the details of your siblings to the database.
MY idea is since i dont know number of your children, i just have a floating button that am using to call a class that adds a contaner with some textFields to be filled.
so I have like a Form here....
private Button btnSubmit;
private Container cnt_box;
public class ChildrenForm extends Form
{
private List<Child> listofchildren;
public ChildrenForm()
{
super("CHILDREN DETAILS",BoxLayout.y());
FloatingActionButton fab=FloatingActionButton.createFAB(FontImage.MATERIAL_ADD);
fab.bindFabToContainer(this);
fab.addActionListener((e) -> addNewChild());
getToolbar().addMaterialCommandToRightBar("", FontImage.MATERIAL_CLEAR_ALL, (e) ->
clearAll());
btnSubmit=new Button("Submit");
cnt_box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
cnt_box.add(btnSubmit);
add(cnt_box);
}
//....here i have some other methods...
}
i have a method to enable the editing here....
public void edit()
{
txtname.startEditingAsync();
txtname3.startEditingAsync();
txtbirth.startEditingAsync();
txtdbirth.startEditingAsync();
}
the floatingAction Button calls this method here....
public void addNewChild()
{
Childdetails td=new Childdetails("","","","",false);
add(td);
revalidate();
td.edit();
}
that method now called this class which i want to take the details showing this container.....
public class Childdetails extends Container
{
private TextField txtname;
private TextField txtname3;
private TextField txtbirth;
private TextField txtdbirth;
private CheckBox done=new CheckBox();
private Container cnt_child;
public Childdetails(String name,String name3,String birthcertno,String dateofbirth ,boolean checked)
{
super(new BorderLayout());
cnt_child=new Container();
cnt_child.addComponent(new Label("First Name"));
txtname = new TextField(name);
txtname.setHint("First Name");
cnt_child.addComponent(txtname);
cnt_child.addComponent(new Label("Surname"));
txtname3 = new TextField(name3);
txtname3.setHint("Surname");
cnt_child.addComponent(txtname3);
cnt_child.addComponent(new Label("Birth Certificate/Notification No"));
txtbirth = new TextField(birthcertno);
txtbirth.setHint("Birth Certificate No:");
cnt_child.addComponent(txtbirth);
cnt_child.addComponent(new Label("Date of Birth"));
txtdbirth = new TextField(dateofbirth);
txtdbirth.setHint("dd/MM/yyyy");
cnt_child.addComponent(txtdbirth);
add(CENTER,cnt_child);
add(LEFT,done);
done.setSelected(checked);
}
public void edit()
{
txtname.startEditingAsync();
txtname3.startEditingAsync();
txtbirth.startEditingAsync();
txtdbirth.startEditingAsync();
}
public boolean isChecked(){
return done.isSelected();
}
public String getText(){
return txtname.getText();
}
}
this is the method which am using to delate any selected container....but i understand its because of that save method......
private void clearAll()
{
int cc=getContentPane().getComponentCount();
for(int i=cc-1; i>=0; i--)
{
Childdetails t=(Childdetails)getContentPane().getComponentAt(i);
if(t.isChecked())
{
t.remove();
}
}
save();
getContentPane().animateLayout(300);
}
the save method....which after following some tutorial i believe its saving the taken data.... here
private void save()
{
listofchildren = new ArrayList<>();
Childdetails detail=new Childdetails("","","","",false);
Child child=new Child()
.name.set(detail.getText())
.name3.set(detail.getText())
.birthcertno.set(detail.getText())
.dateofbirth.set(detail.getText())
.checked.set(detail.isChecked());
listofchildren.add(child);
PropertyIndex.storeJSONList("child.json", listofchildren);
}
i also have a class i constructed following certain tutorial to save the data.....here
public class Child implements PropertyBusinessObject
{
public final Property<String,Child> name=new Property<>("firstname","");
public final Property<String,Child> name3=new Property<>("Surname","");
public final Property<String,Child> birthcertno=new Property<>("BirthCertNo","");
public final Property<String,Child> dateofbirth=new Property<>("dateofbirth","");
public final BooleanProperty<Child> checked=new BooleanProperty<>("checked", false);
private final PropertyIndex idx=new PropertyIndex(this,"Todo", name, name3, birthcertno, dateofbirth, checked);
#Override
public PropertyIndex getPropertyIndex(){
return idx;
}
now my main main problem... i just want when that submit button is pressed, to send the filled details..... i tried this,,,
btnSubmit.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
Log.p("Button pressed", 1);
save();
Log.p("data saved...", 1);
if(existsInStorage("child.json"))
{
Log.p("loading data ...", 1);
listofchildren=new Child().getPropertyIndex().loadJSONList("child.json");
String NationalID=Storage.getInstance().readObject("NationalID").toString();
String UserName=Storage.getInstance().readObject("UserName").toString();
Hashtable hash=new Hashtable();
hash.put("ChildDet", listofchildren);
hash.put("ReadIdCopy", NationalID);
hash.put("UserName",UserName);
final Result res=Result.fromContent(hash);
final String checkthis=res.toString();
//--------check url......
String myUrl="http://localhost:50111/AddChildren";
String Reply="";
requestclass c=new requestclass();
try {
Reply=c.checking(checkthis,myUrl);
} catch (IOException ex) {
// Logger.getLogger(AddChildren.class.getName()).log(Level.SEVERE, null, ex);
} catch (requestclass.JSONException ex) {
// Logger.getLogger(AddChildren.class.getName()).log(Level.SEVERE, null, ex);
}
if(Reply.equals("SuccesfullyRecieved"))
{
Dialog.show("SuccesfullyRecieved", "Details Succesfuly Recieved", "OK", null);
/*----redirect---*/
nextofkin nkin=new nextofkin();
nkin.nxtofkscreen();
}
else if(Reply.equals("sorry"))
{
Dialog.show("SORRY!!!", "Seems their is a problem updating Next of kin details... try again", "OK", null);
}
else
{
Dialog.show("Error", "Something went wrong, try checking your connection and try again later.", "OK", null);
}
}
else
{
ToastBar.showErrorMessage("Sorry, no data to submit....");
}
}
});
i dont know how to do it,,,, also my save method has some errors...please help me out, thanks in advance
This is caused by this line:
Childdetails t=(Childdetails)getContentPane().getComponentAt(i);
What you are doing here is looping over all the components in the content pane and downcasting them to Childdetails.
This is bad. You don't check instanceof which would be helpful. You might have other problems but this line:
add(cnt_box);
Specifically adds a non Childdetails component to the content pane (doing add without a context on a Form implicitly adds to the content pane).
Also about startEditingAsync. This is wrong.
This isn't the way to make them visible.
Notice your code adds a lot of components before the form is shown and uses animateLayout on these instances. This is probably why things aren't visible since you do that on a Form that isn't shown yet (from the constructor) and so the animation "runs" without any effect. The components are probably in the wrong area.
I suggest removing that whole block of startEditingAsync and also try:
if(getContentPane().isInitialized()) {
getContentPane().animateLayout(300);
}
I have a custom dialog that is added to the scene and then removed again. Doing profiling with VisualVM, I noticed that even after a GC run the instance of this dialog is still retained.
I know that this means that there must be a reference to that object somewhere so I had a look at the references:
As seen in the image there are a lot of references from this$ which means inner classes, in this case they are bindings or ChangeListeners. The change listener can be replaced with WeakChangeListener. I'm not quite sure how I should handle the Bindings however.
Furthermore there are some references that do not make much sense at first glance:
bean of type SimpleStringProperty or SimpleObjectProperty
oldParent and value of type Node$1
So here are the concrete questions:
How to get around these strong references, so the object can actually be garbage collected? Would the use of lambda expressions instead of anonymous inner classes have any effect in this respect? How to figure out where the object is references by bean, oldParent and value.
EDIT1:
The bean references of type SimpleStringProperty are used in the super class and therefore should not cause an issue here, I guess. One SimpleObjectProperty bean reference comes from a utility method that provides an EventHandler. How would I resolve that, is there something similar for EventHandler as for ChangeListeners?
EDIT2:
I tried to come up with a simple application to reproduce the same thing. I could manage it and saw that I have basically the same fields listed in the heap dump, but then noticed that I have retained a reference to the component that is removed from the scene in my application. Once I let go of that reference it was cleaned up. The only noticeable difference is in my small example there is no reference in an Object array.
EDIT3:
I did some digging and found two places in the code that when commented out or not used, will not cause the object become eligible for garbage collection. The first one is this ChangeListener:
sailorState.numberOfSailorsProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue,
Number oldValue, Number newValue) {
int inTavern = newValue.intValue()-sailorsAdditionalOnShip.get();
if (inTavern < 0) {
sailorsAdditionalOnShip.set(Math.max(sailorsAdditionalOnShip.get() + inTavern, 0));
inTavern = 0;
}
sailorsInTavern.set(inTavern);
}
});
The second one is a bit more complex. The component is a Dialog that has a close button. On pressing that one the dialog closes. This is the code of the button, I do not think that with this part is the problem, but for completeness sake:
public class OpenPatricianButton extends Control {
protected final StringProperty text;
protected final ReadOnlyObjectProperty<Font> currentFont;
protected final ObjectProperty<EventHandler<MouseEvent>> onAction;
public OpenPatricianButton(String text,
final Font font) {
super();
this.text = new SimpleStringProperty(this, "text", text);
this.currentFont = new ReadOnlyObjectPropertyBase<Font>() {
#Override
public Object getBean() {
return this;
}
#Override
public String getName() {
return "currentFont";
}
#Override
public Font get() {
return font;
}
};
this.onAction = new SimpleObjectProperty<EventHandler<MouseEvent>>(this, "onAction");
this.getStyleClass().add(this.getClass().getSimpleName());
}
#Override
public String getUserAgentStylesheet() {
URL cssURL = getClass().getResource("/ch/sahits/game/javafx/control/"+getClass().getSimpleName()+".css");
return cssURL.toExternalForm();
}
public StringProperty textProperty() {
return text;
}
public String getText() {
return text.get();
}
public void setText(String text) {
this.text.set(text);
}
public Font getFont() {
return currentFont.get();
}
public ObjectProperty<EventHandler<MouseEvent>> onActionProperty() {
return onAction;
}
public EventHandler<MouseEvent> getOnAction() {
return onAction.get();
}
public void setOnAction(EventHandler<MouseEvent> onAction) {
this.onAction.set(onAction);
}
}
public class OpenPatricianSmallWaxButton extends OpenPatricianButton {
public OpenPatricianSmallWaxButton(String text,
final Font font) {
super(text, font);
}
#Override
protected Skin<?> createDefaultSkin() {
return new OpenPatricianSmallWaxButtonSkin(this);
}
public OpenPatricianSmallWaxButton(String text) {
this(text, Font.getDefault());
}
}
public class OpenPatricianSmallWaxButtonSkin extends SkinBase<OpenPatricianSmallWaxButton> {
public OpenPatricianSmallWaxButtonSkin(final OpenPatricianSmallWaxButton button) {
super(button);
InputStream is = getClass().getResourceAsStream("sealingWaxFlattend.png");
Image img = new Image(is);
final ImageView imageView = new ImageView(img);
final Label label = new Label();
label.textProperty().bind(button.textProperty());
label.getStyleClass().add("OpenPatricianSmallWaxButtonLabeled");
label.setFont(button.getFont());
label.onMouseClickedProperty().bind(button.onActionProperty());
label.textProperty().bind(button.textProperty());
imageView.onMouseReleasedProperty().bind(button.onActionProperty());
StackPane stack = new StackPane();
stack.getChildren().addAll(imageView, label);
Group group = new Group(stack);
group.setManaged(false);
button.setPrefHeight(img.getHeight());
button.setPrefWidth(img.getWidth());
getChildren().add(group);
}
}
And here is the code fragment where the button is instantiated:
closeButton = new OpenPatricianSmallWaxButton("X", font);
closeButton.setLayoutX(WIDTH - CLOSE_BUTTON_WIDTH - CLOSE_BUTTON_PADDING);
closeButton.setLayoutY(CLOSE_BTN_Y_POS);
closeButton.setOnAction(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
executeOnCloseButtonClicked();
}
});
closeButton.getStyleClass().add("buttonLabel");
getContent().add(closeButton);
The call to remove the button is done through Guava AsyncEventBus. Therefore the code is a bit length. It starts in the Application thread and then gets posted to the event bus thread which then eventually has to call Platform.runLater:
protected void executeOnCloseButtonClicked() {
ViewChangeEvent event = new ViewChangeEvent(MainGameView.class, EViewChangeEvent.CLOSE_DIALOG);
clientEventBus.post(event);
}
public void handleViewChange(ViewChangeEvent event) {
if (event.getAddresse().equals(MainGameView.class)) {
if (event.getEventNotice() instanceof DialogTemplate) {
setNewDialog((DialogTemplate) event.getEventNotice());
} else {
sceneEventHandlerFactory.getSceneEventHandler().handleEvent(event.getEventNotice());
}
}
}
public void handleEvent(Object eventNotice) {
Preconditions.checkNotNull(dialogContoller, "Dialog controller must be initialized first");
if (eventNotice == EViewChangeEvent.CLOSE_DIALOG) {
dialogContoller.closeDialog();
}
....
public void closeDialog() {
if (Platform.isFxApplicationThread()) {
closeDialogUnwrapped();
} else {
Platform.runLater(() -> closeDialogUnwrapped());
}
}
private void closeDialogUnwrapped() {
if (dialog != null) {
new Exception("Close dialog").printStackTrace();
getChildren().remove(dialog);
dialog = null;
dialogScope.closeScope();
}
}
The really peculiar thing is that the dialog can be cleaned up by the GC (provided the first issue with the ChangeListener is commented out) when I call closeDialog from a timer. In other words this behaviour does only happen if I close the dialog with a mouse click.
I want to use a custom control (ClientControl in the code) in my TableView. Therefore I created a class ClientCell:
public class NewClientCell extends TableCell<Client, Client> {
private final ClientControl cc;
public NewClientCell(ObservableList<Client> suggestions) {
cc = new ClientControl(this.getItem(), suggestions);
this.setAlignment(Pos.CENTER_LEFT);
this.setGraphic(cc);
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Client c, boolean empty) {
super.updateItem(c, empty);
if(!empty){
setGraphic(cc);
}
}
}
In the main program I use the following code to fill the table:
TableColumn<Client, Client> clmClients = new TableColumn<>("Klient");
clmClients.setCellFactory(new Callback<TableColumn<Client, Client>, TableCell<Client, Client>>() {
#Override
public TableCell<Client, Client> call(TableColumn<Client, Client> p) {
return new NewClientCell(suggestions);
};
});
clmClients.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Client, Client>, ObservableValue<Client>>() {
#Override
public ObservableValue<Client> call(TableColumn.CellDataFeatures<Client, Client> p) {
return new SimpleObjectProperty<Client>(p.getValue());
}
});
getColumns().add(clmClients);
The data in the table comes from an ObservableList and is initialized correct.
My problem now is that the custom control needs an Client-Object which it should get out of the ObservableList, but "this.getItem()" always returns null.
How do I get the Client objects correctly into the custom control?
Thanks!
EDIT
Here's the constructor of ClientControl:
public ClientControl(Client client, ObservableList<Client> suggestions) {
setClient(client);
setSuggestions(suggestions);
FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientControl.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
initTextField();
setLabelText(client.toString());
}
The method setClient is a simple setter method (this.client = client;). The variables client and suggestions are this simple defined:
private ObservableList<Client> suggestions;
private Client client;
AFAIK, you should instantiate any controls in the constructor as you did, so that they are only created once (remember that cells get reused for different locations).
But then you need to override one or more of the other methods such as updateItem to get the data from the current item to render.
EDIT
Well, you're assigning the same control without changing it over and over again. Rather than setting the graphics in the updateItem method, set the item property of the client control:
#Override
protected void updateItem(Client c, boolean empty) {
super.updateItem(c, empty);
if(!empty){
cc.setClient(c);
} else {
cc.setClient(null);
}
}
Edit 2
The ClientControl should provide the client item as a property instead of a constructor argument and set it in the updateItem method, not in the constructor.
E.g. something like this (untested!):
private final ObjectProperty<Client> client = new SimpleObjectProperty<>(this, "client");
public final Client getClient(){
return clientProperty().get();
}
public final void setClient(Client client){
clientProperty().set(client);
}
public ObjectProperty<Client> clientProperty(){
return client;
}
And in the constructor: listen for changes of this property to set the labelText etc.
You also might want to provide a constructor without a client argument, as it is not available when you instantiate it in the TableCell constructor.
So I found the solution for my problem. Thank you so much Puce for your help! :-)
Now I set Client via the property like that:
private ObjectProperty<Client> clientProperty = new SimpleObjectProperty<Client>();
Additionally I added a ChangeListener in the constructor of ClientControl:
public ClientControl(ObservableList<Client> suggestions) {
clientProperty.addListener(new ChangeListener<Client>() {
#Override
public void changed(ObservableValue<? extends Client> observable, Client oldValue,
ClientnewValue) {
if(newValue != null) {
setLabelText(newValue.toString());
}
}
});
setSuggestions(suggestions);
FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientControl.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
initTextField();
}
My ClientCell class needed only some simple changes because of the changes in ClientControl:
public class NewClientCell extends TableCell<Client, Client> {
private final ClientControl cc;
public NewClientCell(ObservableList<Client> suggestions) {
cc = new ClientControl(suggestions);
this.setAlignment(Pos.CENTER_LEFT);
this.setGraphic(cc);
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
protected void updateItem(Client c, boolean empty) {
super.updateItem(c, empty);
if(!empty){
cc.setClient(c);
}
}
}
In the main program nothing changed.
In conclusion I would like to thank Puce one more time, I stuck at this problem for many days...
I'm developing a Vaadin application. Now, I have a trouble with a BeanItemContainer. I have a few items inside my container.
private void populateTable() {
tableContainer.removeAllItems();
for(MyBean myBean : beans){
tableContainer.addItem(myBean);
}
}
When I select the item in the table, I bind the item selected with the binder and I fill the form automatically
table.addItemClickListener(new ItemClickListener() {
public void itemClick(ItemClickEvent event) {
myBean = ((BeanItem<MyBean>) event.getItem()).getBean();
//BeanFieldGroup<MyBean>
binder.setItemDataSource(myBean);
}
});
private Component makeForm() {
formLayout = new FormLayout();
binder.bind(comboBoxModPag,"modPagamento");
binder.bind(fieldInizioVal, "id.dInizioVal");
formLayout.addComponent(comboBoxModPag);
formLayout.addComponent(fieldInizioVal);
formLayout.addComponent(binder.buildAndBind(getI18NMessage("dValidoAl"), "dValidoAl", DateField.class));
return formLayout;
}
Now, I have to manage the user interactions in a different way. For example, if the user modify the value inside the combobox, I have to add a new Bean in the container, while if the users modify the value of the field fieldInizioVal I have to update the current Bean.
insertOrUpdateButton.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
tableContainer.addItem(myBean));
}
});
But, when add a new Item, the container adds the new item correctly but modify also the old item selected.
How can I do?
I solved in this way
comboBoxModPag.addValueChangeListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
MyBean oldValue = (MyBean) comboBoxModPag.getOldValue();
MyBean newValue = (MyBean) comboBoxModPag.getValue();
if( oldValue!=null && newValue!=null && !oldValue.equals(newValue) ){
insertMode = true;
}
else{
insertMode = false;
}
}
}
});
protected void saveOrUpdateModPagContrattoSito() {
if(insertMode){
MyBean newMyBean = new MyBean(myBean);
//Do somethings to restore myBean statuse
//....
//....
tableContainer.addBean(newMyBean);
}
else{
tableContainer.addBean(myBean);
}
table.refreshRowCache();
}
But I don't know if this is the correct way.
I want to remove a GWT event handler the first time I receive an event. I also want to avoid polluting my class with tracking registration objects that aren't really necessary. I currently have it coded as:
final HandlerRegistration[] registrationRef = new HandlerRegistration[1];
registrationRef[0] = dialog.addFooHandler(new FooHandler()
{
public void onFoo(FooEvent event)
{
HandlerRegistration removeMe = registrationRef[0];
if(removeMe != null)
{
removeMe.removeHandler();
}
// do stuff here
}
});
but the use of registrationRef makes the code less readable. Is there a better way to do this without adding variables to my class?
I'd just make the HandlerRegistration object a field of the enclosing class, that way you won't be bothered by the compiler and it's more "elegant" than shuffling arrays and stuff:
public class TestWidget extends Composite {
//...
HandlerRegistration handler;
public TestWidget() {
// ...
handler = button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
// ...
handler.removeHandler();
}
});
}
}