Hi, I'm trying to find the best way of creating a ...
# tornadofx
v
Hi, I'm trying to find the best way of creating a nullable property in an
ItemViewModel
of a "Java-primitive" type. The only way I figured out how to do this is to wrap it in a
ObjectProperty
, but the
bind {}
function seems to wrap the value in another property:
Property<ObjectProperty<Boolean?>>
The values on the labels are:
Copy code
nullableStringProperty1 = null
nullableStringProperty2 = null
nullableBooleanProperty1 = null
nullableBooleanProperty2 = false
Is there a cleaner way of dealing with nullable primitive types than
Property<ObjectProperty<Boolean?>>
? Thanks.
b
Do you need property values to be null? then you just need:
property.value = null
v
They are null, but the Boolean property gets "converted" to false from null (see the attached code), because the
SimpleBooleanProperty
is a java class with an underlying primitive value, that cannot be null. And I don't know how to create a binding of type
Property<Boolean>
that can contain null instead of
Property<ObjectProperty<Boolean?>>
. I can use a SimpleStringProperty for a nullable String, because the underlying type is nullable though.
i
Have you tried SimpleObjectProperty<Boolean?> ? you should be able bind it in the ItemViewModel with bind<Boolean?, SimpleObjectProperty<Boolean?>, SimpleObjectProperty<Boolean?>>
Ok, sorry, it doesn'T work: the problem is, that bind has the constraint
T:Any
on it - it doesn't allow nullables.
v
If you
bind
SimpleObjectProperty<Boolean?>
, you also get
Property<SimpleObjectProperty<Boolean?>>
i
It seems that tornadofx's ItemViewModel.bind just doesn't support nullables ...
b
@Alen Mujezinovic
val b = objectProperty<Boolean?>(false)
v
I need to distinguish between null and false
e.g. show a label only if the property is not null
i
can you avoid it by using a 3-valued enum instead?
v
of course, but this also seems like a workaround
and that only works for
Boolean?
. what about
Int?
?
b
@Alen Mujezinovic in the code above it will be so, you will still have:
false
,
true
,
null
this must be done in the model (
Item
), and not in the
class ItemModel: ItemViewModel
for int, everything is similar
v
i don't understand what you mean. have you seen the code sample in the original post? i tried replacing
var nullableBoolean: Boolean? by property(nullableBoolean)
with
var nullableBoolean: Boolean? by objectProperty(nullableBoolean)
and i get an exception:
Caused by: java.lang.ClassCastException: javafx.beans.property.SimpleObjectProperty cannot be cast to tornadofx.PropertyDelegate
could you please provide more context? a sample?
b
Copy code
class Item(nullableBoolean: Boolean? = null) {
    val nullableBooleanProperty = SimpleObjectProperty(this, "nullableBoolean", nullableBoolean)
}

class ItemModel : ItemViewModel<Item>() {
    val nullableBooleanProperty = bind(Item::nullableBooleanProperty)
}
Copy code
class Item() {
    val nullableBooleanProperty = SimpleObjectProperty<Boolean?>(this, "nullableBoolean")
}
v
The type of
nullableBooleanProperty
is
Property<SimpleObjectProperty<Boolean?>>
b
yes
noy
v
b
you can include types, I did not understand in what place, in ViewModel - yes
i
as mentioned, ItemViewModel.bind (and all its overloads) does not support nullable values. You can see it in the signature of the TFX soruce code. the Type-parameter
T
hast a xonstraint:
T:Any
, that means, kotlin will never allow for a binding to retorn a Property<Result> where Result is a nullable Type.
v
i have the same code in my original sample. the question is: can i have a
Property<Boolean>
instead somehow using
bind
, that supports null? it works non-primitive types
b
you have another, you use a primitive, in this case the object will be used
i
@vmerk you can defintely never have a
Property<Result>
where
Result
is a nullable Type with bind.
b
v
yea, just wondering if there's a cleaner solution than
Property<ObjectProperty<Boolean?>>
@Bogdan i need it in the
ItemViewModel
b
noy
no does not exist, this is the most optimal
@Alen Mujezinovic so what did I throw you off?
v
the whole question is about using a nullable primitive type from a
ItemViewModel
. and you are suggesting that i just don't use it?
i
vmerk did you read, what i wrote?
you van however achieve what oyu want with the string property.
SimpleStringProperty can hold a null valie. it can be bound, and it can be checked for null conveniently like so:
v
String is not a problem, Boolean is
i
well, for boolean you're out of luck with the native implementation of bind. you will have to use a workaround.
and i would not use the soluteion with the doubly-wrapped property- In case you ever want to write to these properties, I would assume, that the bindings will not work as you expect them to work with that version. 😕
b
@Alen Mujezinovic did you mean that?
v
@Bogdan i'm not Alen Mujezinovic btw yes, this is a wrapped property
b
@vmerk oh sorry
v
@iari that's unfortunate, seems like a simple problem. thank you for the help would be great if @edvin could weigh in on this, maybe there's something we don't know
b
so it’s normal,
SimpleBooleanProperty
- you need not to waste memory, not to create top objects. The rest you need to use
ObjectProperty
i
I just quickly copied the basic implementation of the bind-method in a little subclass of ViewModel. I replaced the typeconstraint
T:Any
with
T:Any?
- and I only got one conflict with a list of changelisteners which also are constrained to
Any
- that seems like an easy fix - however of course we don't know if that might break the implementation....
v
yea, im not sure this is that easy of a fix, but sounds like something worth trying
adding
T : Any?
to
bind
and passing
forceObjectProperty = true
produces the result that i wanted. not sure if i broke anything, all tests are passing..
👍 1
looks like we don't need any changes to
bind
at all. i think adding
forceObjectProperty
might be enough
tldr:
Copy code
class Item {
    var nullableBoolean: Boolean by property()
    val nullableBooleanProperty: ObjectProperty<Boolean> = getProperty(Item::nullableBoolean)
}

class ItemModel : ItemViewModel<Item>() {
    val nullableBooleanProperty: Property<Boolean> = bind(Item::nullableBooleanProperty, forceObjectProperty = true)
}
b
I think you are doing something wrong. also rather
Boolean?
v
code doesn't compile with
Boolean?
because of
bind
b
your application will crash at runtime
can then throw off the final code? I want to see the case
v
b
where such a model should be used.