gpt4 book ai didi

java - 如何创建一个方法来接受并返回任何类型的 ObjectProperty

转载 作者:行者123 更新时间:2023-12-02 19:19:06 25 4
gpt4 key购买 nike

我的应用程序有一个包含多个 ObjectProperty<Enum> 的对象字段。我正在尝试编写一个执行以下操作的辅助方法:

  • 接受任何类型的 ObjectProperty<Enum>作为参数
  • 显示ChoiceDialog弹出窗口,允许用户为 enum 选择不同的文本值
  • 更新 enum 的值在过去ObjectProperty本身

我对泛型不太熟悉,但我相信以下方法可能有效(没有编译器错误):

public static <E extends Enum<E>> boolean editEnumProperty(String prompt,
ObjectProperty<Class<E>> property,
Window owner) {

// Create the dialog to ask for a new enum value
ChoiceDialog<E> dialog = new ChoiceDialog<>();
dialog.setTitle("Edit Value");
dialog.setHeaderText(null);
dialog.setContentText(prompt);
dialog.initOwner(owner);

// Currently, this displays the enum NAME in the ComboBox, rather than it's text value
dialog.getItems().setAll(FXCollections.observableArrayList(property.get().getEnumConstants()));

Stage dialogStage = (Stage) dialog.getDialogPane().getScene().getWindow();
dialogStage.getIcons().add(ImageHelper.appIcon());

Optional<E> result = dialog.showAndWait();
if (result.isPresent()) {
Utility.printTempMsg(result.toString());
Utility.printTempMsg(Enum.valueOf(property.get(), result.toString()).toString());
}

return true;
}

但是,我不知道如何传递ObjectProperty到这个方法。当尝试按如下方式传递我的属性时,我收到编译器错误:

linkEditRequestSource.setOnAction(event ->
editEnumProperty(
"Select new Request Source:",
simpleObject.requestSourceProperty(), // <-- no instance(s) of type variable(s) E exist so that RequestSource conforms to Class<E>
lblRequestSource.getScene().getWindow()
)
);

我也不知道如何设置 ObjectProperty 的值用户选择后。

下面是一个不起作用的 MCVE:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceDialog;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.Window;

import java.util.Optional;

enum RequestSource {
ACQUIRED("Acquisition"),
MANUAL("Manually Entered"),
MANAGER("Manager Reported");

private final String text;

RequestSource(String text) {
this.text = text;
}

public String getText() {
return text;
}
}

public class GenericEnumProperty extends Application {

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

public static <E extends Enum<E>> boolean editEnumProperty(String prompt,
ObjectProperty<Class<E>> property,
Window owner) {

// Create the dialog to ask for a new enum value
ChoiceDialog<E> dialog = new ChoiceDialog<>();
dialog.setTitle("Edit Value");
dialog.setHeaderText(null);
dialog.setContentText(prompt);
dialog.initOwner(owner);

dialog.getItems().setAll(FXCollections.observableArrayList(property.get().getEnumConstants()));

Optional<E> result = dialog.showAndWait();
if (result.isPresent()) {
// This should actually set the value of the underlying object's ObjectProperty<RequestSource> to
// the new value selected in the ComboBox
System.out.println(Enum.valueOf(property.get(), result.toString()).toString());

// Will use this value to track which properties have been modified
return true;
}

return false;

}

@Override
public void start(Stage primaryStage) {

// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));

// Label to display current value of RequestSource
Label lblRequestSource = new Label();

// Create a new object
SimpleObject simpleObject = new SimpleObject(RequestSource.ACQUIRED);

// Bind the property value to the label
lblRequestSource.textProperty().bind(simpleObject.requestSourceProperty().asString());

// Hyperlink to open value editor
Hyperlink linkEditRequestSource = new Hyperlink("Request Source:");
linkEditRequestSource.setOnAction(event ->
editEnumProperty(
"Select new Request Source:",
simpleObject.requestSourceProperty(), // <-- no instance(s) of type variable(s) E exist so that RequestSource conforms to Class<E>
lblRequestSource.getScene().getWindow()
)
);

root.getChildren().add(
new HBox(5, linkEditRequestSource, lblRequestSource)
);

// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
}

class SimpleObject {

private final ObjectProperty<RequestSource> requestSourceProperty = new SimpleObjectProperty<>();

public SimpleObject(RequestSource source) {
this.requestSourceProperty.set(source);
}

public RequestSource getRequestSourceProperty() {
return requestSourceProperty.get();
}

public void setRequestSourceProperty(RequestSource requestSourceProperty) {
this.requestSourceProperty.set(requestSourceProperty);
}

public ObjectProperty<RequestSource> requestSourceProperty() {
return requestSourceProperty;
}
}

所以这里确实有一些相关的问题:

  • 如何传递通用 ObjectProperty<Enum>到方法?
  • 是否可以显示枚举的文本值而不是枚举名称?
  • 如何设置 Property 的值在用户选择一个新的之后?

最佳答案

您需要传递给泛型方法的属性应该是 ObjectProperty<E> ,不是 ObjectProperty<Class<E>> 。然后你可以这样做:

public static <E extends Enum<E>> boolean editEnumProperty(String prompt,
ObjectProperty<E> property,
Window owner) {

// Create the dialog to ask for a new enum value
ChoiceDialog<E> dialog = new ChoiceDialog<>();
dialog.setTitle("Edit Value");
dialog.setHeaderText(null);
dialog.setContentText(prompt);
dialog.initOwner(owner);



dialog.getItems().setAll(property.get().getDeclaringClass().getEnumConstants());

Optional<E> result = dialog.showAndWait();
boolean changed = result.isPresent();
result.ifPresent(property::set);
return changed ;
}

现在您的示例代码可以按原样运行。

这里有一个警告:if property.get()返回null ,那么这将抛出一个空指针异常

dialog.getItems().setAll(property.get().getDeclaringClass().getEnumConstants());

如果你想支持值为空的“unset”属性,我认为你需要在方法中添加一个额外的参数来表示类型:

public static <E extends Enum<E>> boolean editEnumProperty(String prompt,
Class<E> enumType,
ObjectProperty<E> property,
Window owner) {

// Create the dialog to ask for a new enum value
ChoiceDialog<E> dialog = new ChoiceDialog<>();
dialog.setTitle("Edit Value");
dialog.setHeaderText(null);
dialog.setContentText(prompt);
dialog.initOwner(owner);



dialog.getItems().setAll(enumType.getEnumConstants());

Optional<E> result = dialog.showAndWait();
boolean changed = result.isPresent();
result.ifPresent(property::set);
return changed ;
}

在这种情况下,您只需要稍加修改:

    linkEditRequestSource.setOnAction(event ->
editEnumProperty(
"Select new Request Source:",
RequestSource.class,
simpleObject.requestSourceProperty(),
lblRequestSource.getScene().getWindow()
)
);

您剩下的一个问题是

Is it possible to display the enum's text values instead of the enum name?

因为并非所有枚举都有 getText()方法,没有特别简单的方法来 Hook getText()您定义的用于显示枚举值的方法。一般来说,您可以提供可选的 Function<E, String>通过重载参数:

public static <E extends Enum<E>> boolean editEnumProperty(
String prompt,
ObjectProperty<E> property,
Window owner) {

return editEnumProperty(prompt, property, Object::toString, owner);
}

public static <E extends Enum<E>> boolean editEnumProperty(
String prompt,
ObjectProperty<E> property,
Function<? super E, String> displayText,
Window owner) {

// now what...?
}

但因为也无法访问(据我所知)ChoiceDialog 显示的选择框(或组合框?) ,没有明显的方法来配置文本的显示方式。

此时您可以推出您自己的 ChoiceDialog 版本(获得对弹出控件的访问权限);例如:

public static <E extends Enum<E>> boolean editEnumProperty(String prompt, ObjectProperty<E> property,
Function<? super E, String> displayText, Window owner) {

Dialog<E> dialog = new Dialog<>();
ChoiceBox<E> choice = new ChoiceBox<>();
choice.setConverter(new StringConverter<E>() {

@Override
public String toString(E object) {
return displayText.apply(object);
}

@Override
public E fromString(String string) {
// Not actually needed...
return null;
}

});
choice.getItems().setAll(property.get().getDeclaringClass().getEnumConstants());
choice.getSelectionModel().select(property.get());
dialog.getDialogPane().setContent(new HBox(5, new Label(prompt), choice));
dialog.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, ButtonType.OK);
dialog.setResultConverter(button ->
button == ButtonType.OK ? choice.getSelectionModel().getSelectedItem() : null
);
return dialog.showAndWait().map(value -> {
property.set(value);
return true ;
}).orElse(false);

}

或者您可以尝试像这样的丑陋黑客,它将字符串值和相应的 eval 值存储在 Map 中。 :

public static <E extends Enum<E>> boolean editEnumProperty(String prompt, ObjectProperty<E> property,
Function<? super E, String> displayText, Window owner) {

// Create the dialog to ask for a new enum value
ChoiceDialog<String> dialog = new ChoiceDialog<>();
dialog.setTitle("Edit Value");
dialog.setHeaderText(null);
dialog.setContentText(prompt);
dialog.initOwner(owner);

Map<String, E> displayValueLookup = Stream.of(property.get().getDeclaringClass().getEnumConstants())
.collect(Collectors.toMap(displayText, Function.identity()));

dialog.getItems().setAll(displayValueLookup.keySet());

return dialog.showAndWait()
.map(displayValueLookup::get)
.map(value -> {
property.set(value);
return true ;
})
.orElse(false);
}

当然是现在

    linkEditRequestSource.setOnAction(event -> editEnumProperty(
"Select new Request Source:",
simpleObject.requestSourceProperty(),
RequestSource::getText,
lblRequestSource.getScene().getWindow()));

关于java - 如何创建一个方法来接受并返回任何类型的 ObjectProperty<?>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63287728/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com