Why does TableCloumn<S,T> take 2 Elements? - javafx

The JavaDoc says:
Type Parameters:
S - The type of the TableView generic type (i.e. S == TableView<S>)
T - The type of the content in all cells in this TableColumn.
What does "generic type" mean in this context? If the content is a String, the generic type would also be a string, would it not?
I'm trying to compile the following code taking a String:
TableColumn col = new TableColumn<?, String>();
public void append(String str) {
col.add(str);
}
Why am I not able to do this?

S is your domain object
T is a value of the domain object you want to
show in that column.
Please have a look at the Javadoc for these kind of questions:
http://docs.oracle.com/javafx/2/api/javafx/scene/control/TableView.html

Related

JavaFX Custom Cell Renderer for TreeTableView

I am trying to implement a TreeTableView in JavaFX, containing 'MyData' objects, and having two columns. First column should contain a string; this was easy:
column1.setCellValueFactory((TreeTableColumn.CellDataFeatures<MyData, String> entry)
-> new ReadOnlyStringWrapper(entry.getValue().getValue().toString()));
For the second column, I need to use some more complex data within the MyData object, and I want to render basically a sequence of icons that depict that data. So, I tried to create a custom cell renderer:
MyCellRenderer extends TreeTableCell<MyData, MyData> {
#Override
protected void updateItem(MyData item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
setText(null);
} else {
// building some ContentPane with an HBox of Images here..
setGraphic(contentPane);
}
}
}
and then set the column CellFactory and CellValueFactory as follows:
column2.setCellValueFactory((TreeTableColumn.CellDataFeatures<MyData, MyData> entry)
-> new ReadOnlyObjectWrapper(entry));
column2.setCellFactory(param -> new MyCellRenderer());
But I get this exception at runtime:
Exception in thread "JavaFX Application Thread"
java.lang.ClassCastException:
javafx.scene.control.TreeTableColumn$CellDataFeatures cannot be cast
to MyData
I am afraid I don't really understand the meaning of the different generic types for all these classes, and also I am not sure about the "ReadOnlyObjectWrapper". I just tried to copy/paste and tweak it from the setup of the first column.
I would be very thankful if someone could shine some light on me. Unfortunately the oracle docs about TreeTableView don't go into that much detail, they just show simple examples.
Thank you
You're passing entry, which is of the type TreeTableColumn.CellDataFeatures<MyData, MyData>, as the initial value to a new ReadOnlyObjectWraper - a raw type - which is expecting a type of MyData at runtime and not TreeTableColumn.CellDataFeatures<MyData, MyData>. As you can see, there is a mismatch of generic types.
Try changing
new ReadOnlyObjectWrapper(entry)
to
new ReadOnlyObjectWrapper<>(entry.getValue().getValue())
The reason for two getValue() calls is because the first entry.getValue() returns a TreeItem<MyData> and the second getValue() returns the actual MyData instance.
This is all assuming that your table is declared TreeTableView<MyData> and your column is declared TreeTableColumn<MyData, MyData>.
Edit: Since you said you don't really understand all the generic signatures here's a brief explanation.
TreeTableView<S>
Here the S is the type of object the TreeTableView displays. AKA, the model class. An example would be a Person class which would make S a Person.
TreeTableColumn<S, T>
The S here is the same as the S in the TreeTableView that the column is destined to be a part of. The T is the type of object that a TreeTableCell in the column will be displaying. This is normally a value contained within a property of the type S. Such as a StringProperty for a name of a Person which would make T a String.
TreeTableCell<S, T>
The S and T will be the same as the TreeTableColumn which the cell will be a part of.
Now, for the value callback:
Callback<TreeTableColumn.CellDataFeatures<S, T>, ObservableValue<T>>
Again, the S and T represent the same types of the TreeTableColumn for which the Callback will belong to. This Callback returns an ObservableValue that contains the type T so that the TreeTableCell can observe the value for changes and update the UI accordingly. In your case, since the type you want to display is not held in a property you return a new ReadOnlyObjectWrapper to satisfy the API requirements. If I continue the name StringProperty example I gave above you could end up with something like:
TreeTableView<Person> table = ..;
TreeTableColumn<Person, String> column = ...;
column.setCellValueFactory(dataFeatures -> {
// This could all be done in one line but I figured I'd
// make it explicit to show all the types used.
TreeItem<Person> item = dataFeatures.getValue();
Person person = item.getValue();
return person.nameProperty(); // returns StringProperty which is an
// ObservableStringValue which in turn
// is an ObservableValue<String>
});
You need
column2.setCellValueFactory((TreeTableColumn.CellDataFeatures<MyData, MyData> entry)
-> new ReadOnlyObjectWrapper<>(entry.getValue().getValue()));
Note that if you don't use raw types (i.e. use ReadOnlyObjectWrapper<> or ReadOnlyObjectWrapper<MyData>, instead of just ReadOnlyObjectWrapper), the compiler will inform you of the error, which is much better than trying to decipher what went wrong at runtime.
As you can see, the parameter type for the cell value factory is a TreeTableColumn.CellDataFeatures (see docs). This is simply a wrapper for the row value from which you're going to extract the data that are shown in the cell; this wrapper just contains the tree item for the row itself (which you get with getValue()), as well as the column to which the cell value factory is attached (getTreeTableColumn()) and the table to which that column belongs (getTreeTableView()).
The latter two, I believe, are designed to enable you to write general, reusable, cell value factories, which you might want to customize on the basis of the column or table to which they're attached. (Use cases for this are hard for me to envisage, but nevertheless I suspect there is some occasion for them...)
The TreeItem containing the row (which you get with entry.getValue()), of course contains the row value itself (you get this with getValue(), which is why you end up with entry.getValue().getValue()), as well as other TreeItem-specific information (is it expanded, selected, etc etc).

In a C# TBB: how to split a multi SingleLineTextField into seperate strings

I have a plain textfield in Tridion that can have multiple values. The itemtype is a SingleLineTextField.
In the TBB code I have the following (removed the non-essential parts):
ItemFields itemFields = new ItemFields(folder.Metadata, folder.MetadataSchema);
foreach (ItemField itemField in itemFields)
{
string itemFieldValue = string.Empty;
switch (Utilities.GetFieldType(itemField))
{
case FieldType.SingleLineTextField:
itemFieldValue = itemField.ToString();
break;
}
}
Now the result in case of two entries is just two strings with a character line break in it.
String A
String B
The method used is a generic one, which also works on other fields, so I was looking for some way to find out if a SingleLineTextField has more values in it.
You can cast the field to a SingleLineTextField type, then iterate through the Values collection, something along these lines:
SingleLineTextField field = (SingleLineTextField)itemField;
foreach(string value in field.Values)
{
// do something with value
}
// or if all you want is the count of values
int i = field.Values.Count;
Firstly, I would advise against relying on the ToString() method on objects unless it is specifically documented. In this case it works with the abstract class ItemField, but this may not always be the case.
The TOM.Net API only defines Definition and Name properties for ItemField, so you need to cast your ItemField object to something more specific.
the TextField abstract class, which SingleLineTextField inherits from, defines a ToString() method, but also Value and Values properties, which are much better suited to what you're trying to do. Looking at the documentation, we can see that Values will give us an IList<String> of the values, even if your field is not multi-valued. Perfect!
So, to answer your question, "I was looking for some way to find out if a SingleLineTextField has more values in it", you need to cast your ItemField as a TextField and check the number of Values it provides, thus:
TextField textField = (TextField)itemField;
// If you need to deal with multi-valued fields separately
if (textField.Values.Count > 1)
{
//Logic to deal with multiple values goes here
}
else
{
//Logic to deal with single valued goes here
}
// Much better... If you can deal with any number of values in a generic fashion
foreach (string value in textField.Values)
{
// Generic code goes here
}

How To Put String Value in String Array ?? Code Attached (Error: Object reference not set to an instance of an object.)

i am getting error "Object reference not set to an instance of an object." my is here,
public class UserProfession
{
public UserProfession()
{
}
public System.String[] Designation
{
get;
set;
}
}
then i am using it like,
UserProfession.Designation[0] =txt_Search.Text.ToString();
Error i mentioned you hopes for your suggestions .
-Thanks
When you make an assignment to an array property, like this:
UserProfession.Designation[0] =txt_Search.Text.ToString();
what you are actually doing is calling the get section for that property... not the set. This returns the object supported the property... the whole object, and not just the index. Index lookup does not happen until after the object is returned. Once you have that object, accessing an index works in the normal way.
You get this specific exception because you have the expression UserProfession.Designation that should return a reference to an array object, but because you never initialize the array there is nothing there when you then try to find reference the 0th element. At this point the framework discovers that the array (your "object reference") is "not set to an instance of an object"... which is just a fancy way of saying it's null.
In other words, you need to have an already existing array to hold the value you want to assign. That means doing something like this:
Designation = new String[10];
public String[] Designation
{
get;
set;
}
However, notice that we never used the set section? So you can simplify that further, like this:
Designation = new String[10];
public String[] Designation {get;private set;}
This will keep client code from completely swapping an entire array out from under your object, but otherwise will provide the full functionality of an array property. If you provide your own backing store for the array, you could even get rid of the setter entirely with no loss of functionality:
private string[] _designation = new string[10];
public string[] Designation {get {return _designation;} }
But let's add one more wrinkle: your desire to assign the to array before initializing it indicates to me that you likely don't really know how big it will be up front. If that's the case, you probably want a collection of some kind instead of an array. A generic List is a convenient and very compatible replacement for an array. That would look like this:
private List<string> _designation = new List<string>();
public List<string> Designation {get {return _designation;}}
You can still access items in that list by index, just like you would with an array. The only difference you need to worry about right now is how you add new items:
UserProfession.Designation.Add(txt_Search.Text);
Also notice that I removed the .ToString() call. Since your .Text property is almost certainly already a string, calling the .ToString() method is just silly.
You will have to initialize the object, before assigning the value. The initialization should be done just once. I have initialized the array size to ten. You can have your own values here. If you want to resize dynamically, you can use ArrayList
int length = 10;
UserProfession.Designation = new System.String[length];
UserProfession.Designation[0] =txt_Search.Text.ToString();
For more information: http://msdn.microsoft.com/en-us/library/aa287601(v=vs.71).aspx
it must initialize the value before we use because, currently, it is null.
you better add the initialization code in the constructor function.

Why some VariableDeclaration resolveBinding returns null but others does not

I am developing an eclipse plug-in to analyze the java source code. I traverse the whole AST tree and write a visitor to visit each variableDeclartionStatement, I noticed for some variables, the "resolvebinding" return an instance of IVariableBinding, but others does not. I can not differentiate them. BTW: I have set the ASTParser.setKind(K_COMPILATION_UNIT) and setResolveBindings(true). My code is as follows:
#Override
public boolean visit(VariableDeclarationStatement vStatement) {
Type theType = vStatement.getType();
for(Iterator iterator = vStatement.fragments().iterator();iterator.hasNext();){
VariableDeclarationFragment fragment = (VariableDeclarationFragment)iterator.next();
IVariableBinding binding = fragment.resolveBinding();
if(binding !=null){
ITypeBinding tBinding = binding.getType();
if(tBinding !=null){
// if there is ArrayType, get the root type
while(tBinding.getComponentType()!=null){
tBinding = tBinding.getComponentType();
}
System.out.println("USING BINDING VARIABLE CLASS IS: " + tBinding.getQualifiedName());
}
}
}
}
My question is: How can I differentiate the variable declarations which can resolve bindings with others which can not?
Many thanks in advance
From the JavaDoc on VariableDeclarationFragment:
Variable declaration fragment AST node
type, used in field declarations,
local variable declarations, and
ForStatement initializers. It
contrast to
SingleVariableDeclaration, fragments
are missing the modifiers and the
type; these are located in the
fragment's parent node.
Try to get the type binding from the VariableDeclarationFragment's parent.

NullValueInNestedPathException for Bean[] class binding

Hello I'd like to ask if you can assign arrays of beans as a form
for example i have a form:
PageForm{
Group[] groupArray;
Group[] getGroupArray(){
return groupArray;
}
void setGroupArray( Group[] groupArray ){
this.groupArray = groupArray;
}
}
Group{
boolean isChecked;
boolean getIsChecked(){
return isChecked;
}
void setIsChecked( boolean ischecked ){
this.isChecked = ischecked;
}
}
id like to access this group array in my jsp.
can i do that using this:
<spring:form>
<spring:checkbox path="groupArray[0].isChecked" />
<spring:checkbox path="groupArray[1].isChecked" />
<spring:checkbox path="groupArray[2].isChecked" />
</spring:form>
What i get is an exception:
org.springframework.beans.NullValueInNestedPathException:
Invalid property 'groupArray[0]' of
bean class [PageForm]: Cannot access
indexed value of property referenced
in indexed property path
'groupArray[0]': returned null
Please help me.
Thanks.
The problem is that Group[] groupArray has not been initialized, so when it goes to the array and looks for the object Group at position 0 it cannot find the Group object.
If you know in advance the number of objects which there can be in the array you can insert as many Group objects as you need in the array groupArray in the constructor of PageForm.
In case you don't know how many object you'll have in the array (because you'll create them from data coming from a form) you'll need to provide a way to create new Group objects when the object has not been instantiated in that position before. I think the easiest way toget this is to change your Group[] array to a List<Group> and use a lazy list like Spring AutoPopulatingList, Apache Commons Collections LazyList or the one provided by the library Guava.
try to change your attribute name maybe myChecked and getter/setter as well
e.g. getChecked and setChecked

Resources