gpt4 book ai didi

JavaFX TreeView 的多种对象类型? (和更多)

转载 作者:行者123 更新时间:2023-12-01 22:16:43 25 4
gpt4 key购买 nike

我目前有以下对象数据结构:

项目

  • 字符串名称
  • 信息数组列表

角色

  • 字符串名称
  • 元素集合

帐户

  • 字符串名称
  • 角色集合(最多 8 个)

我想制作一个如下所示的 TreeView:

Root(invisible)
======Jake(Account)
============JakesChar(Character)
==================Amazing Sword(Item)
==================Broken Bow(Item)
==================Junk Metal(Item)
======Mark(Account)
============myChar(Character)
==================Godly Axe(Item)
======FreshAcc(Account)
======MarksAltAcc(Account)
============IllLvlThisIPromise(Character)
======Jeffrey(Account)
============Jeff(Character)
==================Super Gun(Item)
==================Better Super Gun(Item)
==================Super Gun Scope(Item)

所有这些名称都是我编的,显然真正的实现会复杂得多。如何才能做到这一点? TreeItem 要求每个 TreeItem 与其父项具有相同的类型。

我唯一的解决方案是执行以下操作:

public class ObjectPointer
{
Object pointer;
String name;
}

我的 TreeView 将是 ObjectPointer 类型,并且在每一行上我会将 ObjectPointer 转换为 AccountCharacter、项目。这很糟糕,但我认为它会起作用。

子问题:

  • 如何让 TreeItem 检测 setOnMouseHover 事件?

  • 如何让 TreeItem 不使用其类型的 toString 方法,而是使用显示 String< 的自定义方式 他们需要的属性?

  • 如何让 TreeItem 在 GUI 中显示彩色文本而不是纯文本?

谢谢!

最佳答案

如果您查看模型并一般性地思考,所有类都具有一定程度的相似性,您可以将其分解为父类(super class):

package model;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public abstract class GameObject<T extends GameObject<?>> {


public GameObject(String name) {
setName(name);
}

private final StringProperty name = new SimpleStringProperty();

public final StringProperty nameProperty() {
return this.name;
}


public final String getName() {
return this.nameProperty().get();
}


public final void setName(final String name) {
this.nameProperty().set(name);
}

private final ObservableList<T> items = FXCollections.observableArrayList();

public ObservableList<T> getItems() {
return items ;
}

public abstract void createAndAddChild(String name);
}

类型参数T这里代表“子”对象的类型。所以你的Account类(其子类型为 GameCharacter - 不要将类命名为与 java.lang 中的任何内容相同,顺便说一句...)看起来像

package model;

public class Account extends GameObject<GameCharacter> {

public Account(String name) {
super(name);
}

@Override
public void createAndAddChild(String name) {
getItems().add(new GameCharacter(name));
}

}

并且类似地一直沿着层次结构向下延伸。我定义一个 Information类(即使它只有一个名称)以使所有内容都符合结构,因此:

package model;

public class Item extends GameObject<Information> {

public Item(String name) {
super(name);
}

@Override
public void createAndAddChild(String name) {
getItems().add(new Information(name));
}

}

并且,自 Information没有子项,它的子项列表只是一个空列表:

package model;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Information extends GameObject<GameObject<?>> {

public Information(String name) {
super(name);
}

@Override
public ObservableList<GameObject<?>> getItems() {
return FXCollections.emptyObservableList();
}

@Override
public void createAndAddChild(String name) {
throw new IllegalStateException("Information has no child items");
}

}

现在树中的每个项目都是 GameObject<?> ,所以你基本上可以构建一个 TreeView<GameObject<?>> 。棘手的部分是您的树项目需要反射(reflect)模型中已构建的结构。由于那里有可观察的列表,因此您可以使用列表上的监听器来执行此操作。

您可以使用树上的单元工厂来自定义显示 TreeItem 的单元格的外观s。如果您希望每种类型的项目具有不同的外观,我建议在外部 CSS 类中定义样式,并设置 CSS PseudoClass 在与项目类型相对应的单元格上。如果您使用某种命名约定(我认为伪类名称是类名称的小写版本),则可以非常灵活地做到这一点。这是一个相当简单的示例:

package ui;

import static java.util.stream.Collectors.toList;

import java.util.Arrays;
import java.util.List;

import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import model.Account;
import model.GameCharacter;
import model.GameObject;
import model.Information;
import model.Item;

public class Tree {

private final TreeView<GameObject<?>> treeView ;

private final List<Class<? extends GameObject<?>>> itemTypes = Arrays.asList(
Account.class, GameCharacter.class, Item.class, Information.class
);

public Tree(ObservableList<Account> accounts) {
treeView = new TreeView<>();

GameObject<?> root = new GameObject<Account>("") {

@Override
public ObservableList<Account> getItems() {
return accounts ;
}

@Override
public void createAndAddChild(String name) {
getItems().add(new Account(name));
}

};

TreeItem<GameObject<?>> treeRoot = createItem(root);

treeView.setRoot(treeRoot);
treeView.setShowRoot(false);

treeView.setCellFactory(tv -> {

TreeCell<GameObject<?>> cell = new TreeCell<GameObject<?>>() {

@Override
protected void updateItem(GameObject<?> item, boolean empty) {
super.updateItem(item, empty);
textProperty().unbind();
if (empty) {
setText(null);
itemTypes.stream().map(Tree.this::asPseudoClass)
.forEach(pc -> pseudoClassStateChanged(pc, false));
} else {
textProperty().bind(item.nameProperty());
PseudoClass itemPC = asPseudoClass(item.getClass());
itemTypes.stream().map(Tree.this::asPseudoClass)
.forEach(pc -> pseudoClassStateChanged(pc, itemPC.equals(pc)));
}
}
};

cell.hoverProperty().addListener((obs, wasHovered, isNowHovered) -> {
if (isNowHovered && (! cell.isEmpty())) {
System.out.println("Mouse hover on "+cell.getItem().getName());
}
});

return cell ;
}
}

public TreeView<GameObject<?>> getTreeView() {
return treeView ;
}

private TreeItem<GameObject<?>> createItem(GameObject<?> object) {

// create tree item with children from game object's list:

TreeItem<GameObject<?>> item = new TreeItem<>(object);
item.setExpanded(true);
item.getChildren().addAll(object.getItems().stream().map(this::createItem).collect(toList()));

// update tree item's children list if game object's list changes:

object.getItems().addListener((Change<? extends GameObject<?>> c) -> {
while (c.next()) {
if (c.wasAdded()) {
item.getChildren().addAll(c.getAddedSubList().stream().map(this::createItem).collect(toList()));
}
if (c.wasRemoved()) {
item.getChildren().removeIf(treeItem -> c.getRemoved().contains(treeItem.getValue()));
}
}
});

return item ;
}

private PseudoClass asPseudoClass(Class<?> clz) {
return PseudoClass.getPseudoClass(clz.getSimpleName().toLowerCase());
}

}

快速测试,可行,但请注意您可能需要测试更多功能:

package application;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import model.Account;
import model.GameCharacter;
import model.GameObject;
import model.Information;
import model.Item;
import ui.Tree;

public class Main extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
Tree tree = new Tree(createAccounts());
TreeView<GameObject<?>> treeView = tree.getTreeView();

TextField addField = new TextField();
Button addButton = new Button("Add");
EventHandler<ActionEvent> addHandler = e -> {
TreeItem<GameObject<?>> selected = treeView
.getSelectionModel()
.getSelectedItem();
if (selected != null) {
selected.getValue().createAndAddChild(addField.getText());
addField.clear();
}
};
addField.setOnAction(addHandler);
addButton.setOnAction(addHandler);
addButton.disableProperty().bind(Bindings.createBooleanBinding(() -> {
TreeItem<GameObject<?>> selected = treeView.getSelectionModel().getSelectedItem() ;
return selected == null || selected.getValue() instanceof Information ;
}, treeView.getSelectionModel().selectedItemProperty()));

Button deleteButton = new Button("Delete");
deleteButton.setOnAction(e -> {
TreeItem<GameObject<?>> selected = treeView.getSelectionModel().getSelectedItem() ;
TreeItem<GameObject<?>> parent = selected.getParent() ;
parent.getValue().getItems().remove(selected.getValue());
});
deleteButton.disableProperty().bind(treeView.getSelectionModel().selectedItemProperty().isNull());

HBox controls = new HBox(5, addField, addButton, deleteButton);
controls.setPadding(new Insets(5));
controls.setAlignment(Pos.CENTER);

BorderPane root = new BorderPane(treeView);
root.setBottom(controls);

Scene scene = new Scene(root, 600, 600);
scene.getStylesheets().add(getClass().getResource("/ui/style/style.css").toExternalForm());
primaryStage.setScene(scene);

primaryStage.show();
}

public static void main(String[] args) {
launch(args);
}

private ObservableList<Account> createAccounts() {
Account jake = new Account("Jake");
Account mark = new Account("Mark");
Account freshAcc = new Account("Fresh Account");
Account marksAltAcc = new Account("Mark's alternative account");
Account jeffrey = new Account("Jeffrey");

GameCharacter jakesChar = new GameCharacter("Jakes character");
Item amazingSword = new Item("Amazing Sword");
Item brokenBow = new Item("Broken Bow");
Item junkMetal = new Item("Junk Metal");

GameCharacter myChar = new GameCharacter("Me");
Item godlyAxe = new Item("Godly Axe");

GameCharacter level = new GameCharacter("I'll level this I promise");

GameCharacter jeff = new GameCharacter("Jeff");
Item superGun = new Item("Super Gun");
Item superGunScope = new Item("Super Gun Scope");

jake.getItems().add(jakesChar);
mark.getItems().add(myChar);
marksAltAcc.getItems().add(level);
jeffrey.getItems().add(jeff);

jakesChar.getItems().addAll(amazingSword, brokenBow, junkMetal);
myChar.getItems().add(godlyAxe);
jeff.getItems().addAll(superGun, superGunScope);

return FXCollections.observableArrayList(jake, mark, freshAcc, marksAltAcc, jeffrey);

}

}

以 CSS 为例:

.tree-cell, .tree-cell:hover:empty {
-fx-background-color: -fx-background ;
-fx-background: -fx-control-inner-background ;
}

.tree-cell:hover {
-fx-background-color: crimson, -fx-background ;
-fx-background-insets: 0, 1;
}

.tree-cell:account {
-fx-background: lightsalmon ;
}
.tree-cell:gamecharacter {
-fx-background: bisque ;
}
.tree-cell:item {
-fx-background: antiquewhite ;
}

.tree-cell:selected {
-fx-background: crimson ;
}

关于JavaFX TreeView 的多种对象类型? (和更多),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58620753/

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