Javafx 自定义单元工厂节点不工作但在单元工厂中继承的 setText() 方法是
Javafx custom cell factory nodes not working but inherited setText() method in Cell factory is
我做了一个定制的细胞工厂。大多数值显示正确,但有些值显示不正确。当我扩展和折叠单元格时,问题变得更糟。奇怪的是继承的 setText()
方法按预期工作。我只是使用 setText()
方法来帮助我理解为什么这不起作用。您会注意到我自定义内容左侧的 setText()
方法的内容。
查看第一个单元格,您会注意到 none 的自定义单元格内容正在显示(最值得注意的是,TextFlow
节点未显示)。但是 setText()
内容确实如此,所以我知道 if 语句逻辑按预期工作。知道到底发生了什么吗?
下面是代码:
import java.util.Collections;
import java.util.List;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
public class CellValueMaker extends TreeTableCell<ProviderAttribute, ProviderAttribute>{
ImageView up;
ImageView down;
GridPane grid;
Text cellName;
Text cellDesc;
Label serialNumber;
VBox innerVB;
GridPane innerLowerGrid;
ImageButton upButton;
ImageButton downButton;
TextFlow flow;
public CellValueMaker(){
up = new ImageView(new Image(getClass().getResourceAsStream(
"/resources/up.png")));
up.setFitHeight(15);
up.setFitWidth(15);
upButton = new ImageButton(up);
down = new ImageView(new Image(getClass().getResourceAsStream(
"/resources/down.png")));
down.setFitHeight(15);
down.setFitWidth(15);
downButton = new ImageButton(down);
grid = new GridPane();
innerVB = new VBox();
innerVB.setPadding(new Insets(0, 0, 0, 3));
innerLowerGrid = new GridPane();
serialNumber = new Label("");
serialNumber.setFont(Font.font ("System", 10));
innerLowerGrid.add(serialNumber, 1, 0);
cellName = new Text("");
cellDesc = new Text("");
cellDesc.setStyle("-fx-font-weight: bold");
flow = new TextFlow();
flow.getChildren().addAll(cellDesc, cellName);
innerVB.getChildren().addAll(flow, serialNumber);
upButton.setOnMouseClicked(new OnMoveUp());
downButton.setOnMouseClicked(new OnMoveDown());
// set lower nested grid
grid.add(upButton, 0, 0);
grid.add(downButton, 1, 0);
grid.add(innerVB, 2, 0);
setGraphic(grid);
}
@Override
public void updateItem(ProviderAttribute item, boolean empty){
super.updateItem(item, empty);
if(item == null || empty){
setGraphic(null);
setText("");
setStyle("-fx-background-color: white;");
cellName.setText("");
cellDesc.setText("");
}else{
if(item instanceof DigitalIdentityType){
DigitalIdentityType certBean = item.getEncapsulatedBean();
setGraphic(grid);
cellName.setText(item.getStringName());
cellDesc.setText("Cert: ");
setText(item.getStringName());
setStyle("-fx-background-color: darkkhaki;");
if(certBean.getParentCert() != null){
serialNumber.setText("SN: " + certBean.getParentCert().getSerialNumber().toString());
}
}else if(item instanceof TSPServiceType){
setGraphic(grid);
cellName.setText(item.getStringName());
serialNumber.setText("");
cellDesc.setText("Service: ");
setStyle("-fx-background-color: lightblue;");
setText("Service: " + item.getStringName());
}else if(item instanceof TSPType){
setGraphic(grid);
cellName.setText(item.getStringName());
serialNumber.setText("");
cellDesc.setText("TSP: ");
setText("TSP: " + item.getStringName());
setStyle("-fx-background-color: bisque;");
}else{
GridPane pane = new GridPane();
pane.add(innerVB, 0, 0);
setGraphic(pane);
setText(item.getStringName());
serialNumber.setText("");
setStyle("-fx-background-color: white;");
// cellName.setText(item.getStringName());
}
}
}
public class OnMoveUp implements EventHandler<MouseEvent>{
private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";
@SuppressWarnings("unchecked")
@Override
public void handle(MouseEvent event) {
Button button = (Button)event.getSource();
button.setStyle(STYLE_PRESSED);
// get the table
TreeTableView<ProviderAttribute> table = (TreeTableView<ProviderAttribute>)
button.getParent().getParent().getParent()
.getParent().getParent().getParent().getParent();
// get the item
TreeTableRow<ProviderAttribute> row = (TreeTableRow<ProviderAttribute>)
button.getParent().getParent().getParent();
ProviderAttribute itemValue = row.getItem();
TreeItem<ProviderAttribute> item = row.getTreeItem();
ObservableList<TreeItem<ProviderAttribute>> list = item.getParent().getChildren();
if(item == null || list == null || list.size() <= 1) return;
// swap the current item with the one above it
int index = getIndexOf(list, itemValue);
if(index > 0){
Collections.swap(list, index, index-1);
table.getSelectionModel().clearSelection();
}
}
}
public class OnMoveDown implements EventHandler<MouseEvent>{
private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";
@SuppressWarnings("unchecked")
@Override
public void handle(MouseEvent event) {
Button button = (Button)event.getSource();
button.getGraphic().setOpacity(50);
button.setStyle(STYLE_PRESSED);
// get the table
TreeTableView<ProviderAttribute> table = (TreeTableView<ProviderAttribute>)
button.getParent().getParent().getParent()
.getParent().getParent().getParent().getParent();
// get the item
TreeTableRow<ProviderAttribute> row = (TreeTableRow<ProviderAttribute>)
button.getParent().getParent().getParent();
ProviderAttribute itemValue = row.getItem();
TreeItem<ProviderAttribute> item = row.getTreeItem();
ObservableList<TreeItem<ProviderAttribute>> list = item.getParent().getChildren();
if(item == null || list == null || list.size() <= 1) return;
int index = getIndexOf(list, itemValue);
if(index < list.size() - 1){
Collections.swap(list, index, index+1);
table.getSelectionModel().clearSelection();
}
}
}
public int getIndexOf(List<TreeItem<ProviderAttribute>> items, ProviderAttribute bean){
int index = -1;
for(int i = 0; i < items.size(); i++){
if(items.get(i).getValue().equals(bean))
return i;
}
return index;
}
public class ImageButton extends Button {
private final String STYLE_NORMAL = "-fx-background-color: transparent; -fx-padding: 2, 2, 2, 2;";
public ImageButton(ImageView image) {
setGraphic(image);
setStyle(STYLE_NORMAL);
setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
setStyle(STYLE_NORMAL);
// setOpacity(0);
}
});
}
}
// public class EventHandler
}
由于单元格被重复使用,有时您会使 innerVB
成为在最后一个 else 子句中创建的新 GridPane
的子节点;但是 innerVB
已经是另一个父节点的子节点(grid
,并且可能还有先前在同一 else 子句的先前调用中创建的网格窗格)。这违反了场景图的规则(一个节点只能是一个父节点的子节点),并且可能会混淆布局,导致无法预测的显示。
你可能应该这样做
grid.getChildren().clear();
每次调用 updateItem()
,然后
grid.addRow(0, upButton, downButton, innerVB);
或
grid.addRow(0, innerVB);
根据需要。
我做了一个定制的细胞工厂。大多数值显示正确,但有些值显示不正确。当我扩展和折叠单元格时,问题变得更糟。奇怪的是继承的 setText()
方法按预期工作。我只是使用 setText()
方法来帮助我理解为什么这不起作用。您会注意到我自定义内容左侧的 setText()
方法的内容。
查看第一个单元格,您会注意到 none 的自定义单元格内容正在显示(最值得注意的是,TextFlow
节点未显示)。但是 setText()
内容确实如此,所以我知道 if 语句逻辑按预期工作。知道到底发生了什么吗?
下面是代码:
import java.util.Collections;
import java.util.List;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
public class CellValueMaker extends TreeTableCell<ProviderAttribute, ProviderAttribute>{
ImageView up;
ImageView down;
GridPane grid;
Text cellName;
Text cellDesc;
Label serialNumber;
VBox innerVB;
GridPane innerLowerGrid;
ImageButton upButton;
ImageButton downButton;
TextFlow flow;
public CellValueMaker(){
up = new ImageView(new Image(getClass().getResourceAsStream(
"/resources/up.png")));
up.setFitHeight(15);
up.setFitWidth(15);
upButton = new ImageButton(up);
down = new ImageView(new Image(getClass().getResourceAsStream(
"/resources/down.png")));
down.setFitHeight(15);
down.setFitWidth(15);
downButton = new ImageButton(down);
grid = new GridPane();
innerVB = new VBox();
innerVB.setPadding(new Insets(0, 0, 0, 3));
innerLowerGrid = new GridPane();
serialNumber = new Label("");
serialNumber.setFont(Font.font ("System", 10));
innerLowerGrid.add(serialNumber, 1, 0);
cellName = new Text("");
cellDesc = new Text("");
cellDesc.setStyle("-fx-font-weight: bold");
flow = new TextFlow();
flow.getChildren().addAll(cellDesc, cellName);
innerVB.getChildren().addAll(flow, serialNumber);
upButton.setOnMouseClicked(new OnMoveUp());
downButton.setOnMouseClicked(new OnMoveDown());
// set lower nested grid
grid.add(upButton, 0, 0);
grid.add(downButton, 1, 0);
grid.add(innerVB, 2, 0);
setGraphic(grid);
}
@Override
public void updateItem(ProviderAttribute item, boolean empty){
super.updateItem(item, empty);
if(item == null || empty){
setGraphic(null);
setText("");
setStyle("-fx-background-color: white;");
cellName.setText("");
cellDesc.setText("");
}else{
if(item instanceof DigitalIdentityType){
DigitalIdentityType certBean = item.getEncapsulatedBean();
setGraphic(grid);
cellName.setText(item.getStringName());
cellDesc.setText("Cert: ");
setText(item.getStringName());
setStyle("-fx-background-color: darkkhaki;");
if(certBean.getParentCert() != null){
serialNumber.setText("SN: " + certBean.getParentCert().getSerialNumber().toString());
}
}else if(item instanceof TSPServiceType){
setGraphic(grid);
cellName.setText(item.getStringName());
serialNumber.setText("");
cellDesc.setText("Service: ");
setStyle("-fx-background-color: lightblue;");
setText("Service: " + item.getStringName());
}else if(item instanceof TSPType){
setGraphic(grid);
cellName.setText(item.getStringName());
serialNumber.setText("");
cellDesc.setText("TSP: ");
setText("TSP: " + item.getStringName());
setStyle("-fx-background-color: bisque;");
}else{
GridPane pane = new GridPane();
pane.add(innerVB, 0, 0);
setGraphic(pane);
setText(item.getStringName());
serialNumber.setText("");
setStyle("-fx-background-color: white;");
// cellName.setText(item.getStringName());
}
}
}
public class OnMoveUp implements EventHandler<MouseEvent>{
private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";
@SuppressWarnings("unchecked")
@Override
public void handle(MouseEvent event) {
Button button = (Button)event.getSource();
button.setStyle(STYLE_PRESSED);
// get the table
TreeTableView<ProviderAttribute> table = (TreeTableView<ProviderAttribute>)
button.getParent().getParent().getParent()
.getParent().getParent().getParent().getParent();
// get the item
TreeTableRow<ProviderAttribute> row = (TreeTableRow<ProviderAttribute>)
button.getParent().getParent().getParent();
ProviderAttribute itemValue = row.getItem();
TreeItem<ProviderAttribute> item = row.getTreeItem();
ObservableList<TreeItem<ProviderAttribute>> list = item.getParent().getChildren();
if(item == null || list == null || list.size() <= 1) return;
// swap the current item with the one above it
int index = getIndexOf(list, itemValue);
if(index > 0){
Collections.swap(list, index, index-1);
table.getSelectionModel().clearSelection();
}
}
}
public class OnMoveDown implements EventHandler<MouseEvent>{
private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";
@SuppressWarnings("unchecked")
@Override
public void handle(MouseEvent event) {
Button button = (Button)event.getSource();
button.getGraphic().setOpacity(50);
button.setStyle(STYLE_PRESSED);
// get the table
TreeTableView<ProviderAttribute> table = (TreeTableView<ProviderAttribute>)
button.getParent().getParent().getParent()
.getParent().getParent().getParent().getParent();
// get the item
TreeTableRow<ProviderAttribute> row = (TreeTableRow<ProviderAttribute>)
button.getParent().getParent().getParent();
ProviderAttribute itemValue = row.getItem();
TreeItem<ProviderAttribute> item = row.getTreeItem();
ObservableList<TreeItem<ProviderAttribute>> list = item.getParent().getChildren();
if(item == null || list == null || list.size() <= 1) return;
int index = getIndexOf(list, itemValue);
if(index < list.size() - 1){
Collections.swap(list, index, index+1);
table.getSelectionModel().clearSelection();
}
}
}
public int getIndexOf(List<TreeItem<ProviderAttribute>> items, ProviderAttribute bean){
int index = -1;
for(int i = 0; i < items.size(); i++){
if(items.get(i).getValue().equals(bean))
return i;
}
return index;
}
public class ImageButton extends Button {
private final String STYLE_NORMAL = "-fx-background-color: transparent; -fx-padding: 2, 2, 2, 2;";
public ImageButton(ImageView image) {
setGraphic(image);
setStyle(STYLE_NORMAL);
setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
setStyle(STYLE_NORMAL);
// setOpacity(0);
}
});
}
}
// public class EventHandler
}
由于单元格被重复使用,有时您会使 innerVB
成为在最后一个 else 子句中创建的新 GridPane
的子节点;但是 innerVB
已经是另一个父节点的子节点(grid
,并且可能还有先前在同一 else 子句的先前调用中创建的网格窗格)。这违反了场景图的规则(一个节点只能是一个父节点的子节点),并且可能会混淆布局,导致无法预测的显示。
你可能应该这样做
grid.getChildren().clear();
每次调用 updateItem()
,然后
grid.addRow(0, upButton, downButton, innerVB);
或
grid.addRow(0, innerVB);
根据需要。