简体   繁体   English

JavaFx从单个FXML生成多个场景

[英]JavaFx Generate multiple scene from single FXML

I started a javafx project that interact with a database (add new, edit, delete, find,...). 我启动了一个与数据库交互的javafx项目(添加,编辑,删除,查找等)。
My database contains a lot of tables, and each table requires its own scene (which are almost the same!!!). 我的数据库包含很多表,每个表需要自己的场景(几乎相同!!!)。
so My problem is: instead of implementing ~20 fxml file, is it possible to make a single fxml file that will change its content based on the Class name (for example) passed to its controller? 所以我的问题是:不是实现〜20 fxml文件,而是可以制作一个单独的fxml文件,该文件将根据传递给其控制器的类名(例如)来更改其内容?
if yes, any tips to achieve it? 如果是,有什么技巧可以实现吗?
Here is what I have tried: 这是我尝试过的:
added a HashMap for each TableClass containing all the attributes needed to be in the scene and and iterate through it in a ControllerClass to add the control to the scene!!! 为每个TableClass添加了一个HashMap,其中包含场景中所需的所有属性,并在ControllerClass中对其进行迭代以将控件添加到场景中! but FAILED! 但是失败了!
TableSampleClass: TableSampleClass:

public class TableSampleClass{
public static final HashMap<String, String> attr;
static {
    attr = new HashMap<String, String>();
    attr.put("ref", "text");
    attr.put("name", "text");
    attr.put("adress", "text");
    attr.put("Mobile", "tel");
    attr.put("mail", "mail");
    attr.put("isalive", "checkbox");//just to illustrate what i want !
    }
     ........
   }

ControllerClass: ControllerClass:

@FXML
private AnchorPane pane;
@Override
public void initialize(URL location, ResourceBundle resources)
{     Iterator it = TableSampleClass.attr.entrySet().iterator();
    while(it.hasNext())
    {
        Map.Entry pair = (Map.Entry)it.next();
        switch (pair.getValue().toString()){
        case "text":
            TextField txt =new TextField(pair.getValue().toString());
            txt.setPromptText(pair.getKey().toString());
            Label lbl =new Label(pair.getKey().toString());
            pane.getChildren().add(txt);
            break;
        }
    }
}

I hope I did explain myself clearly !! 我希望我确实清楚地解释了自己!

Use the Custom component FXML pattern . 使用自定义组件FXML模式 The way this works is that you write a controller class which loads the corresponding FXML file in the constructor. 它的工作方式是编写一个控制器类,该类将相应的FXML文件加载到构造函数中。 Since you use this by calling the constructor, you can allow the constructor to take parameters and use those parameters to configure the component after loading the FXML. 由于通过调用构造函数来使用此功能,因此可以允许构造函数获取参数,并在加载FXML之后使用这些参数来配置组件。

The code you showed isn't really very clear to me, but this structure would look something like: 您显示的代码对我来说不是很清楚,但是这种结构看起来像:

public class MyCustomTableDisplay extends AnchorPane {

    @FXML
    private AnchorPane pane ;

    public MyCustomTableDisplay(Map<String, String> config) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
            loader.setRoot(this); 
            loader.setController(this);
            loader.load();
        } catch (IOException exc) {
            throw new RuntimeException(exc);
        }

        // now configure pane based on config passed in...
    }
}

The FXML file has to use a "dynamic root", which means the root element is determined by calling setRoot(...) on the FXMLLoader (as seen in the code above). FXML文件必须使用“动态根”,这意味着根元素是通过在FXMLLoader上调用setRoot(...)FXMLLoader (如上面的代码所示)。 So it looks like 所以看起来

<!-- imports omitted -->
<fx:root type="AnchorPane" xmlns:fx="..." ... >
    <!-- usual fxml stuff -->
    <AnchorPane fx:id="pane" ...>

    <AnchorPane>
</fx:root>

Now you just do 现在你要做

Map<String, String> config = new HashMap<>();
// populate config...
MyCustomTableDisplay display = new MyCustomTableDisplay(config);
Scene scene = new Scene(display);
// etc...

The type of the fx:root can be basically any node type, but must match the type of the class. type的的fx:root可以是基本上任何节点类型,但必须类的类型相匹配。 Then you can include any fxml content you want. 然后,您可以包含所需的任何fxml内容。 The class acts as the controller, so you can inject values from the FXML in the usual way: they will be initialized (as usual) when the load() method is invoked on the loader. 该类充当控制器,因此您可以按常规方式从FXML注入值:在加载程序上调用load()方法时,它们将被初始化(照常)。

Potential Approaches 潜在方法

There are some third party libraries which generate forms and interface UIs for JavaFX dynamically, such as FXForm2 and ControlsFX PropertySheets . 有一些第三方库可以为JavaFX动态生成表单和界面UI,例如FXForm2ControlsFX PropertySheets

It is also possible to generate a table from data dynamically , which seems like it might be what you are actually trying to do. 也可以从数据动态生成 ,这似乎是您实际上要尝试执行的操作。

On FXML 在FXML上

For most of those systems, you don't define the internal GUI of the widget using FXML. 对于大多数这些系统,您无需使用FXML定义小部件的内部GUI。 Instead the low-level fields are dynamically generated, either by introspection on data or Java classes. 相反,可以通过对数据或Java类进行自省来动态生成低级字段。 All you would do is add the appropriate library to SceneBuilder and import the high level control (eg the ControlsFX PropertySheet), just declaring only that in FXML and not defining the detailed fields for the control within FXML. 您要做的就是将适当的库添加到SceneBuilder中,并导入高级控件(例如ControlsFX PropertySheet),仅在FXML中声明,而不在FXML中定义控件的详细字段。

If needed, and the systems in the linked libraries aren't what you need, you can also create custom controls and import those for use in SceneBuilder , though those will still likely work in a similarly manner of dynamically generating the detail fields from data or Java class introspection via reflection . 如果需要,并且链接库中的系统不是您所需要的,则您还可以创建自定义控件并将其导入在SceneBuilder中使用 ,尽管它们仍然可能以类似的方式工作,即从数据或数据中动态生成详细信息字段。通过反射进行 Java类自省。

On Dynamic Field Generation via Introspection 通过自省生成动态场

Creating a custom control based upon reflection is an advanced topic recommended only for experienced Java and JavaFX developers. 基于反射创建自定义控件是一个高级主题,仅建议有经验的Java和JavaFX开发人员使用。 You can view the PropertySheet implementation for example code for such an approach, that uses java beans and an Introspector via a BeanPropertyUtils utility class. 您可以查看PropertySheet实现的示例代码,以了解这种方法,该方法通过BeanPropertyUtils实用程序类使用Java BeanIntrospector Java beans are a pretty large topic, I can't run through in detail here. Java bean是一个很大的话题,在这里我无法详细介绍。 Only some features of the java beans specification are required to achieve what you need, as other parts of the specification are obsoleted by newer JavaFX features such as properties and binding. 只有Java Bean规范的某些功能才能实现所需的功能,因为该规范的其他部分已被较新的JavaFX功能(如属性和绑定)所取代。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM