控制器方法具有不同类型时如何使用

问题描述 投票:0回答:1

在我的项目中,我有多个控制器来满足不同的需求。

基本上,有一个主 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>
<?>
是否有帮助(以及如何帮助)。

有什么技巧可以解决这个问题?

java javafx types controller
1个回答
0
投票

这不是对您问题的直接回答;它演示了如何实现“将一组信息存储在列表中以跟踪事物”的概念。

该实现使用了两种相当常见的编程模式:注册表模式装饰器模式,并演示了它们的用法。

在此过程中,它将执行多次强制转换,以提供对存储在注册表中的类型化对象的访问,并提供对装饰器的类型化访问,以便可以在适当的存储对象和装饰器上调用适当的方法。

这并不是作为通用 JavaFX 接口框架而设计的。 该代码作为 Java 面向对象教程示例提供。 大多数 JavaFX 应用程序最好遵循不同的模式,并使用 MVC 设计模式将 UI 代码与应用程序逻辑分离,如果需要,可能使用 IOC 容器 来处理注册表,而不是在应用程序中实现注册表代码。

ui

我不会在这里详细解释代码的设计和操作,但希望您可以通过阅读和研究来理解它。

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.fxmlsubmarine.fxmlpower.fxml 对于本演示来说只是空 UI 文件。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>

<BorderPane/>
© www.soinside.com 2019 - 2024. All rights reserved.