在我的项目中,我有多个控制器来满足不同的需求。
基本上,有一个主 GUI,其控制器打开“子 GUI”。可以打开多个子GUI。
因此,为了保持整洁,我将一组信息存储在列表中以跟踪事物。
public class InterfaceInformation {
FXMLLoader fxmlLoader;
Stage interfaceStage;
Scene interfaceScene;
String name;
boolean SetForRemoval;
}
[...]
private Map<String, InterfaceInformation> InterfaceList = new HashMap<String, InterfaceInformation>();
[...]
每个“子”控制器都实现一个接口。
类似的东西:
public interface CtrlCommon {
public void doCommonThing01();
}
public class MyController extends BaseApplicationElements implements CtrlCommon {
public void doCommonThing01() {
// Do something
}
}
因此,当需要在每个子 GUI 中调用所有这些方法时,我使用该列表并尝试从 FXML 加载器获取控制器。但我被 doCommonThing01() 的调用困住了。
for (Map.Entry<String, InterfaceInformation> elm : InterfaceList.entrySet()) {
elm.getValue().getFxmlLoader().getController().<i_m_stuck_here>
}
我知道每个控制器都有实现接口的方法。但我无法让它工作。
我不知道尝试使用
<T>
或 <?>
是否有帮助(以及如何帮助)。
有什么技巧可以解决这个问题?
这不是对您问题的直接回答;它演示了如何实现“将一组信息存储在列表中以跟踪事物”的概念。
该实现使用了两种相当常见的编程模式:注册表模式和装饰器模式,并演示了它们的用法。
在此过程中,它将执行多次强制转换,以提供对存储在注册表中的类型化对象的访问,并提供对装饰器的类型化访问,以便可以在适当的存储对象和装饰器上调用适当的方法。
这并不是作为通用 JavaFX 接口框架而设计的。 该代码作为 Java 面向对象教程示例提供。 大多数 JavaFX 应用程序最好遵循不同的模式,并使用 MVC 设计模式将 UI 代码与应用程序逻辑分离,如果需要,可能使用 IOC 容器 来处理注册表,而不是在应用程序中实现注册表代码。
我不会在这里详细解释代码的设计和操作,但希望您可以通过阅读和研究来理解它。
InterfaceApp.java
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.*;
record InterfaceRecord(
FXMLLoader loader,
Stage stage,
Scene scene,
String name
) {}
interface Decorator {
Paint DEFAULT_PAINT = Color.BEIGE;
void paint(Paint paint);
}
interface Painted {
Paint getPaint();
}
interface Powered {
PowerPlant getPowerPlant();
}
class CarController implements Decorator, Painted, Powered {
private final ReadOnlyObjectWrapper<Paint> paint = new ReadOnlyObjectWrapper<>(DEFAULT_PAINT);
private final ReadOnlyObjectWrapper<PowerPlant> powerPlant;
public CarController(PowerPlant powerPlant) {
this.powerPlant = new ReadOnlyObjectWrapper<>(powerPlant);
}
@Override
public void paint(Paint paint) {
this.paint.set(paint != null ? paint : DEFAULT_PAINT);
}
@Override
public Paint getPaint() {
return paint.get();
}
public ReadOnlyObjectProperty<Paint> paintProperty() {
return paint.getReadOnlyProperty();
}
@Override
public PowerPlant getPowerPlant() {
return powerPlant.get();
}
public ReadOnlyObjectWrapper<PowerPlant> powerPlantProperty() {
return powerPlant;
}
}
class SubmarineController implements Decorator, Painted {
private Paint paint = Color.BEIGE;
@Override
public void paint(Paint paint) {
this.paint = paint != null ? paint : DEFAULT_PAINT;
}
@Override
public Paint getPaint() {
return paint;
}
}
interface PowerPlant {}
class NuclearPowerPlant implements Decorator, Painted, PowerPlant {
private Paint paint = Color.BLUE;
@Override
public void paint(Paint paint) {
this.paint = paint != null ? paint : DEFAULT_PAINT;
}
@Override
public Paint getPaint() {
return paint;
}
}
class InterfaceRegistry {
private static final InterfaceRegistry instance = new InterfaceRegistry();
private final Map<String, InterfaceRecord> interfaces = new HashMap<>();
private final ObservableList<InterfaceRecord> interfaceList = FXCollections.observableArrayList();
private InterfaceRegistry() {}
public void register(InterfaceRecord interfaceRecord) {
interfaces.put(
interfaceRecord.name(),
interfaceRecord
);
interfaceList.add(interfaceRecord);
}
public void deregister(String name) {
interfaceList.remove(lookup(name));
interfaces.remove(name);
}
public InterfaceRecord lookup(String interfaceName) {
return interfaces.get(interfaceName);
}
public <T> T lookupController(String interfaceName) {
return interfaces.get(interfaceName).loader().getController();
}
public ObservableList<InterfaceRecord> getInterfaces() {
return interfaceList;
}
public static InterfaceRegistry getInstance() {
return instance;
}
}
class InterfaceLoader {
public static InterfaceRecord load(
String interfaceName,
Object controller
) throws IOException {
InterfaceRegistry registry = InterfaceRegistry.getInstance();
InterfaceRecord interfaceRecord = registry.lookup(interfaceName);
if (interfaceRecord != null) {
return interfaceRecord;
}
FXMLLoader loader = new FXMLLoader(
InterfaceRegistry.class.getResource(
interfaceName + ".fxml"
)
);
loader.setController(controller);
Stage stage = new Stage();
stage.setScene(new Scene(loader.load()));
registry.register(
new InterfaceRecord(
loader,
stage,
stage.getScene(),
interfaceName
)
);
return registry.lookup(interfaceName);
}
}
class InterfaceCell extends ListCell<InterfaceRecord> {
private final TextFlow textFlow = new TextFlow();
@Override
protected void updateItem(InterfaceRecord item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
textFlow.getChildren().clear();
return;
}
ObservableList<Node> texts = textFlow.getChildren();
texts.add(new Label(item.name()));
Object controller = item.loader().getController();
if (controller instanceof Painted painted) {
texts.add(new Label(", "));
Text paintedText = new Text("painted " + painted.getPaint());
paintedText.setFill(painted.getPaint());
texts.add(paintedText);
}
if (controller instanceof Powered powered) {
texts.add(new Label(", "));
PowerPlant powerPlant = powered.getPowerPlant();
Text poweredByText = new Text("powered by a " + powerPlant.getClass().getSimpleName());
poweredByText.setFill(Color.ORANGE);
texts.add(poweredByText);
if (powerPlant instanceof Painted powerPlantPainted) {
Text paintedText = new Text(" painted " + powerPlantPainted.getPaint());
paintedText.setFill(powerPlantPainted.getPaint());
texts.add(paintedText);
}
}
setGraphic(textFlow);
}
}
public class InterfaceAccessApp extends Application {
private final InterfaceRegistry registry = InterfaceRegistry.getInstance();
@Override
public void start(Stage stage) throws Exception {
InterfaceLoader.load(
"power",
new NuclearPowerPlant()
);
InterfaceLoader.load(
"car",
new CarController(
registry.lookupController(
"power"
)
)
);
InterfaceLoader.load(
"submarine",
new SubmarineController()
);
Decorator autobodyShop = registry.lookupController("car");
autobodyShop.paint(Color.RED);
Decorator submarinePen = registry.lookupController("submarine");
submarinePen.paint(Color.GREEN);
ListView<InterfaceRecord> interfaceView = new ListView<>(registry.getInterfaces());
interfaceView.setCellFactory(param -> new InterfaceCell());
interfaceView.setPrefSize(500, 100);
Pane layout = new VBox(
10,
interfaceView
);
layout.setPadding(new Insets(10));
layout.setStyle("-fx-base: azure");
stage.setTitle("Interfaces");
stage.setScene(new Scene(layout));
stage.show();
System.out.println("Interfaces " + registry.getInterfaces());
}
@Override
public void stop() throws Exception {
List<InterfaceRecord> interfacesToRemove = new ArrayList<>(
registry.getInterfaces()
);
interfacesToRemove
.forEach(i ->
registry.deregister(
i.name()
)
);
}
public static void main(String[] args) throws IOException {
launch(args);
}
}
每个 fxml 文件 car.fxml、submarine.fxml 和 power.fxml 对于本演示来说只是空 UI 文件。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane/>