如何使用 JavaFX 正确实现 Previous 或 Next 按钮事件

How to implement a Previous or Next button event properly using JavaFX

在这里使用 JavaFX 编写我的第一个程序。该程序显示 object(人)的数据,我想实现一个 'previous' 按钮,该按钮应使用静态 ArrayList 'arrayListOfPeople' 中的前一个 object 刷新窗格。

作为菜鸟,我希望我可以像这样简单地执行 currentPersonPosition-1 和 loadWindow:

Button btnBottom = new Button(Integer.toString(currentPersonPosition-1));
    final EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent e) {
            loadWindow(currentPersonPosition, borderPane, anotherStage);
        }
    };

但是,handle() 方法不能使用 currentPersonPosition 变量,因为 inner 方法似乎只能使用 final 实例变量...那么你如何正确处理这个问题?

我写的东西肯定不是正确的做法:我将按钮文本设置为 currentPersonPosition-1,然后在 handle 方法中读取并解析该值。 在花了很多时间来解决这个愚蠢的解决方法之后,我想知道它是如何正确完成的。

下面的最小可生成示例打开 window 并在 window 标题栏中显示 Name1/Name2/Name3,并在左下角包含一个小按钮,用作 [=26] =] 按钮。

提前致谢!

public class Main extends Application {
Scene scene = null;
static ArrayList<String> arrayListOfPeople = new ArrayList<>();

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

@Override
public void start(final Stage primaryStage) {
    int currentPersonPosition = arrayListOfPeople.size() - 1;
    final BorderPane borderPane = new BorderPane();
    scene = new Scene(borderPane, 640, 480);
    arrayListOfPeople.add("Name1");
    arrayListOfPeople.add("Name2");
    arrayListOfPeople.add("Name3");
    loadWindow(currentPersonPosition, borderPane, primaryStage);
}

public void loadWindow(int currentPersonPosition, final BorderPane borderPane, final Stage anotherStage) {
    if (currentPersonPosition < 0) currentPersonPosition = arrayListOfPeople.size()-1;

    // BOTTOM
    Button btnBottom = new Button(Integer.toString(currentPersonPosition-1));
    final EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent e) {
            String[] testString = e.getTarget().toString().split(",");
            System.out.println(testString[0]);
            if (testString[0].contains("\"")) {
                int positionOfFirstTextQuote = testString[0].indexOf("\"");
                int positionOfLastTextQuote = testString[0].lastIndexOf("\"");
                String currentClipPositionString = testString[0].substring(positionOfFirstTextQuote + 1, positionOfLastTextQuote);
                int currentPersonPosition = Integer.parseInt(currentClipPositionString);

                loadWindow(currentPersonPosition, borderPane, anotherStage);
            }
        }
    };
    btnBottom.addEventHandler(MouseEvent.MOUSE_CLICKED, eventHandler);
    borderPane.setBottom(btnBottom);

    anotherStage.setTitle(arrayListOfPeople.get(currentPersonPosition));
    anotherStage.setScene(scene);
    anotherStage.show();
}

}

有多种方法可以解决这个问题,但它们的工作方式都是一样的;您需要将值封装在对象中。

如果您使用的是 Java 10 或更高版本,则可以将匿名内部 class 与局部变量类型推断一起使用。像这样声明变量:

final var currentPersonPosition = new Object() {
    int value;
};

现在,您可以使用 currentPersonPosition.value 引用变量。这样做的缺点是您将无法将对象作为参数传递并且仍然可以访问 value 字段。

另一种选择是改用单个元素数组:

final int[] currentPersonPosition = new int[1];

现在您可以使用 currentPersonPosition[0] 引用变量。

解决这个问题的关键是使用计数器变量来跟上当前位置。您不应允许该计数器变量变得大于列表大小 - 1 或小于 0。如果您是初学者,我建议使用匿名内部 class 创建按钮处理程序,如下例所示。

主要

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;


/**
 * JavaFX App
 * @Author Sedrick (SedJ601)
 */
public class App extends Application {

    List<Person> listOfPeople = new ArrayList();
    AtomicInteger currentPosition = new AtomicInteger();
    Label lblName;
    Label lblAge;
    
    @Override
    public void start(Stage stage) {
        listOfPeople.add(new Person("John Doe", 22));
        listOfPeople.add(new Person("Jane Doe", 21));
        listOfPeople.add(new Person("Kim Doe", 5));
        listOfPeople.add(new Person("John Doe Jr", 3));
        
        //Load the first Person
        stage.setTitle(listOfPeople.get(currentPosition.get()).getName());
        Label lblNameTag = new Label("Name: ");
        lblName = new Label(listOfPeople.get(currentPosition.get()).getName());
        Label lblAgeTag = new Label("Age: ");
        lblAge = new Label(Integer.toString(listOfPeople.get(currentPosition.get()).getAge()));    
        
        //Use a GridPane to display the name and age.
        GridPane gridPane = new GridPane();
        gridPane.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE);
        gridPane.add(lblNameTag, 0, 0);
        gridPane.add(lblName, 1, 0);
        gridPane.add(lblAgeTag, 0, 1);
        gridPane.add(lblAge, 1, 1);
        
        //Create Previous and Next Buttons with their handlers
        Button btnPrevious = new Button("<");
        btnPrevious.setOnAction((t) -> {
            System.out.println(currentPosition.get());
            if(currentPosition.get() > 0)
            {                
                currentPosition.decrementAndGet();
                stage.setTitle(listOfPeople.get(currentPosition.get()).getName());
                lblName.setText(listOfPeople.get(currentPosition.get()).getName());
                lblAge.setText(Integer.toString(listOfPeople.get(currentPosition.get()).getAge())); 
            }
        });
        Button btnNext = new Button(">");
        btnNext.setOnAction((t) -> {
            System.out.println(currentPosition.get());
            if(currentPosition.get() < listOfPeople.size() - 1)
            {                
                currentPosition.incrementAndGet();
                stage.setTitle(listOfPeople.get(currentPosition.get()).getName());
                lblName.setText(listOfPeople.get(currentPosition.get()).getName());
                lblAge.setText(Integer.toString(listOfPeople.get(currentPosition.get()).getAge())); 
            }
        });
        HBox hBox = new HBox(btnPrevious, btnNext);
        hBox.setAlignment(Pos.CENTER);
        
        BorderPane root = new BorderPane();
        root.setCenter(gridPane);
        root.setBottom(hBox);
        
        var scene = new Scene(root, 640, 480);
        stage.setScene(scene);
        stage.show();
    }

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

}

/**
 *
 * @author sedrick (SedJ601)
 */
class Person 
{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" + "name=" + name + ", age=" + age + '}';
    }    
}