在javafx听众中,obs,ov和nv代表什么?

时间:2014-11-11 13:05:05

标签: lambda javafx listener

以下是一些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究竟在这里?

2 个答案:

答案 0 :(得分:1)

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

changed(ObservableValue<? extends T> observable, T oldValue, T newValue)

这是因为在使用lambda时你不必提供类型。如果你手动键盘输出,那么使用obs,ov,nv更容易。在我写的任何changeListener中,我通常只访问newValue - nv。

可以更改代码示例

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

可能是

boolean granted = nv.equals(MY_PASS);

答案 1 :(得分:0)

很高兴你顺便读完这本书!

正如它在第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);
    }
});