如何使用 FXML 在 JavaFX 2.0 中创建自定义组件?

2024-01-18

我似乎找不到有关该主题的任何材料。举一个更具体的例子,假设我想创建一个结合了复选框和标签的简单组件。然后,使用此自定义组件的实例填充 ListView。

更新: 请参阅我的答案以获取完整代码

更新2: 如需最新教程,请咨询官方文档 http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm。有很多新的东西 http://docs.oracle.com/javafx/2/fxml_get_started/whats_new2.htm这是在 2.2 中添加的。最后,FXML 简介 http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html几乎涵盖了您需要了解的有关 FXML 的所有内容。

更新3: 亨德里克·埃伯斯(Hendrik Ebbers)做了一个非常有帮助的博客文章 http://www.guigarage.com/2012/11/custom-ui-controls-with-javafx-part-1/关于自定义 UI 控件。


Update:如需最新教程,请咨询官方文档 http://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm。有很多新的东西 http://docs.oracle.com/javafx/2/fxml_get_started/whats_new2.htm这是在 2.2 中添加的。另外,FXML 简介 http://docs.oracle.com/javafx/2/api/javafx/fxml/doc-files/introduction_to_fxml.html几乎涵盖了您需要了解的有关 FXML 的所有内容。最后,Hendrik Ebbers 做了一个非常有帮助的博客文章 http://www.guigarage.com/2012/11/custom-ui-controls-with-javafx-part-1/关于自定义 UI 控件。


经过几天的环顾API http://docs.oracle.com/javafx/2.0/api/并阅读一些文档(FXML 简介 http://docs.oracle.com/javafx/2.0/api/javafx/fxml/doc-files/introduction_to_fxml.html, FXML 入门 http://docs.oracle.com/javafx/2.0/fxml_get_started/jfxpub-fxml_get_started.htm 属性绑定 http://docs.oracle.com/javafx/2.0/binding/jfxpub-binding.htm, FXML 的未来 http://fxexperience.com/2011/10/fxml-why-it-rocks-and-the-next-phase/)我想出了一个相当明智的解决方案。 我从这个小实验中学到的最不直接的信息是控制器的实例(在 FXML 中用 fx:controller 声明)由FXML加载器 http://docs.oracle.com/javafx/2.0/api/javafx/fxml/FXMLLoader.html加载 FXML 文件...最糟糕的是,这个重要事实仅在一个地方 http://docs.oracle.com/javafx/2.0/api/javafx/fxml/doc-files/introduction_to_fxml.html#controllers在我看到的所有文档中:

控制器通常仅对创建它的 FXML 加载程序可见

因此,请记住,为了以编程方式(从 Java 代码)获取对在 FXML 中声明的控制器实例的引用fx:controller use FXMLLoader.getController() http://docs.oracle.com/javafx/2.0/api/javafx/fxml/FXMLLoader.html#getController%28%29(有关完整示例,请参阅下面 ChoiceCell 类的实现)。

另一件需要注意的是Property.bindBi Direction() http://docs.oracle.com/javafx/2.0/api/javafx/beans/property/Property.html#bindBidirectional%28javafx.beans.property.Property%29会将调用属性的值设置为作为参数传入的属性的值。给定两个布尔属性target(最初设置为false) and source(最初设置为true) 呼叫target.bindBidirectional(source)将设置的值target to true。显然,对任一属性的任何后续更改都会更改另一个属性的值(target.set(false)将导致值source被设置为false):

BooleanProperty target = new SimpleBooleanProperty();//value is false
BooleanProperty source = new SimpleBooleanProperty(true);//value is true
target.bindBidirectional(source);//target.get() will now return true
target.set(false);//both values are now false
source.set(true);//both values are now true

不管怎样,这里是演示 FXML 和 Java 如何协同工作的完整代码(以及其他一些有用的东西)

封装结构:

com.example.javafx.choice
  ChoiceCell.java
  ChoiceController.java
  ChoiceModel.java
  ChoiceView.fxml
com.example.javafx.mvc
  FxmlMvcPatternDemo.java
  MainController.java
  MainView.fxml
  MainView.properties

FxmlMvcPatternDemo.java

package com.example.javafx.mvc;

import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class FxmlMvcPatternDemo extends Application
{
    public static void main(String[] args) throws ClassNotFoundException
    {
        Application.launch(FxmlMvcPatternDemo.class, args);
    }

    @Override
    public void start(Stage stage) throws Exception
    {
        Parent root = FXMLLoader.load
        (
            FxmlMvcPatternDemo.class.getResource("MainView.fxml"),
            ResourceBundle.getBundle(FxmlMvcPatternDemo.class.getPackage().getName()+".MainView")/*properties file*/
        );

        stage.setScene(new Scene(root));
        stage.show();
    }
}

主视图.fxml

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

<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox
    xmlns:fx="http://javafx.com/fxml"
    fx:controller="com.example.javafx.mvc.MainController"

    prefWidth="300"
    prefHeight="400"
    fillWidth="false"
>
    <children>
        <Label text="%title" />
        <ListView fx:id="choicesView" />
        <Button text="Force Change" onAction="#handleForceChange" />
    </children>
</VBox>

MainView.properties

title=JavaFX 2.0 FXML MVC demo

主控制器.java

package com.example.javafx.mvc;

import com.example.javafx.choice.ChoiceCell;
import com.example.javafx.choice.ChoiceModel;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;

public class MainController implements Initializable
{
    @FXML
    private ListView<ChoiceModel> choicesView;

    @Override
    public void initialize(URL url, ResourceBundle rb)
    {
        choicesView.setCellFactory(new Callback<ListView<ChoiceModel>, ListCell<ChoiceModel>>()
        {
            public ListCell<ChoiceModel> call(ListView<ChoiceModel> p)
            {
                return new ChoiceCell();
            }
        });
        choicesView.setItems(FXCollections.observableArrayList
        (
            new ChoiceModel("Tiger", true),
            new ChoiceModel("Shark", false),
            new ChoiceModel("Bear", false),
            new ChoiceModel("Wolf", true)
        ));
    }

    @FXML
    private void handleForceChange(ActionEvent event)
    {
        if(choicesView != null && choicesView.getItems().size() > 0)
        {
            boolean isSelected = choicesView.getItems().get(0).isSelected();
            choicesView.getItems().get(0).setSelected(!isSelected);
        }
    }
}

ChoiceView.fxml

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

<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<HBox
    xmlns:fx="http://javafx.com/fxml"

    fx:controller="com.example.javafx.choice.ChoiceController"
>
    <children>
        <CheckBox fx:id="isSelectedView" />
        <Label fx:id="labelView" />
    </children>
</HBox>

ChoiceController.java

package com.example.javafx.choice;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;

public class ChoiceController
{
    private final ChangeListener<String> LABEL_CHANGE_LISTENER = new ChangeListener<String>()
    {
        public void changed(ObservableValue<? extends String> property, String oldValue, String newValue)
        {
            updateLabelView(newValue);
        }
    };

    private final ChangeListener<Boolean> IS_SELECTED_CHANGE_LISTENER = new ChangeListener<Boolean>()
    {
        public void changed(ObservableValue<? extends Boolean> property, Boolean oldValue, Boolean newValue)
        {
            updateIsSelectedView(newValue);
        }
    };

    @FXML
    private Label labelView;

    @FXML
    private CheckBox isSelectedView;

    private ChoiceModel model;

    public ChoiceModel getModel()
    {
        return model;
    }

    public void setModel(ChoiceModel model)
    {
        if(this.model != null)
            removeModelListeners();
        this.model = model;
        setupModelListeners();
        updateView();
    }

    private void removeModelListeners()
    {
        model.labelProperty().removeListener(LABEL_CHANGE_LISTENER);
        model.isSelectedProperty().removeListener(IS_SELECTED_CHANGE_LISTENER);
        isSelectedView.selectedProperty().unbindBidirectional(model.isSelectedProperty())
    }

    private void setupModelListeners()
    {
        model.labelProperty().addListener(LABEL_CHANGE_LISTENER);
        model.isSelectedProperty().addListener(IS_SELECTED_CHANGE_LISTENER);
        isSelectedView.selectedProperty().bindBidirectional(model.isSelectedProperty());
    }

    private void updateView()
    {
        updateLabelView();
        updateIsSelectedView();
    }

    private void updateLabelView(){ updateLabelView(model.getLabel()); }
    private void updateLabelView(String newValue)
    {
        labelView.setText(newValue);
    }

    private void updateIsSelectedView(){ updateIsSelectedView(model.isSelected()); }
    private void updateIsSelectedView(boolean newValue)
    {
        isSelectedView.setSelected(newValue);
    }
}

ChoiceModel.java

package com.example.javafx.choice;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class ChoiceModel
{
    private final StringProperty label;
    private final BooleanProperty isSelected;

    public ChoiceModel()
    {
        this(null, false);
    }

    public ChoiceModel(String label)
    {
        this(label, false);
    }

    public ChoiceModel(String label, boolean isSelected)
    {
        this.label = new SimpleStringProperty(label);
        this.isSelected = new SimpleBooleanProperty(isSelected);
    }

    public String getLabel(){ return label.get(); }
    public void setLabel(String label){ this.label.set(label); }
    public StringProperty labelProperty(){ return label; }

    public boolean isSelected(){ return isSelected.get(); }
    public void setSelected(boolean isSelected){ this.isSelected.set(isSelected); }
    public BooleanProperty isSelectedProperty(){ return isSelected; }
}

ChoiceCell.java

package com.example.javafx.choice;

import java.io.IOException;
import java.net.URL;
import javafx.fxml.FXMLLoader;
import javafx.fxml.JavaFXBuilderFactory;
import javafx.scene.Node;
import javafx.scene.control.ListCell;

public class ChoiceCell extends ListCell<ChoiceModel>
{
    @Override
    protected void updateItem(ChoiceModel model, boolean bln)
    {
        super.updateItem(model, bln);

        if(model != null)
        {
            URL location = ChoiceController.class.getResource("ChoiceView.fxml");

            FXMLLoader fxmlLoader = new FXMLLoader();
            fxmlLoader.setLocation(location);
            fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());

            try
            {
                Node root = (Node)fxmlLoader.load(location.openStream());
                ChoiceController controller = (ChoiceController)fxmlLoader.getController();
                controller.setModel(model);
                setGraphic(root);
            }
            catch(IOException ioe)
            {
                throw new IllegalStateException(ioe);
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 FXML 在 JavaFX 2.0 中创建自定义组件? 的相关文章

  • fxml getController() 返回 null

    我是 JavaFX 的新手 谁能帮我 这是我的代码 Stage stage new Stage FXMLLoader loader new FXMLLoader Parent root Parent loader load getClass
  • 限制 JavaFX TextField 的字符数会导致撤消时 IndexOutOfBounds

    我需要限制用户可以输入的字符数TextFieldJavaFX 控件 我已经延长了TextField like so public class LengthLimitedTextField extends TextField param ma
  • 如何在单击按钮时从 JavaFX WebView 调用 JavaScript 函数?

    我正在尝试从 JavaFX 调用 JavaScript 函数WebView http docs oracle com javafx 2 api javafx scene web WebView html在 JavaFX 按钮单击事件上 我正
  • 窗格形状修改

    好吧 长话短说 我正在尝试创建一种聊天 消息系统 并且需要一点帮助 我正在尝试在容器上创建一个箭头 如下图所示 该图像是从 ControlsFX 及其 PopOver 窗口中取出的 我不能使用他们的弹出窗口小部件 因为它的行为与我使用它的目
  • 转换为 UI 的记录器条目随着时间的推移停止更新

    我有一个 javafx concurrent Task 在后台运行一些代码并使用 java util logging Logger 提供有关其状态的信息 我需要在主线程的 UI 中显示此日志条目 我怎样才能做到这一点 这是我制作的一个简单的
  • JavaFX 中的字段验证[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我使用 fxml 创建了一份注册表单 现在我想实现字段验证功能 我正在尝试实现 TextField 的验证 但仍然没有得到它 不幸的是
  • 如何保存 JavaFX GUI 状态?

    是否有一种现有的简单方法来持久保存 JavaFX GUI 状态 包括节点的 userData 字段的自定义 反 序列化 None
  • 如何在 Eclipse 中使用 JavaFX 2 SDK?

    我已经安装了 JavaFX 2 0 SDK 现在我想使用 Eclipse 制作一个 JavaFX 应用程序 但我该如何使用javafx Eclipse 中的类 The 官方 JavaFX Eclipse 插件 http docs oracl
  • JavaFX 2 中的组合框键值对

    我刚刚开始学习 JavaFX 2 现在我正在尝试构建一个示例应用程序 然后我就陷入了组合框 我在 JavaFX 中没有找到任何对组合框键值对的引用 组合框 javadoc 位于http docs oracle com javafx 2 ap
  • JAVA FXCollections LoadException 类不是有效类型

    我正在尝试在此帮助下实现带有一些数据的 TableViewTutorial https docs oracle com javafx 2 fxml get started fxml tutorial intermediate htm CIA
  • 如何在JavaFX 2应用程序中正确使用Weld?

    我正在尝试让 Weld 在我的 JavaFX 2 SE 应用程序中工作 或者我应该说 JavaFX 在 Weld 中工作 我有响应用户交互的控制器 现在我想将我的服务 例如数据库服务 注入到这些控制器中 使用 Weld 这应该像以下一样简单
  • JavaFX 2:TableView:删除标题+空时显示网格

    我有两个关于 Javafx 2 中的 TableView 的问题 1 是否可以隐藏表格中的标题 2 当表为空时 它只显示一个白色窗格 上面写着 表中没有内容 是否可以更改此设置以显示默认网格 即使表格为空 如果可能的话 我想要一个带有 CS
  • JavaFX - 为什么多次将节点添加到窗格或不同的窗格会导致错误?

    我现在正在学习基本的 JavaFX 我不明白我正在阅读的书中的这一说法 不 诸如文本字段之类的节点只能添加到一个窗格中一次 将节点添加到多次窗格或不同的窗格将导致运行时错误 我可以从书中提供的UML图看出它是一个组合 但我不明白为什么 库类
  • 使用 CSS 在 javaFX 中设置按钮样式

    我在使用 CSS 的 javaFX 中设置按钮样式时遇到问题 我使用 Intellij Idea IDE 我有 CSS css 文件 Button fx padding 8 15 15 15 fx background insets 0 0
  • 访问 FXML 控制器类

    我想随时与 FXML 控制器类进行通信 以更新主应用程序或其他阶段屏幕上的信息 这可能吗 我还没有找到任何方法来做到这一点 静态函数可能是一种方法 但它们无法访问表单的控件 有任何想法吗 您可以从以下位置获取控制器FXMLLoader FX
  • 如何从舞台组件中仅删除“最小化”按钮以及如何在 JavaFX 中自定义组件?

    如何从舞台组件中仅删除 最小化 按钮以及如何在 JavaFX 中自定义它们 我正在使用 Netbeans 7 1 2 并创建了一个简单的 JavaFX 应用程序 我有一个名为 PrimaryStage 的阶段对象 我怎样才能实现它 不幸的是
  • 如何平滑拖动JavaFX多边形?

    我有一个多边形 三角形 我想让它可以用鼠标拖动 下面是我尝试过的代码 但是使用此代码我无法顺利拖动它 请让我知道如何才能使其顺利拖动 public void start Stage primaryStage throws Exception
  • Javafx过滤表视图

    我正在尝试使用文本字段来过滤表视图 我想要一个文本字段 txtSearch 来搜索 nhs 号码 名字 姓氏 和 分类类别 我尝试过在线实施各种解决方案 但没有运气 我对这一切仍然很陌生 所以如果问得不好 我深表歉意 任何帮助将不胜感激 我
  • JavaFX Platform.runLater 的使用以及从不同线程访问 UI

    我有几个问题Platform runLater 我有一个 JavaFX 应用程序类 在这个类中 我运行一个线程 该线程从网络套接字读取数据 现在当我创建一个新的Stage在线程内部 系统抛出异常 JavaFX 事件调度程序线程和我的网络读取
  • 如何设置菜单按钮和菜单项的样式

    我尝试更改菜单按钮中的样式 我可以更改菜单按钮样式 但不能更改其菜单项 无论我尝试什么 菜单按钮内的菜单项都保持不变 menu button fx background color black menu button label fx ba

随机推荐

  • 如果任何源列为 true,则将布尔值聚合为 true

    假设我有下表 id column a column b column c 1 t f t 2 t f f 3 f t f 从上表中 我想 select rows from id 1 2 结果应该是 column a column b col
  • 除了最后一项之外,如何在所有项上设置边框底部

    如果我有一个ul 我如何设置所有的边框底部li除了最后一项之外的项目 我也在尝试使宽度border180 像素 这是我的代码 HTML ul class sideNav li a href history asp History a li
  • 长按注释时,注释图像会被 RedPushPin 替换

    我使用以下内容创建了自定义注释 MKAnnotationView mapView MKMapView mapView viewForAnnotation id
  • 提示用户输入汇编 ci20 seg 错误

    我目前正在 ci20 机器上开发一个小程序 提示用户输入整数值 然后将该值打印到屏幕上 我当前的代码 data prompt asciiz Please enter an integer message asciiz nValue ente
  • 蟒蛇时间偏移

    如何在 python 中应用当前时间的偏移量 换句话说 能够获取当前时间减去 x 小时和 或减去 m 分钟和 或减去 s 秒和 或减去 ms 毫秒 例如 curent time 18 26 00 000 offset 01 10 00 00
  • 单子值的案例

    有没有一种方法可以对 monad 中存储的值执行 case 而无需将名称绑定到它 即 不要这样做 c lt getChar case c of 有没有办法做到这一点 mcase getChar of 或者 如果可以部分应用 case 语句
  • 有没有更有效的方法将数组从 C++ 返回到 javascript?

    为了将类型化数组从 emscripten ed C 传递到 javascript 我想出了这段代码 include
  • 判断操作系统是否为Mac

    我最近做了很多谷歌搜索 试图找到一个简单 容易的 php 脚本来识别用户是否在 Mac 上 我想用它来告诉用户我告诉他们的键盘快捷键是 控制 还是 命令 我不需要了解浏览器什么的 只要电脑是Mac就可以了 这是我所要求的可能的概述 if o
  • 何时使用 babel.config.js 和 .babelrc

    我正在学习 Babel 想学习如何配置 Babel 我找到了两种配置 Babel 的方法 创建 babel config js 和 babelrc 文件 在什么情况下我们应该选择一个配置文件而不是另一个 来自文档 https babeljs
  • 计算单个进程的总磁盘 I/O

    我正在寻找一些工具 可以在单个进程结束后转储总磁盘 I O 到目前为止我的发现是 iotop 它实时显示每个进程的 i o 但不给出 流程结束后总计 iostat 它显示实时 I O 但 不告诉过程 例如 我有一些进程在后台运行 PID 为
  • 每天将自动增量列重置回 0

    postgresql中有没有办法让自动递增列在每天的指定时间重置为零 对于 cronjob 来说这可能是非常微不足道的 0 0 echo SELECT setval public my table id seq 1 false psql U
  • 云sql数据库导出导入问题

    从实例 第二代 导出 sql 数据库并将其导入到另一个 sql 实例时 出现以下错误 第 24 行出现错误 1839 HY000 GLOBAL GTID PURGED can only be set when GLOBAL GTID MOD
  • 了解 JQuery 是否可用的最佳方法? [复制]

    这个问题在这里已经有答案了 可能的重复 如何检查 jQuery 是否已加载以及什么版本 https stackoverflow com questions 6973941 how to check if jquery is loaded a
  • Visual Studio 2010 解决方案查找所有引用不起作用

    我有一个从 Visual Studio 2008 解决方案导入的 Visual Studio 2010 解决方案 查找所有引用 对其不起作用 我尝试在谷歌上进行一些搜索来尝试解决这个问题 但结果却是空手而归 VS2008 中的 查找所有引用
  • AWS Athena:“HIVE_BAD_DATA:解析列'X'时出错:空字符串”

    我想使用 OpenCSVSerde 在 AWS Athena 上基于 CSV 文件创建外部表 CREATE EXTERNAL TABLE table name string value double group string ROW FOR
  • Objective-C 中替换字符串中的一个字符

    希望有人可以帮助我 我想替换字符串中的某个字符 并且想知道执行此操作的最佳方法是什么 我知道字符的位置 例如 如果我想将字符串中的第三个字符从 A 更改为 B 我该如何编码 如果始终是相同的字符 您可以使用 stringByReplacin
  • 在 python 中使用 Lambda 触发器将用户迁移到 Cognito

    我在 Python 中创建了一个 Lambda 函数 用于将用户从 RDS 迁移到 AWS Cognito 我面临的问题是我的函数的返回类型 以便 Cognito 创建用户 起初我返回 JSON return response userAt
  • AndroidManifest - 意图过滤器应该有多个操作吗?

    我当前的 MainActivity 意图过滤器如下所示
  • 如何使用lightgbm.cv进行回归?

    我想对 LightGBM 模型进行交叉验证lgb 数据集并使用提前停止回合 以下方法对于 XGBoost 来说没有问题xgboost cv 我不喜欢将 Scikit Learn 的方法与 GridSearchCV 一起使用 因为它不支持提前
  • 如何使用 FXML 在 JavaFX 2.0 中创建自定义组件?

    我似乎找不到有关该主题的任何材料 举一个更具体的例子 假设我想创建一个结合了复选框和标签的简单组件 然后 使用此自定义组件的实例填充 ListView 更新 请参阅我的答案以获取完整代码 更新2 如需最新教程 请咨询官方文档 http do