Cập nhật: Đối với một up-to-date hướng dẫn, xin vui lòng, tham khảo ý kiến the official documentation. Đã có rất nhiều new stuff đã được thêm vào trong 2.2. Ngoài ra, Introduction to FXML bao gồm tất cả mọi thứ bạn cần biết về FXML. Cuối cùng, Hendrik Ebbers đã thực hiện một số cực kỳ hữu ích blog post về các điều khiển giao diện người dùng tùy chỉnh.
Sau một vài ngày kể từ khi nhìn xung quanh API và đọc qua một số tài liệu (Intro to FXML, Getting started with FXMLProperty binding, Future of FXML) Tôi đã tìm ra một giải pháp khá hợp lý. Thông tin nhỏ nhất về phía trước mà tôi đã học được từ thí nghiệm nhỏ này là trường hợp của bộ điều khiển (được khai báo với bộ điều khiển fx: trong FXML) được giữ bởi FXMLLoader đã tải tệp FXML ... Tồi tệ nhất, điều này quan trọng thực tế chỉ được nhắc đến trong one place trong tất cả các tài liệu tôi thấy:
một bộ điều khiển nói chung là chỉ hiển thị cho các bộ nạp FXML tạo ra nó
Vì vậy, hãy nhớ, để lập trình (từ mã Java) có được một tham chiếu đến trường hợp của một bộ điều khiển đã được khai báo trong FXML với fx:controller
sử dụng FXMLLoader.getController() (tham khảo việc thực hiện lớp ChoiceCell dưới đây để có một ví dụ hoàn chỉnh).
Một điều cần lưu ý là Property.bindBiderctional() sẽ đặt giá trị của thuộc tính gọi thành giá trị của thuộc tính được chuyển làm đối số. Với hai thuộc tính boolean target
(ban đầu được đặt thành false
) và source
(ban đầu được đặt thành true
), hãy gọi target.bindBidirectional(source)
sẽ đặt giá trị target
thành true
.Rõ ràng, bất kỳ thay đổi tiếp theo hoặc bất động sản sẽ thay đổi giá trị tài sản của người khác (target.set(false)
sẽ làm cho giá trị của source
được thiết lập để 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
Dù sao, đây là mã hoàn chỉnh trình bày cách FXML và Java có thể làm việc cùng nhau (cũng như một vài điều hữu ích khác)
cấu trúc
gói:
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);
}
}
}
}
Ví dụ kiểm soát tùy chỉnh trong liên kết 'tài liệu chính thức' của bạn bị hỏng. Trong đó có hai phương pháp không phải là một phần của API. –
@danLeon đầu tiên, nó không phải là MY "tài liệu chính thức". đó là THE "tài liệu chính thức" được viết bởi các nhân viên Oracle đang làm việc trên JavaFX. thứ hai, mã tôi đang liên kết để chứa một ví dụ làm việc về cách tạo các thành phần tùy chỉnh trong JavaFX 2.2. rất có thể là phiên bản bạn có là cũ hơn, do đó thiếu phương pháp. Đây là một điểm nổi bật từ trang đó: "Trước khi bạn bắt đầu, hãy đảm bảo rằng phiên bản NetBeans IDE mà bạn đang sử dụng hỗ trợ JavaFX 2.2" – Andrey
Bạn nói đúng! IDE của tôi là dưới JavaFx 2.1, Cảm ơn bạn đã bình luận. Bây giờ trên 2,2, tôi đã xóa bất kỳ phiên bản java trước đó trong máy tính của tôi. –