【问题标题】:What do obs, ov and nv stand for in javafx listeners?obs、ov 和 nv 在 javafx 侦听器中代表什么?
【发布时间】:2015-01-08 01:05:31
【问题描述】:

这是一些 javafx 书籍中的示例:

package sample;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.PasswordField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.SVGPath;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

/**
 * A login form to demonstrate lambdas, properties and bindings.
 * @author cdea
 */
public class Main extends Application {

    private final static String MY_PASS = "xyz";
    private final static BooleanProperty GRANTED_ACCESS = new SimpleBooleanProperty(false);
    private final static int MAX_ATTEMPTS = 3;
    private final IntegerProperty ATTEMPTS = new SimpleIntegerProperty(0);

    @Override
    public void start(Stage primaryStage) {
        // create a model representing a user
        User user = new User();

        // create a transparent stage
        primaryStage.initStyle(StageStyle.TRANSPARENT);

        Group root = new Group();
        Scene scene = new Scene(root, 320, 112, Color.rgb(0, 0, 0, 0));
        primaryStage.setScene(scene);

        // all text, borders, svg paths will use white
        Color foregroundColor = Color.rgb(255, 255, 255, .9);

        // rounded rectangular background
        Rectangle background = new Rectangle(320, 112);
        background.setX(0);
        background.setY(0);
        background.setArcHeight(15);
        background.setArcWidth(15);
        background.setFill(Color.rgb(0, 0, 0, .55));
        background.setStrokeWidth(9.5);
//        background.setStroke(foregroundColor);
        background.setStroke(Color.rgb(12, 233, 233));

        // a read only field holding the user name.
        Text userName = new Text();
        userName.setFont(Font.font("SanSerif", FontWeight.BOLD, 30));
        userName.setFill(foregroundColor);
        userName.setSmooth(true);
        userName.textProperty().bind(user.userNameProperty());

        // wrap text node
        HBox userNameCell = new HBox();
        userNameCell.prefWidthProperty().bind(primaryStage.widthProperty().subtract(45));
        userNameCell.getChildren().add(userName);

        // pad lock
        SVGPath padLock = new SVGPath();
        padLock.setFill(foregroundColor);
        padLock.setContent("M24.875,15.334v-4.876c0-4.894-3.981-8.875-8.875-8.875s-8.875,3.981-8.875,8.875v4.876H5.042v15.083h21.916V15.334H24.875zM10.625,10.458c0-2.964,2.411-5.375,5.375-5.375s5.375,2.411,5.375,5.375v4.876h-10.75V10.458zM18.272,26.956h-4.545l1.222-3.667c-0.782-0.389-1.324-1.188-1.324-2.119c0-1.312,1.063-2.375,2.375-2.375s2.375,1.062,2.375,2.375c0,0.932-0.542,1.73-1.324,2.119L18.272,26.956z");

        // first row
        HBox row1 = new HBox();
        row1.getChildren().addAll(userNameCell, padLock);


        // password text field
        PasswordField passwordField = new PasswordField();
        passwordField.setFont(Font.font("SanSerif", 20));
        passwordField.setPromptText("Password");
        passwordField.setStyle("-fx-text-fill:black; "
                + "-fx-prompt-text-fill:gray; "
                + "-fx-highlight-text-fill:black; "
                + "-fx-highlight-fill: gray; "
                + "-fx-background-color: rgba(255, 255, 255, .80); ");
        passwordField.prefWidthProperty().bind(primaryStage.widthProperty().subtract(55));
        user.passwordProperty().bind(passwordField.textProperty());

        // error icon
        SVGPath deniedIcon = new SVGPath();
        deniedIcon.setFill(Color.rgb(255, 0, 0, .9));
        deniedIcon.setStroke(Color.WHITE);//
        deniedIcon.setContent("M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z");
        deniedIcon.setVisible(false);

        SVGPath grantedIcon = new SVGPath();
        grantedIcon.setFill(Color.rgb(0, 255, 0, .9));
        grantedIcon.setStroke(Color.WHITE);//
        grantedIcon.setContent("M2.379,14.729 5.208,11.899 12.958,19.648 25.877,6.733 28.707,9.561 12.958,25.308z");
        grantedIcon.setVisible(false);

        StackPane accessIndicator = new StackPane();
        accessIndicator.getChildren().addAll(deniedIcon, grantedIcon);
        accessIndicator.setAlignment(Pos.CENTER_RIGHT);

        grantedIcon.visibleProperty().bind(GRANTED_ACCESS);

        // second row
        HBox row2 = new HBox(3);
        row2.getChildren().addAll(passwordField, accessIndicator);
        HBox.setHgrow(accessIndicator, Priority.ALWAYS);

        // user hits the enter key
        passwordField.setOnAction(actionEvent -> {
            if (GRANTED_ACCESS.get()) {
                System.out.printf("User %s is granted access.\n", user.getUserName());
                System.out.printf("User %s entered the password: %s\n", user.getUserName(), user.getPassword());
                Platform.exit();
            } else {
                deniedIcon.setVisible(true);
            }
            ATTEMPTS.set(ATTEMPTS.add(1).get());
            System.out.println("Attempts: " + ATTEMPTS.get());
        });

        // listener when the user types into the password field
        passwordField.textProperty().addListener((obs, ov, nv) -> {
            boolean granted = passwordField.getText().equals(MY_PASS);
            GRANTED_ACCESS.set(granted);
            if (granted) {
                deniedIcon.setVisible(false);
            }
        });

        // listener on number of attempts
        ATTEMPTS.addListener((obs, ov, nv) -> {
            if (MAX_ATTEMPTS == nv.intValue()) {
                // failed attemps
                System.out.printf("User %s is denied access.\n", user.getUserName());
                Platform.exit();
            }
        });

        VBox formLayout = new VBox(4);
        formLayout.getChildren().addAll(row1, row2);
        formLayout.setLayoutX(12);
        formLayout.setLayoutY(12);

        root.getChildren().addAll(background, formLayout);

        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

这两位听众我不太了解:

    // listener when the user types into the password field
    passwordField.textProperty().addListener((obs, ov, nv) -> {
        boolean granted = passwordField.getText().equals(MY_PASS);
        GRANTED_ACCESS.set(granted);
        if (granted) {
            deniedIcon.setVisible(false);
        }
    });

    // listener on number of attempts
    ATTEMPTS.addListener((obs, ov, nv) -> {
        if (MAX_ATTEMPTS == nv.intValue()) {
            // failed attemps
            System.out.printf("User %s is denied access.\n", user.getUserName());
            Platform.exit();
        }
    });

在第一个监听器中,没有使用 obs、ov 或 nv,在第二个监听器中,只使用了 nv。 obs、ov 和 nv 到底是什么?

【问题讨论】:

    标签: lambda javafx listener


    【解决方案1】:

    顺便说一句,很高兴你正在阅读这本书!

    正如第 3 章开头所述,Java 8 中引入的称为 lambda 表达式 或简称为 lambdas 的新语言特性允许您避免使用像这样的匿名内部类:

    passwordField.textProperty().addListener(new ChangeListener<String>() {
    
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            boolean granted = passwordField.getText().equals(MY_PASS);
            GRANTED_ACCESS.set(granted);
            if (granted) {
                deniedIcon.setVisible(false);
            }
        }
    });
    

    通过使用这样的表达式:

    passwordField.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
        boolean granted = passwordField.getText().equals(MY_PASS);
        GRANTED_ACCESS.set(granted);
        if (granted) {
            deniedIcon.setVisible(false);
        }
    });
    

    此外,参数可以选择键入。编译器将推断类型 通过匹配方法的参数类型(它的签名)和它的返回类型,参数的数量取决于上下文。正因为如此,就像在内部类中一样,我们必须使用所有需要的参数,即使它们没有在你的函数体中使用。

    所以我们也可以这样写:

    passwordField.textProperty().addListener((observable, oldValue, newValue) -> {
        boolean granted = passwordField.getText().equals(MY_PASS);
        GRANTED_ACCESS.set(granted);
        if (granted) {
            deniedIcon.setVisible(false);
        }
    });
    

    最后,正如@brian 所说,你给参数起的名字是任意的,为了方便我们可以简化一下:

    passwordField.textProperty().addListener((obs, ov, nv) -> {
        boolean granted = passwordField.getText().equals(MY_PASS);
        GRANTED_ACCESS.set(granted);
        if (granted) {
            deniedIcon.setVisible(false);
        }
    });
    

    他也对使用nv

    passwordField.textProperty().addListener((obs, ov, nv) -> {
        boolean granted = nv.equals(MY_PASS);
        GRANTED_ACCESS.set(granted);
        if (granted) {
            deniedIcon.setVisible(false);
        }
    });
    

    【讨论】:

      【解决方案2】:

      https://docs.oracle.com/javafx/2/api/javafx/beans/value/ChangeListener.html

      changed(ObservableValue&lt;? extends T&gt; observable, T oldValue, T newValue)

      这是因为在使用 lambdas 时,您不必提供类型。如果您是手动输入键盘,那么使用 obs、ov、nv 会更容易。在我编写的几乎所有 changeListener 中,我通常只访问 newValue - nv。

      代码示例可以更改

      boolean granted = passwordField.getText().equals(MY_PASS);

      可能

      boolean granted = nv.equals(MY_PASS);

      【讨论】:

        猜你喜欢
        • 2019-04-21
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 2017-07-13
        • 2013-12-17
        • 2011-02-25
        • 2017-11-22
        相关资源
        最近更新 更多