英文:
How to implement a Previous or Next button event properly using JavaFX
问题
使用JavaFX编写我的第一个程序。该程序显示一个对象(Person)的数据,我想要实现一个“上一个”按钮,该按钮应该以静态ArrayList“arrayListOfPeople”的上一个对象刷新Pane。
作为一个新手,我希望我可以简单地执行currentPersonPosition-1并像这样加载窗口:
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 变量,因为似乎内部方法只能使用 final 实例变量... 那么如何正确处理这个问题呢?
我写了一些肯定不是正确方法的东西:我将按钮文本设置为 currentPersonPosition-1,然后在 handle 方法中读取和解析该值。
在花了很多时间想出这个愚蠢的解决方法之后,我想知道如何正确地做。
下面是一个最小的可复现示例,它打开一个窗口,在窗口标题栏中显示 Name1/Name2/Name3,并在左下角包含一个作为“上一个”按钮工作的小按钮。
提前感谢您的帮助!
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;
// 底部
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();
}
}
英文:
Writing my first program using JavaFX here. The program shows data of an object (Person) and I want to implement a 'previous' button that should refresh the Pane with the previous object in a static ArrayList 'arrayListOfPeople'.
As a noob, I hoped I could simply do currentPersonPosition-1 and loadWindow like this:
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);
}
};
But, the handle() method can't use the currentPersonPosition variable as it seems the the inner method can only use final instance variables... Then how do you deal with this properly?
I wrote something that certainly isn't a proper way of doing it: I've set the button text to be the currentPersonPosition-1, and then read&parse the value within the handle method.
After spending a lot of time to come with this dopey workaround, I wonder how it's done properly.
The minimal producible example below opens a window and shows Name1/Name2/Name3 in the window title bar, and contains a tiny button at the bottom left that functions as the 'previous' button.
Thanks in advance!
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();
}
}
答案1
得分: 0
有多种方法可以解决这个问题,但它们的工作方式都相同;您需要将该值封装在一个对象内。
如果您使用的是Java 10或更高版本,您可以使用匿名内部类以及局部变量类型推断。像这样声明变量:
final var currentPersonPosition = new Object() {
int value;
};
现在,您可以使用 currentPersonPosition.value
引用该变量。这样做的缺点是您将无法将该对象作为参数传递,同时仍然可以访问 value
字段。
另一个选项是改用单元素数组:
final int[] currentPersonPosition = new int[1];
现在,您可以使用 currentPersonPosition[0]
引用该变量。
英文:
There are various ways to work around this, but they all work the same way; you need to encapsulate the value inside an Object.
If you are using Java 10 or later, you can use an anonymous inner class together with local variable type inference. Declare the variable like this:
final var currentPersonPosition = new Object() {
int value;
};
Now, you can reference the variable using currentPersonPosition.value
. The downside to doing this is that you won't be able to pass the Object as a parameter and still have access to the value
field.
The other option is to use a single element array instead:
final int[] currentPersonPosition = new int[1];
Now you can reference the variable using currentPersonPosition[0]
.
答案2
得分: 0
The key to solving this is by using a counter variable to keep up with the current position. You should not allow that counter variable to become greater than the list size - 1 or less than 0. If you are a beginner, I would recommend creating the button handler using an anonymous inner class like in the following example.
**Main**
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();
}
}
**Person**
/**
*
* @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 + '}';
}
}
英文:
The key to solving this is by using a counter variable to keep up with the current position. You should not allow that counter variable to become greater than the list size - 1 or less than 0. If you are a beginner, I would recommend creating the button handler using an anonymous inner class like in the following example.
Main
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();
}
}
Person
/**
*
* @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 + '}';
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论