JavaFX 8 How to pass and use a reference to a method that doesn't return a value? - combobox

I'm trying to pass and use a method reference to another method. The reference is to a setter in a TableView's model class that accepts a String input parameter and doesn't return a value.
In my FMXL controller, I'm dynamically creating table columns that contain Combo Boxes. The code is based on James_D's solution here: Java FX ComboBoxTableCell Show In Every Cell. I pass the method reference as follows:
TableColumn<TestModel, DBComboChoice> colComboBoxField = DAOGenUtil.createComboBoxColumn
("ComboBox Field",
TestModel::comboBoxFieldProperty, //this one works
TestModel::setComboBoxField, //this one doesn't work
comboData);
I'm stuck in two places in the createComboBoxColumn method - in the method declaration and in the setOnAction.
public <S> TableColumn<S, DBComboChoice> createComboBoxColumn(String title,
Function<S, StringProperty> methodGetComboFieldProperty,
//==> <WHAT-GOES-HERE?> methodSetComboField,
ObservableList<DBComboChoice> comboData ) {
TableColumn<S, DBComboChoice> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> {
String masterCode = methodGetComboFieldProperty.apply(cellData.getValue()).get();
DBComboChoice choice = DBComboChoice.getDescriptionByMasterCode(masterCode, comboData);
return new SimpleObjectProperty<>(choice);
});
col.setCellFactory((TableColumn<S, DBComboChoice> tablecol) -> {
ComboBox<DBComboChoice> combo = new ComboBox<>();
combo.getItems().addAll(comboData);
TableCell<S, DBComboChoice> cell = new TableCell<S, DBComboChoice>() {
#Override
protected void updateItem(DBComboChoice choice, boolean empty) {
super.updateItem(choice, empty);
if (empty) {
setGraphic(null);
} else {
combo.setValue(choice);
setGraphic(combo);
}
}
};
combo.setOnAction((ActionEvent event) -> {
String masterCode = combo.getSelectionModel().getSelectedItem().getMasterCode();
//==> col.getTableView().getItems().get(cell.getIndex()).<AND-HOW-DO-I-USE-IT-TO-SET-THE-DATA-MODEL'S-FIELD-TO-masterCode?>
});
return cell ;
});
return col;
}
When I tried Function<S, Void> methodSetComboField, I got an error in the FXML controller ("method createComboBoxColumn in class DAOGenUtil cannot be applied to given types"). BiConsumer<S, String> methodSetComboField didn't generate an error but I couldn't figure out how to use it in the setOnAction.
Can anyone help please? I'm using JavaFX8, NetBeans 8.2 and Scene Builder 8.3.
DBComboChoice is a class that contains a masterCode and a masterDescription eg. "F" for "Female", "M" for "Male". The masterCode is stored in the TableView's model. The masterDescription is shown in the ComboBox. I'm loading the values from a database master table.
Here are the relevant bits from the TableView's data model class:
public class TestModel {
//...
public String getComboBoxField() {
return comboBoxField.get();
}
public void setComboBoxField(String comboBoxField) {
this.comboBoxField.set(comboBoxField);
}
public StringProperty comboBoxFieldProperty() {
return comboBoxField;
}
//...
}

Let's take a look at the signature available:
void setComboBoxField(String)
since you don't want to specify the instance but use TestModel::setComboBoxField, you need a functional interface with a method that accepts 2 parameters: TestModel and String. You could create such an interface yourself easily
#FunctionalInterface
public interface MyInterface<S, T> {
void call(S s, T t);
}
public <S> TableColumn<S, DBComboChoice> createComboBoxColumn(String title,
Function<S, StringProperty> methodGetComboFieldProperty,
MyInterface<? super S, ? super String> methodSetComboField,
ObservableList<DBComboChoice> comboData )
Or use the existing interface BiConsumer:
public <S> TableColumn<S, DBComboChoice> createComboBoxColumn(String title,
Function<S, StringProperty> methodGetComboFieldProperty,
BiConsumer<? super S, ? super String> methodSetComboField,
ObservableList<DBComboChoice> comboData ) {
...
methodSetComboField.accept(col.getTableView().getItems().get(cell.getIndex()), masterCode);
...
}

Related

How do I create a JavaFX 8 ComboBox which can bind to a field on a seperate POJO

I have had a challenge finding anything on the following situation. Let's say I have a record called DatabaseRecord which is a POJO with several fields:
public class DatabaseRecord {
private Long recordId;
private StringProperty foreignKeyId;
private StringProperty otherValuesForMainRecord....
... setters/getters
public class LookUpDataValue {
private String recordId;
private String descriptiveText;
private String otherValues.....
....
I have a combo box which displays the selectable values for the foreignKeyId value something like this:
#FXML
ComboBox<LookUpDataValue> combobox;
combobox.setCellFactory
(new Callback<ListView<LookUpDataValue>, ListCell<LookUpDataValue>>() {
#Override
public ListCell<LookUpDataValue> call(ListView<LookUpDataValue> p) {
ListCell<LookUpDataValue> cell = new ListCell<LookUpDataValue>() {
#Override
protected void updateItem(LookUpDataValue item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText("");
} else {
setText(item.getDescriptiveText());
}
}
};
return cell;
}
});
I would like to Bidirectionally bind the POJO DatabaseRecord.foreignKeyIdProperty to the combobox.valueProperty() - but this doesn't work since one is a string and one is a LookUpDataValue object.
I would like this combobox to be set correctly when the records are loaded, and conversely update the record when it's changed.
I would appreciate any pointers on where I can find an example of this...
I was not able to change my datamodel so I found the following solution which works.
// Handle ComboBox event.
myComboBox.setOnAction((event) -> {
LookUpDataValue selected = myComboBox.getSelectionModel().getSelectedItem();
if(selected != null){
dto.setForeignKeyId(selected.getId());
}
});
This works well. Thanks for your comments.

How to load a datasource with multiple objects at a time in WPF datagrid

I have two objects with same properties obj1 and Obj2 . but the values in these objects are different. I want to combine these object and the result I want to bind to the Itemsource of the datagrid.Is that possible using lambda expession/Linq ?
If the number of Properties are limited then I have a simple solution
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<Data1> _data1= new List<Data1>{new Data1{Name="Test11"},new Data1{Name="Test12"}};
List<Data2> _data2=new List<Data2>{new Data2{Name="Test21"},new Data2{Name="Test22"}};
List<Common> _common = new List<Common>();
_common.AddRange(_data1.ConvertToCommon());
_common.AddRange(_data2.ConvertToCommon());
foreach(var item in _common)
{
Console.WriteLine(item.Name);
}
}
}
class Data1
{
public string Name{get;set;}
}
class Data2
{
public string Name{get;set;}
}
class Common
{
public string Name{get;set;}
}
static class Extension
{
public static IEnumerable<Common> ConvertToCommon(this IEnumerable<Data1> data)
{
foreach(var item in data)
yield return new Common{Name=item.Name};
}
public static IEnumerable<Common> ConvertToCommon(this IEnumerable<Data2> data)
{
foreach(var item in data)
yield return new Common{Name=item.Name};
}
}
Then you can use the Common class to Bind to UI. The other option is to use MultiBinding and then a IMultiValueConverter. Again you need to Cast to a data type.

How to show Drop down control in Property Grid?

I am adding the Property grid control in my project.
I have to show the Drop down box in one field of Property Grid.
Is there any solution to apply this.
You have to declare a type editor for the property in your PropertyGrid and then add to the list of choices. This example creates a Type Converter and then overrides the GetStandardValues() method to provide choices to the drop-down:
private String _formatString = null;
[Category("Display")]
[DisplayName("Format String")]
[Description("Format string governing display of data values.")]
[DefaultValue("")]
[TypeConverter(typeof(FormatStringConverter))]
public String FormatString { get { return _formatString; } set { _formatString = value; } }
public class FormatStringConverter : StringConverter
{
public override Boolean GetStandardValuesSupported(ITypeDescriptorContext context) { return true; }
public override Boolean GetStandardValuesExclusive(ITypeDescriptorContext context) { return true; }
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
List<String> list = new List<String>();
list.Add("");
list.Add("Currency");
list.Add("Scientific Notation");
list.Add("General Number");
list.Add("Number");
list.Add("Percent");
list.Add("Time");
list.Add("Date");
return new StandardValuesCollection(list);
}
}
The key is the property being assigned a Type Converter in the line:
[TypeConverter(typeof(FormatStringConverter))]
That provides you with the opportunity to introduce your own behavior via overrides.
Here's a simpler example, which allows the Enum type of a Property to automatically provide its values to the PropertyGrid drop-down:
public enum SummaryOptions
{
Sum = 1,
Avg,
Max,
Min,
Count,
Formula,
GMean,
StdDev
}
private SummaryOptions _sumType = SummaryOptions.Sum;
[Category("Summary Values Type")]
[DisplayName("Summary Type")]
[Description("The summary option to be used in calculating each value.")]
[DefaultValue(SummaryOptions.Sum)]
public SummaryOptions SumType { get { return _sumType; } set { _sumType = value; } }
By virtue of the fact that the property is an Enum type, those enum values pass through to become the drop-down options automatically.

Need a reusable SelectAll ViewModel

I have often run into situations where I want to have a 3-State checkbox to select all/deselect all of my view models. I have run into difficulties creating a reusable class to do this with.
I tried to create the following base classes:
public class SelectAllListVM
{
public List<SelectableVM> ChildList = new List<SelectableVM>();
public bool? SelectAll // call UpdateSelectedChildren on set
internal void UpdateSelectAll ()
// Set SelectAll based on ChildList elements
// true = all selected, false = non selected, null = some selected
private void UpdateSelectedChildren () {
foreach ( SelectableVM vm in ChildList )
vm.SetIsSelected( SelectAll.Value );
}
}
public class SelectableVM
{
public SelectableVM (SelectAllListVM parentVM) {}
public bool IsSelected // call parentVM.UpdateSelectAll
}
The problem with this is every time I want to iterate through the ChildList I have to cast the SelectableVM to it's concrete implementation. How can I reuse this behavior and avoid casting?
I did some attached behavior trickery back in the day to do this. Everything is handled by the view no need for the VM to care about select all logic. I wrote the details of how to do it in three parts (part 1, part 2, part 3) I made the code available on fileden...and subsequently lost it because I didn't log into the account enough times. But all the code is there throughout the three posts.
You could create an Interface ISelectableVM
public interface ISelectableVM
{
public bool IsSelected;
}
and implement it in your derived classes.
public class SelectableVM : ISelectableVM
{}
public class OtherSelectableVM : ISelectableVM
{}
Then in your ParentVM you don't have to cast:
public class SelectAllListVM
{
public List<ISelectableVM> ChildList = new List<ISelectableVM>();
public bool? SelectAll; // call UpdateSelectedChildren on set
private void UpdateSelectedChildren()
{
foreach (ISelectableVM vm in ChildList)
vm.IsSelected = SelectAll.Value;
}
}
Instead of an interface you could also use
public class BaseSelectableVM
{
public bool IsSelected;
}
and derive from it.

Dynamic Autosuggest Combobox in GXT

Over the past 5 months we have been prototyping GWT and setting up the infrastructure. WE are using GXT for the widgets with MVP and Command Pattern implementations. However, we are currently looking to do a spike on a ComboBox with autosuggest from a live Database. I would like to do this in the framework of the MVP and Command pattern implementations. Any one out there have any ideas how to go about doing this?
I solved that using a generic DispatchDataProxy modelled over the Command Pattern. Thanks for the link, but GXT documentation leaves a lot to be desired, though the framework is really nice and cool.
I will post the code here `public class DispatchDataProxy implements DataProxy> {
#Inject
private DispatchAsync dispatch ;//= new StandardDispatchAsync(new DefaultExceptionHandler());
#Override
public void load(DataReader<ListLoadResult<X>> reader, Object loadConfig, final AsyncCallback<ListLoadResult<X>> callback) {
if (loadConfig instanceof BasePagingLoadConfig) {
BasePagingLoadConfig a = (BasePagingLoadConfig) loadConfig;
Map<String, Object> map = a.getProperties();
Object data = map.get("query");
XCommand action = new XCommand();
action.setX((String) data);
dispatch.execute(action, new AsyncCallback<XResult>() {
#Override
public void onFailure(Throwable arg0) {
//Log.debug("Some error:" + arg0.getMessage());
callback.onFailure(arg0);
}
#Override
public void onSuccess(XResult arg0) {
ListLoadResult<X> list = arg0.getList();
callback.onSuccess(list);
}
});
}
}
public DispatchAsync getDispatch() {
return dispatch;
}
public void setDispatch(DispatchAsync dispatch) {
this.dispatch = dispatch;
}
}`
Hope its useful. Will appreciate some comments as well
Have you looked here?
http://www.sencha.com/examples-2/explorer.html#advancedcombobox
They show something similar. The issue with GXT is you are better off using their DataProxy because you need to set a ModelData instance.
I found solution for simple combo box, override getValue method:
public SimpleComboBox<String> createEditableSimpleComboBox() {
return new SimpleComboBox<String>() {
#Override
public SimpleComboValue<String> getValue() {
SimpleComboValue<String> v = super.getValue();
String raw = getRawValue();
if ((v == null || v.getValue() == null) && raw != null && !raw.isEmpty()) {
v = new SimpleComboValue<String>(raw){
private static final long serialVersionUID = 1L;
};
}
return v;
}
};
}
Now when you add to combo box default value (not defined in store) method getValue returns this value - not null.

Resources