gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 17:52:22 24 4
gpt4 key购买 nike

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

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

更新2:如需最新教程,请咨询the official documentation 。有很多new stuff这是在 2.2 中添加的。最后,Introduction to FXML几乎涵盖了您需要了解的有关 FXML 的所有内容。

更新3:亨德里克·埃伯斯(Hendrik Ebbers)做了一个非常有帮助的blog post关于自定义 UI 控件。

最佳答案

更新:有关最新教程,请参阅 the official documentation 。有很多new stuff这是在 2.2 中添加的。另外,Introduction to FXML几乎涵盖了您需要了解的有关 FXML 的所有内容。最后,Hendrik Ebbers 做了一个非常有帮助的 blog post关于自定义 UI 控件。

<小时/>

经过几天的环顾 API并阅读一些文档( Intro to FXMLGetting started with FXML Property bindingFuture of FXML )我想出了一个相当明智的解决方案。我从这个小实验中了解到的最不直接的信息是 Controller 的实例(在 FXML 中用 fx:controller 声明)由 FXMLLoader 保存。加载 FXML 文件...最糟糕的是,这个重要事实仅在 one place 中提到。在我看到的所有文档中:

a controller is generally only visible to the FXML loader that creates it

因此,请记住,为了以编程方式(从 Java 代码)获取对使用 fx:controller 在 FXML 中声明的 Controller 实例的引用,请使用 FXMLLoader.getController() (有关完整示例,请参阅下面 ChoiceCell 类的实现)。

另一件事需要注意的是Property.bindBiderctional()会将调用属性的值设置为作为参数传入的属性的值。给定两个 bool 属性target(最初设置为false)和source(最初设置为true)调用target.bindBi Direction(source) 会将 target 的值设置为 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();
}
}

MainView.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

MainController.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);
}
}
}
}

关于javafx-2 - 如何使用 FXML 在 JavaFX 2.0 中创建自定义组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8434787/

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