有没有办法在 JavaFX 中使 ListView 元素变为粗体?
Is there a way to make ListView element bold in JavaFX?
所以我是 JavaFX 的新手,我正在制作我的第一个应用程序。我希望有一个选项,可以在选择并单击按钮后使我的 ListView 中的元素变为粗体。不幸的是,我找不到解决问题的方法,而且我没有主意。如果您能告诉我如何在 .java 或 .fxml 文件中执行此操作,我将不胜感激,因为我现在不使用 CSS 文件。
实现这样的功能需要一些东西:
- 适合您的
ListView
的数据模型
- 为您的
ListView
定制的 CellFactory
将修改其中包含的项目的样式
- 更新 Person 模型以将个人标记为“重要”的方法
此答案底部有一个完整的示例应用程序(带注释),但让我们对其进行分解并解决上述问题。
数据模型:
如果您使用简单的 String
作为 ListView
的类型(即:ListView<String>
),您将需要更改它以提供自定义对象。对于这个例子,我们将创建一个新的 Person
class.
class Person {
private final StringProperty name = new SimpleStringProperty();
private final BooleanProperty important = new SimpleBooleanProperty(false);
public Person(String name) {
this.name.set(name);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public boolean isImportant() {
return important.get();
}
public BooleanProperty importantProperty() {
return important;
}
public void setImportant(boolean important) {
this.important.set(important);
}
}
现在,您需要相应地定义 ListView
:
ListView<Person> listView = new ListView<>();
自定义细胞工厂:
CellFactory
是 ListView
的一部分,负责呈现 ListView
中每一行的实际内容。为了根据特定 Person
的属性更改单元格的外观,我们必须提供自己的实现(JavaFX 的标准实现将简单地呈现每个单元格以包含项目的 toString()
方法) .
listView.setCellFactory(cell -> new ListCell<Person>(){
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
// First, we are only going to update the cell if there is actually an item to display there.
if (!empty && person != null) {
// Set the text of the cell to the Person's name
setText(person.getName());
// If the Person has the "important" flag, we can make the text bold here
if (person.isImportant()) {
setStyle("-fx-font-weight: bold");
} else {
// Remove any styles from the cell, because this Person isn't important
setStyle(null);
}
} else {
// If there is no item to display in this cell, set the text to null
setText(null);
}
}
});
更新“重要”属性:
您 MenuItem
的操作应该会更新所选人员的 important
属性。这相当简单:
mnuSetImportant.setOnAction(event -> {
Person selectedPerson = listView.getSelectionModel().getSelectedItem();
if (selectedPerson != null) {
selectedPerson.setImportant(!selectedPerson.isImportant());
}
});
请注意,在这种情况下,我已将操作设置为切换此人的重要状态。您可以轻松地将 属性 设置为 true
,但如果不添加单独的菜单选项,您将无法再次将其设置为 false
。
但是,在此之后,您会注意到单元格不会使用新样式自行更新。这是因为 ListView
不会“监听”每个 Person
的属性变化。因此,在下面的示例中,我们向 Person
class 添加了一个静态 extractor()
方法,它允许其属性触发对 ListView
.
的更新
就是这样!下面是一个完整的应用程序,您可以亲自试用一下,看看它的实际效果:
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewItemProperties extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// **********************************************************************************************
// Create a basic layout
// **********************************************************************************************
BorderPane root = new BorderPane();
// **********************************************************************************************
// Create the menu bar and Menu items
// **********************************************************************************************
MenuBar menuBar = new MenuBar();
Menu mnuMore = new Menu("More");
MenuItem mnuSetImportant = new MenuItem("Set important");
// **********************************************************************************************
// Create the ListView
// **********************************************************************************************
ListView<Person> listView = new ListView<>();
// **********************************************************************************************
// Set the action for the "Set important" menu item to update the property of the selected
// Person in the ListView, if applicable
// **********************************************************************************************
mnuSetImportant.setOnAction(event -> {
// **********************************************************************************************
// Get reference to the currently selected Person
// **********************************************************************************************
Person selectedPerson = listView.getSelectionModel().getSelectedItem();
if (selectedPerson != null) {
// **********************************************************************************************
// If a person has been selected, toggle their "important" property
// **********************************************************************************************
selectedPerson.setImportant(!selectedPerson.isImportant());
}
});
// **********************************************************************************************
// Assemble the menus
// **********************************************************************************************
mnuMore.getItems().add(mnuSetImportant);
menuBar.getMenus().add(mnuMore);
// **********************************************************************************************
// Create some sample Persons and add them to the ListView. This will also configure the list with
// the extractor we created in the Person class in order to trigger updates to the ListView when any
// of the Person's properties change.
// **********************************************************************************************
ObservableList<Person> people = FXCollections.observableArrayList(Person.extractor());
people.addAll(
new Person("Dad"),
new Person("Sis"),
new Person("Babe"));
listView.setItems(people);
// **********************************************************************************************
// Here we will create our own CellFactory so we can set the style of the text based on the
// important property of each Person
// **********************************************************************************************
listView.setCellFactory(cell -> new ListCell<Person>() {
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
// First, we are only going to update the cell if there is actually an item to display there.
if (!empty && person != null) {
// Set the text of the cell to the Person's name
setText(person.getName());
// If the Person has the "important" flag, we can make the text bold here
if (person.isImportant()) {
setStyle("-fx-font-weight: bold");
} else {
// Remove any styles from the cell, because this Person isn't important
setStyle(null);
}
} else {
// If there is no item to display in this cell, set the text to null
setText(null);
}
}
});
// **********************************************************************************************
// Assemble the Scene
// **********************************************************************************************
root.setTop(menuBar);
root.setCenter(listView);
// **********************************************************************************************
// Set the Scene for the stage
// **********************************************************************************************
primaryStage.setScene(new Scene(root));
// **********************************************************************************************
// Configure the Stage
// **********************************************************************************************
primaryStage.setTitle("Test Application");
primaryStage.show();
}
}
class Person {
// Name of this person
private final StringProperty name = new SimpleStringProperty();
// Boolean property to track whether this person has been flagged as "important"
private final BooleanProperty important = new SimpleBooleanProperty(false);
public Person(String name) {
this.name.set(name);
}
/**
* Callback to trigger updates whenever a property of a Person is changed. This allows our ListView
* to refresh the cell when the "important" property changes.
*/
public static Callback<Person, Observable[]> extractor() {
// **********************************************************************************************
// Return the callback which fires change events whenever either name or important properties
// are updated. A ListView normally only listens for changes to its Items list but ignores
// changes to the item's internal properties.
// **********************************************************************************************
return (Person p) -> new Observable[]{
p.name, p.important
};
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty nameProperty() {
return name;
}
public boolean isImportant() {
return important.get();
}
public void setImportant(boolean important) {
this.important.set(important);
}
public BooleanProperty importantProperty() {
return important;
}
}
所以我是 JavaFX 的新手,我正在制作我的第一个应用程序。我希望有一个选项,可以在选择并单击按钮后使我的 ListView 中的元素变为粗体。不幸的是,我找不到解决问题的方法,而且我没有主意。如果您能告诉我如何在 .java 或 .fxml 文件中执行此操作,我将不胜感激,因为我现在不使用 CSS 文件。
实现这样的功能需要一些东西:
- 适合您的
ListView
的数据模型
- 为您的
ListView
定制的CellFactory
将修改其中包含的项目的样式 - 更新 Person 模型以将个人标记为“重要”的方法
此答案底部有一个完整的示例应用程序(带注释),但让我们对其进行分解并解决上述问题。
数据模型:
如果您使用简单的 String
作为 ListView
的类型(即:ListView<String>
),您将需要更改它以提供自定义对象。对于这个例子,我们将创建一个新的 Person
class.
class Person {
private final StringProperty name = new SimpleStringProperty();
private final BooleanProperty important = new SimpleBooleanProperty(false);
public Person(String name) {
this.name.set(name);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public boolean isImportant() {
return important.get();
}
public BooleanProperty importantProperty() {
return important;
}
public void setImportant(boolean important) {
this.important.set(important);
}
}
现在,您需要相应地定义 ListView
:
ListView<Person> listView = new ListView<>();
自定义细胞工厂:
CellFactory
是 ListView
的一部分,负责呈现 ListView
中每一行的实际内容。为了根据特定 Person
的属性更改单元格的外观,我们必须提供自己的实现(JavaFX 的标准实现将简单地呈现每个单元格以包含项目的 toString()
方法) .
listView.setCellFactory(cell -> new ListCell<Person>(){
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
// First, we are only going to update the cell if there is actually an item to display there.
if (!empty && person != null) {
// Set the text of the cell to the Person's name
setText(person.getName());
// If the Person has the "important" flag, we can make the text bold here
if (person.isImportant()) {
setStyle("-fx-font-weight: bold");
} else {
// Remove any styles from the cell, because this Person isn't important
setStyle(null);
}
} else {
// If there is no item to display in this cell, set the text to null
setText(null);
}
}
});
更新“重要”属性:
您 MenuItem
的操作应该会更新所选人员的 important
属性。这相当简单:
mnuSetImportant.setOnAction(event -> {
Person selectedPerson = listView.getSelectionModel().getSelectedItem();
if (selectedPerson != null) {
selectedPerson.setImportant(!selectedPerson.isImportant());
}
});
请注意,在这种情况下,我已将操作设置为切换此人的重要状态。您可以轻松地将 属性 设置为 true
,但如果不添加单独的菜单选项,您将无法再次将其设置为 false
。
但是,在此之后,您会注意到单元格不会使用新样式自行更新。这是因为 ListView
不会“监听”每个 Person
的属性变化。因此,在下面的示例中,我们向 Person
class 添加了一个静态 extractor()
方法,它允许其属性触发对 ListView
.
就是这样!下面是一个完整的应用程序,您可以亲自试用一下,看看它的实际效果:
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewItemProperties extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// **********************************************************************************************
// Create a basic layout
// **********************************************************************************************
BorderPane root = new BorderPane();
// **********************************************************************************************
// Create the menu bar and Menu items
// **********************************************************************************************
MenuBar menuBar = new MenuBar();
Menu mnuMore = new Menu("More");
MenuItem mnuSetImportant = new MenuItem("Set important");
// **********************************************************************************************
// Create the ListView
// **********************************************************************************************
ListView<Person> listView = new ListView<>();
// **********************************************************************************************
// Set the action for the "Set important" menu item to update the property of the selected
// Person in the ListView, if applicable
// **********************************************************************************************
mnuSetImportant.setOnAction(event -> {
// **********************************************************************************************
// Get reference to the currently selected Person
// **********************************************************************************************
Person selectedPerson = listView.getSelectionModel().getSelectedItem();
if (selectedPerson != null) {
// **********************************************************************************************
// If a person has been selected, toggle their "important" property
// **********************************************************************************************
selectedPerson.setImportant(!selectedPerson.isImportant());
}
});
// **********************************************************************************************
// Assemble the menus
// **********************************************************************************************
mnuMore.getItems().add(mnuSetImportant);
menuBar.getMenus().add(mnuMore);
// **********************************************************************************************
// Create some sample Persons and add them to the ListView. This will also configure the list with
// the extractor we created in the Person class in order to trigger updates to the ListView when any
// of the Person's properties change.
// **********************************************************************************************
ObservableList<Person> people = FXCollections.observableArrayList(Person.extractor());
people.addAll(
new Person("Dad"),
new Person("Sis"),
new Person("Babe"));
listView.setItems(people);
// **********************************************************************************************
// Here we will create our own CellFactory so we can set the style of the text based on the
// important property of each Person
// **********************************************************************************************
listView.setCellFactory(cell -> new ListCell<Person>() {
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
// First, we are only going to update the cell if there is actually an item to display there.
if (!empty && person != null) {
// Set the text of the cell to the Person's name
setText(person.getName());
// If the Person has the "important" flag, we can make the text bold here
if (person.isImportant()) {
setStyle("-fx-font-weight: bold");
} else {
// Remove any styles from the cell, because this Person isn't important
setStyle(null);
}
} else {
// If there is no item to display in this cell, set the text to null
setText(null);
}
}
});
// **********************************************************************************************
// Assemble the Scene
// **********************************************************************************************
root.setTop(menuBar);
root.setCenter(listView);
// **********************************************************************************************
// Set the Scene for the stage
// **********************************************************************************************
primaryStage.setScene(new Scene(root));
// **********************************************************************************************
// Configure the Stage
// **********************************************************************************************
primaryStage.setTitle("Test Application");
primaryStage.show();
}
}
class Person {
// Name of this person
private final StringProperty name = new SimpleStringProperty();
// Boolean property to track whether this person has been flagged as "important"
private final BooleanProperty important = new SimpleBooleanProperty(false);
public Person(String name) {
this.name.set(name);
}
/**
* Callback to trigger updates whenever a property of a Person is changed. This allows our ListView
* to refresh the cell when the "important" property changes.
*/
public static Callback<Person, Observable[]> extractor() {
// **********************************************************************************************
// Return the callback which fires change events whenever either name or important properties
// are updated. A ListView normally only listens for changes to its Items list but ignores
// changes to the item's internal properties.
// **********************************************************************************************
return (Person p) -> new Observable[]{
p.name, p.important
};
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty nameProperty() {
return name;
}
public boolean isImportant() {
return important.get();
}
public void setImportant(boolean important) {
this.important.set(important);
}
public BooleanProperty importantProperty() {
return important;
}
}