Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

306
Visualizações
JavaFX valueAt () El enlace solo se calcula una vez

Sabemos que ListExpression tiene un método ObjectBinding<E> valueAt(ObservableIntegerValue) . Podemos usar este método para escuchar exactamente un elemento de ListProperty .

Espero que se una tanto a ListProperty como a ObservableNumberValue . Por lo tanto, la lista cambia o los cambios en el valor del número observable harán que el enlace sea inválido y se vuelva a calcular. ¡Pero en el siguiente código, el enlace se calcula solo una vez! (En realidad dos veces, si no ignoramos el cálculo inicial)

La etiqueta mostrará una cadena aleatoria al principio. Y la property tendrá 100 Bean como valor inicial. Si hacemos clic en button1 , indexProperty aumentará en 1. Si hacemos clic en button2 , el Bean ubicado en el índice actual de ListProperty cambiará. Ambos efectos invalidarán el enlace y volverán a calcular el texto de la etiqueta.

Pero en la práctica, el texto cambiará la primera vez que se haga clic en un botón. Y no cambiará más.

Estoy usando Liberica JDK17 que contiene jmods de JavaFX por defecto.

 class FixmeApp : Application() { companion object { fun genRandomDouble(): Double = Math.random() * 10000 fun genRandomString(): String = genRandomDouble().roundToInt().toString(36) } class Bean { val stringProperty = SimpleStringProperty(genRandomString()) val doubleProperty = SimpleDoubleProperty(genRandomDouble()) } val property: ListProperty<Bean> = SimpleListProperty(FXCollections.observableArrayList(Bean())) override fun start(primaryStage: Stage) { property.addAll((0..100).map { Bean() }) val indexProperty = SimpleIntegerProperty(0) val label = Label().apply { textProperty().bind(Bindings.createStringBinding( { genRandomString() }, property.valueAt(indexProperty) )) } val button1 = Button("Change Index").apply { setOnAction { indexProperty.set(indexProperty.get() + 1) } } val button2 = Button("Change Bean").apply { setOnAction { property[indexProperty.get()] = Bean() } } val scene = Scene(BorderPane().apply { center = label bottom = HBox(button1, button2) }) primaryStage.scene = scene primaryStage.show() } } fun main() { Application.launch(FixmeApp::class.java) }

Por cierto, si cambiamos las dependencias vinculantes de property.valueAt(indexProperty) a property, indexProperty , el código se ejecutará como esperábamos.

En mi programa, el enlace devolverá la propiedad de Bean en la ubicación indexProperty.get() de propiedad


Editar (por James_D):

Para aumentar la audiencia de esta pregunta, aquí hay (hasta donde yo sé) una traducción de este ejemplo a Java.

 import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.property.*; import javafx.collections.FXCollections; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.stage.Stage; import java.util.Random; public class FixMeApp extends Application { private final Random rng = new Random(); private final ListProperty<Bean> property = new SimpleListProperty<>(FXCollections.observableArrayList()); @Override public void start(Stage stage) throws Exception { for (int i = 0 ; i < 100 ; i++) property.add(new Bean()); var index = new SimpleIntegerProperty(0); var label = new Label(); label.textProperty().bind(Bindings.createStringBinding( this::generateRandomString, property.valueAt(index) )); var button1 = new Button("Change Index"); button1.setOnAction(e -> index.set(index.get() + 1)); var button2 = new Button("Change bean"); button2.setOnAction(e -> property.set(index.get(), new Bean())); var root = new BorderPane(label); root.setBottom(new HBox(button1, button2)); var scene = new Scene(root); stage.setScene(scene); stage.show(); } private double generateRandomDouble() { return rng.nextDouble() * 10000 ; } private String generateRandomString() { return Integer.toString((int) generateRandomDouble()); } class Bean { private StringProperty stringProperty = new SimpleStringProperty(generateRandomString()); private DoubleProperty doubleProperty = new SimpleDoubleProperty(generateRandomDouble()); StringProperty stringProperty() { return stringProperty; } DoubleProperty doubleProperty() { return doubleProperty; } } public static void main(String[] args) { Application.launch(args); } }
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Voy a responder en Java, ya que estoy más familiarizado con él. El razonamiento también se aplica a kotlin.

Bindings.createStringBinding(function, dependencies) crea un enlace que se invalida cada vez que se invalida cualquiera de las dependencias. Aquí "invalidado" significa "cambios de un estado válido a un estado no válido". El problema con su código es que define la dependencia como property.valueAt(index) , que es un enlace al que no tiene otra referencia.

Cuando cambia el índice o el bean en ese índice en la lista, el enlace deja de ser válido. Dado que nunca vuelve a calcular el valor de ese enlace, nunca vuelve a ser válido (es decir, nunca contiene ni ha devuelto un valor válido). Por lo tanto, los cambios posteriores no cambiarán su estado de validación (simplemente sigue siendo inválido; no puede pasar de válido a inválido).

Cambiando el código a

 label.textProperty().bind(Bindings.createStringBinding( () -> property.valueAt(index).get().stringBinding().get(), property.valueAt(index) ));

no ayuda: tiene un enlace utilizado para la dependencia (cuyo valor nunca se calcula, por lo que nunca se devuelve a un estado válido) y un enlace diferente cada vez que se calcula el valor. El valor del enlace utilizado como dependencia nunca se calcula, por lo que nunca se devuelve a un estado válido y, en consecuencia, nunca se puede volver a invalidar.

Sin embargo

 ObjectBinding<Bean> bean = property.valueAt(index); label.textProperty().bind(Bindings.createStringBinding( () -> bean.get().stringProperty().get(), bean ));

trabajará. Aquí, el cálculo del texto obliga a bean a calcular su valor actual, devolviéndolo a un estado válido. Luego, los cambios posteriores en el índice o la lista invalidarán bean nuevamente, lo que desencadenará un nuevo cálculo del enlace al que está vinculado el text .

Creo que la traducción kotlin de esto es

 val bean = property.valueAt(indexProperty) val label = Label().apply { textProperty().bind(Bindings.createStringBinding( { bean.value.stringProperty.value }, bean )) }

Puedes experimentar con otras variaciones. Este no se actualiza más de una vez, porque bean nunca se valida:

 ObjectBinding<Bean> bean = property.valueAt(index); label.textProperty().bind(Bindings.createStringBinding( this::generateRandomString, bean ));

Mientras que este fuerza la validación, por lo que siempre se actualiza:

 ObjectBinding<Bean> bean = property.valueAt(index); label.textProperty().bind(Bindings.createStringBinding( () -> { bean.get(); return generateRandomString(); }, bean ));
over 4 years ago · Santiago Trujillo Relatório

0

Gracias a @James_D, no solo sé por qué este código no se ejecutó como se esperaba, sino que también resolví otro problema relacionado con los enlaces.

TL; DR: JavaFX no validará automáticamente los enlaces cuando las dependencias dejen de ser válidas . Debe validarlos obteniendo el valor o de alguna manera.

En el siguiente código, bean dejará de ser válido, ya sea la property o los cambios index , y se calculará StringBinding . Después del cálculo, el bean aún no es válido porque no lo calculamos para validarlo. Entonces, la próxima vez que cambien las dependencias del bean , StringBinding no volverá a calcular.

 ObjectBinding<Bean> bean = property.valueAt(index); label.textProperty().bind(Bindings.createStringBinding( this::generateRandomString, bean ));

Pero para este, es diferente. Aunque nunca usamos el valor del bean vinculante, lo validamos obteniendo. Entonces el código se ejecuta como se esperaba.

 ObjectBinding<Bean> bean = property.valueAt(index); label.textProperty().bind(Bindings.createStringBinding( () -> { bean.get(); return generateRandomString(); }, bean ));

Y para otra situación, ¡cuidado! May bean ser válido y, durante el cálculo, el flag era false , por lo que bean no se validó . Si no validamos bean alguna manera en algún lugar antes de que las dependencias de bean vuelvan a ser inválidas la próxima vez, el enlace no se calculará .

 ObjectBinding<Bean> bean = property.valueAt(index); label.textProperty().bind(Bindings.createStringBinding( () -> { if (flag) return bean.value else return generateRandomString(); }, bean ));
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda