Почему не работает прослушиватель JavaFX TextField? - PullRequest
1 голос
/ 12 июня 2019

Я хочу добавить слушателя к textField в окне, которое появляется, когда я нажимаю кнопку в предыдущем окне.Проблема в том, что слушатель вообще не работает.Это не обнаруживает никаких изменений.

public class WindowTwoController {

private Stage stage;

@FXML
private TextField imieTF = new TextField();


public void show() throws IOException {

    FXMLLoader loader = new FXMLLoader(getClass().getResource("winTwo.fxml"));
    Parent root = loader.load();

    stage = new Stage();
    stage.initModality(Modality.APPLICATION_MODAL);

    stage.setTitle("Sell Art");
    stage.setScene(new Scene(root, 500, 500));

    imieTF.textProperty().addListener((observable, oldValue, newValue) -> {
        System.out.println("textfield changed from " + oldValue + " to " + newValue);
    });

    stage.showAndWait();

}

Я изменяю значение textField, но на консоль ничего не выводится.Метод show вызывается при нажатии кнопки в предыдущем окне.Пожалуйста, помогите мне.Это мой winTwo.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>

<GridPane alignment="center" hgap="10" prefHeight="441.0" prefWidth="500.0" vgap="10" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="windowTwo.WindowTwoController">
<columnConstraints>
    <ColumnConstraints />
</columnConstraints>
<rowConstraints>
    <RowConstraints />
</rowConstraints>
<children>
    <VBox prefHeight="354.0" prefWidth="455.0">
        <children>
            <Label alignment="CENTER" prefHeight="45.0" prefWidth="457.0" text="Sprzedaż dzieła">
                <font>
                    <Font size="30.0" />
                </font>
            </Label>
            <Separator prefWidth="200.0" />
            <GridPane prefHeight="139.0" prefWidth="455.0">
                <columnConstraints>
                    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                </columnConstraints>
                <rowConstraints>
                    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                </rowConstraints>
                <children>
                    <Label alignment="CENTER" prefHeight="40.0" prefWidth="220.0" text="Imię">
                        <font>
                            <Font size="28.0" />
                        </font>
                    </Label>
                    <Label alignment="CENTER" prefHeight="40.0" prefWidth="220.0" text="Nazwisko" GridPane.rowIndex="1">
                        <font>
                            <Font size="28.0" />
                        </font>
                    </Label>
                    <TextField fx:id="imieTF" GridPane.columnIndex="1">
                        <GridPane.margin>
                            <Insets right="20.0" />
                        </GridPane.margin></TextField>
                    <TextField fx:id="nazwiskoTF" GridPane.columnIndex="1" GridPane.rowIndex="1">
                        <GridPane.margin>
                            <Insets right="20.0" />
                        </GridPane.margin>
                    </TextField>
                </children>
            </GridPane>
            <Separator prefWidth="200.0" />
            <Label alignment="CENTER" prefHeight="17.0" prefWidth="450.0" text="Klient powracający">
                <font>
                    <Font size="22.0" />
                </font>
            </Label>
            <Separator prefWidth="200.0" />
            <GridPane prefHeight="126.0" prefWidth="455.0">
                <columnConstraints>
                    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                </columnConstraints>
                <rowConstraints>
                    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                </rowConstraints>
                <children>
                    <Label alignment="CENTER" prefHeight="40.0" prefWidth="220.0" text="Poziom Zaprzyjaźnienia" textFill="#00000080">
                        <font>
                            <Font size="19.0" />
                        </font>
                    </Label>
                    <ComboBox fx:id="cb" opacity="0.5" prefHeight="25.0" prefWidth="207.0" GridPane.columnIndex="1" />
                    <Button mnemonicParsing="false" prefHeight="25.0" prefWidth="175.0" text="Akceptuj" GridPane.rowIndex="1">
                        <GridPane.margin>
                            <Insets left="25.0" />
                        </GridPane.margin>
                    </Button>
                    <Button mnemonicParsing="false" prefHeight="25.0" prefWidth="175.0" text="Anuluj" GridPane.columnIndex="1" GridPane.rowIndex="1">
                        <GridPane.margin>
                            <Insets left="27.0" />
                        </GridPane.margin>
                    </Button>
                </children>
            </GridPane>
        </children>
    </VBox>
</children>
</GridPane>

Ответы [ 2 ]

3 голосов
/ 12 июня 2019

Вы должны добавить аннотацию к приватному члену imieTF следующим образом:

public class WindowTwoController {
  @FXML
  private TextField imieTF;

  @FXML
  private void initialize() {
      imieTF.textProperty().addListener((observable, oldValue, newValue) -> 
       {
         System.out.println("textfield changed from " + oldValue + " to " + newValue);
       });
  }

  public static void show() {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("winTwo.fxml"));
    Parent root = loader.load();

    stage = new Stage();
    stage.initModality(Modality.APPLICATION_MODAL);

    stage.setTitle("Sell Art");
    stage.setScene(new Scene(root, 500, 500));
    stage.showAndWait();
  }
}

Это должно привязать экземпляр TextField к контроллеру.Но из того, что я могу узнать, FXML создаст новый экземпляр WindowTwoController, когда будет создано окно, принадлежащее файлу fxml.

Также см. https://www.callicoder.com/javafx-fxml-form-gui-tutorial/ для базового примера того, как это работает.

Обратите внимание, что все манипуляции с текстовым полем должны быть частью потока JavaFX и не могут быть выполнены в ручном экземпляре WindowTwoController.Помните, что JavaFX создаст свой собственный экземпляр WindowTwoController во время операции loader.load();.

0 голосов
/ 12 июня 2019

Ваш WindowTwoController#show() метод является методом экземпляра. Это означает, что вам нужно создать экземпляр WindowTwoController для вызова show(). Однако при использовании fx:controller в файле FXML FXMLLoader создаст свой собственный экземпляр класса контроллера. Конечным результатом является то, что TextField, к которому вы добавляете слушателя, не совпадает с FXMLLoader, созданным, введенным и добавленным в граф сцены.

Примечание: Вы никогда не хотите создавать экземпляры полей, которые будут внедрены FXMLLoader (то есть полей с соответствующими атрибутами fx:id). В лучшем случае это пустая трата ресурсов, а в худшем - незначительные ошибки. Если удаление логики создания экземпляра приводит к NullPointerException, значит, что-то не так с вашей настройкой.

Один из способов решения вашей проблемы - не использовать fx:controller, а вместо этого установить контроллер вручную:

@FXML private TextField imieTF; // don't instantiate manually

public void show() {
    FXMLLoader loader = new FXMLLoader(/* location */);
    loader.setController(this); // must set before calling load()
    Parent root = loader.load();

    // remaining code omitted
}

Другой другой вариант (и в этом случае я лично предпочитаю вышеизложенное) состоит в том, чтобы следовать Гербену Джонгериусу : сделать show() статическим методом и переместить add-listener-to- TextField логика в методе initialize(). Если вы не знаете, метод initialize() вызывается после того, как все соответствующие поля были введены.


Просто чтобы показать другой способ ведения дел:

Обратите внимание, что вам не нужно добавлять ChangeListener в коде; Вы также можете зарегистрировать прослушиватель свойств в файле FXML. Это задокументировано Введение в FXML .

FXML:

<TextField onTextChange="#handleTextChange"/>

Метод контроллера:

@FXML
private void handleTextChange(ObservableValue<? extends String> observable, 
                              String oldValue, String newValue) {
    // do something...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...