I want to have a button enabled or disabled based on whether a text field contains anything, and I want to implement this by using property binding.
So at first I used the isEmpty() method on the text field's text property to create a boolean binding for the button's disabled property:
startSearchButton.disableProperty().bind(searchField.textProperty().isEmpty());
While the binding works, my definition of "text field contains anything" is different to what the isEmpty() method does, namely just checking if the text's length is > 0. However, I'm interested in whether there is "real" text, i.e. whether the text field is blank (not just not empty, but actually not only whitespace).
Unfortunately there is no method isBlank(), and I also couldn't find anything appropriate in the Bindings utility class. Now I saw that you can implement any custom boolean property you like via the Bindings.createBooleanProperty method, but I'm not yet familiar with the concept of defining custom bindings. How would I have to implement such a boolean property for my case?
You can create a custom binding using (among many methods) Bindings.createBooleanBinding(...). The first argument is a function that computes the value of the binding (you can trim whitespace from the text with trim() and then check if the result is empty); the remaining arguments are a list of observables that trigger recomputation of the binding. You want to recompute the binding when the text in the text field changes, so just specify the text property:
startSearchButton.disableProperty().bind(Bindings.createBooleanBinding(() ->
searchField.getText().trim().isEmpty(),
searchField.textProperty());
As for 2022
public static BooleanBinding isBlank(StringProperty stringProperty) {
return Bindings.createBooleanBinding(() -> stringProperty.get().isBlank(), stringProperty);
}
public static BooleanBinding isNotBlank(StringProperty stringProperty) {
return isBlank(stringProperty).not();
}
(idk why didn't nobody suggest String::isBlank, perhaps it was added in Java later)
You can do this too:
With Apache StringUtils.isBlank()
startSearchButton.disableProperty().bind(Bindings.createBooleanBinding(() ->
StringUtils.isBlank(searchField.getText()),
searchField.textProperty());
Create you own method
public static boolean IsNullOrWhitespace(String s) {
if(s == null) {
return true;
}
for(int i = 0; i < s.length(); ++i) {
if(!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
and then:
startSearchButton.disableProperty().bind(Bindings.createBooleanBinding(() ->
IsNullOrWhitespace(searchField.getText()),
searchField.textProperty());
Related
I have the following code
public ValidationResult notNull(Control control, String content) {
boolean condition = content.length() <=0;
return ValidationResult.fromMessageIf(control, "Field is empty!", Severity.WARNING, condition);
}
it checks if there is any character in text field,
the i call it like this
validator = new ValidationSupport();
validator.registerValidator(itemIdTf,vals::notNull);
and finally is do this
validator.invalidProperty().addListener((observable, oldValue, newValue) -> {
itemIdTf.pseudoClassStateChanged(PseudoClass.getPseudoClass("negative"), oldValue);});
And this works, it sets the pseudo class for certain controll, how ever when i have few text field controls on same validatior it must wait for all of them to be validated before changing the pseudoclass.
so i thought to perhaps do it in the ValidationResult method, because i think using many validators is probably not good. How ever i dont know if that is possible, i need some listener that is unique to every control, not for validation result.
well i found something that works, but it still leaves some unanswered questions :
public ValidationResult notNull(Control control, String content) {
boolean condition = content.length() <=0;
control.pseudoClassStateChanged(positive,!condition);
return ValidationResult.fromMessageIf(control, "Field is empty!", Severity.ERROR, condition);
}
i am using css styling validator, so the things that come from this line do not work (at least not all of them)
return ValidationResult.fromMessageIf(control, "Field is empty!", Severity.ERROR, bp.getValue());
Here above there is string "Field is empty" which should be tooltip for control, however its never set, so i just created my own tooltip inside validation and i add it to control.
then the whole thing looks something like this :
PseudoClass positive = PseudoClass.getPseudoClass("positive");
final Tooltip notNullTooltip = new Tooltip("Must have some value");
public ValidationResult notNull(Control control, String content) {
boolean condition = content.length() <=0;
control.pseudoClassStateChanged(positive,!condition);
control.setTooltip(notNullTooltip);
return ValidationResult.fromMessageIf(control, "Field is empty!", Severity.ERROR, condition);
}
And it does work, if anyone has more elegant solution i would be thankfull.
I have read Access property delegate in Kotlin which is about accessing a delegate from an instance. One can use KProperty::getDelegate since Kotlin 1.1, however this will return the instance of the delegate and therefore needs an instance of the class first.
Now I want to get the type of the delegate without having an instance of the class. Consider a library with a custom delegate type CustomDelegate that want's to get all properties of a class that are delegated to an instance of CustomDelegate:
class Example
{
var nonDelegatedProperty = "I don't care about this property"
var delegatedProperty1 by lazy { "I don't care about this too" }
var delegatedProperty2 by CustomDelegate("I care about this one")
}
How can I, given I have KClass<Example>, but not an instance of Example, get all properties delegated to CustomDelegate?
How can I, given I have KClass<Example>, but not an instance of
Example, get all properties delegated to CustomDelegate?
You can do it in two ways depending on your needs.
First of all, you have to include the kotlin-reflect dependency in your build.gradle file:
compile "org.jetbrains.kotlin:kotlin-reflect:1.1.51"
In my opinion, you should use the first solution if you can, because it's the most clear and optimized one. The second solution instead, can handle one case that the first solution can't.
First
You can loop an the declared properties and check if the type of the property or the type of the delegate is CustomDelegate.
// Loop on the properties of this class.
Example::class.declaredMemberProperties.filter { property ->
// If the type of field is CustomDelegate or the delegate is an instance of CustomDelegate,
// it will return true.
CustomDelegate::class.java == property.javaField?.type
}
There's only one problem with this solution, you will get also the fields with type CustomDelegate, so, given this example:
class Example {
var nonDelegatedProperty = "I don't care about this property"
val delegatedProperty1 by lazy { "I don't care about this too" }
val delegatedProperty2 by CustomDelegate("I care about this one")
val customDelegate = CustomDelegate("jdo")
}
You will get delegatedProperty2 and customDelegate. If you want to get only delegatedProperty2, I found an horrible solution that you can use if you need to manage this case.
Second
If you check the source code of KPropertyImpl, you can see how a delegation is implemented. So, you can do something like this:
// Loop on the properties of this class.
Example::class.declaredMemberProperties.filter { property ->
// You must check in all superclasses till you find the right method.
property::class.allSuperclasses.find {
val computeField = try {
// Find the protected method "computeDelegateField".
it.declaredFunctions.find { it.name == "computeDelegateField" } ?: return#find false
} catch (t: Throwable) {
// Catch KotlinReflectionInternalError.
return#find false
}
// Get the delegate or null if the delegate is not present.
val delegateField = computeField.call(property) as? Field
// If the delegate was null or the type is different from CustomDelegate, it will return false.
CustomDelegate::class.java == delegateField?.type
} != null
}
In this case, you will get only delegatedProperty2 as result.
I have a simple JavaFX Table with a column like this:
#FXML
private TableColumn<PropertyModel, String> columnPropertyProdValue;
Within the initialize method I used this
columnPropertyProdValue.setCellFactory(TextFieldTableCell.forTableColumn());
in order to get an textarea at a double click event on this column. This is working fine.
The column should store different property values but the datatype depends on a different column in the table. The first column "datatype" defines the datatype like boolean, string or integer and the property column should store its value. But in the moment it is always a String.
Its fine for me if I store the property value as a String in the database but the application should check for correctness of the datatype at runtime.
Does anyone has a good idea how to realize that?
Thanks a lot
Hauke
For TextInputControl and subclasses you can apply TextFormatter. This class allows you to control input. For example (for float number):
setTextFormatter(new TextFormatter<String>(
s -> {
if (s.getControlNewText().isEmpty())
return s;
try{
Float.parseFloat(s.getControlNewText());
return s;
} catch (NumberFormatException e) {
return null;
}
}
I have a form with 2 fields, the 1st is filled with a lookup and the 2nd (not editable, just a Description of the 1st) is filled with a "display" method in the form.
public display Name displaySalesChannelName()
{
return SalesChannelTable::find(SalesChannelFilter.valueStr()).Description;
}
Seems to work fine, but only shows the value when the field is clicked.
How can I synchronize this 2 fields?
You can override method modified of the 1st control (with the lookup) and call method update of the 2nd control from there, e.g. if the name of the 2nd control is SalesChannelName and its AutoDeclaration property has been set to Yes, then:
public boolean modified()
{
boolean ret = super();
SalesChannelName.update();
return ret;
}
But then there's not much sense in using a display method here. You can just as well clear the DataMethod property of the 2nd control, and the modified method above can be rewritten as follows:
public boolean modified()
{
boolean ret = super();
SalesChannelName.text(SalesChannelTable::find(this.valueStr()).Description);
return ret;
}
you should try to put the display method on table level, your field's properties in the form must have the datasource Table name as datasource and your method's name as data method
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
}