gpt4 book ai didi

javafx:如何创建一个 cellFactory 来考虑一个对象的两个属性?

转载 作者:行者123 更新时间:2023-12-03 20:22:00 25 4
gpt4 key购买 nike

我有一个 ReadOnlyBooleanProperty名为 caution对于每个 Trade我创建的对象。每个Trade对象填充 TableView 中的一行 fxTransactionLog .现在我希望表格 cellcaution 时保持以绿色闪烁,并且同一卷单元格中的文本变为黄色。是true .

现在我正在努力让电池闪光。问题是我要求体积属性列可编辑并根据另一个 boolean 绑定(bind)属性闪烁。

本质上,cellFactory 正在查看两个不同的属性,这就是使这个问题变得非常困难的原因。 因为我经常要从volume列中查找表格行来获取Trade对象,然后查找相应的boolean-binding caution属性。这种方法似乎很复杂。

public class Trade{
private DoubleProperty volume;
private ReadOnlyBooleanWrapper caution;

public Trade(double volume){
this.volume = new SimpleDoubleProperty(volume);
this.caution = new ReadOnlyBooleanWrapper();
this.caution.bind(this.volume.greaterThan(0));
}

}

这是我的代码,但它给我错误。

fvolume.setCellValueFactory(new PropertyValueFactory<Trade,Double>("price"));
PseudoClass flashHighlight = PseudoClass.getPseudoClass("flash-highlight");
volume.setCellFactory(


tv -> {
TableCell<Trade, Double> cell = new TableCell<>();
Timeline flasher = new Timeline(

new KeyFrame(Duration.seconds(0.5), e -> {
cell.pseudoClassStateChanged(flashHighlight, true);
}),

new KeyFrame(Duration.seconds(1.0), e -> {
cell.pseudoClassStateChanged(flashHighlight, false);
})
);
flasher.setCycleCount(Animation.INDEFINITE);

ChangeListener<Boolean> cautionListener = (obs, cautionWasSet, cautionIsNowSet) -> {
if (cautionIsNowSet) {
flasher.play();
} else {
flasher.stop();
cell.pseudoClassStateChanged(flashHighlight, false);
}
};

cell.itemProperty().addListener((obs, oldItem, newItem) -> {
if (oldItem != null) {
oldItem.cautionProperty().removeListener(cautionListener); //<--- PROBLEM 1
}
if (newItem == null) {
flasher.stop();
cell.pseudoClassStateChanged(flashHighlight, false);
} else {
newItem.cautionProperty().addListener(cautionListener); //<-- PROBLEM 2
if (newItem.cautionProperty().get()) { //<-- PROBLEM 3
flasher.play();
} else {
flasher.stop();
cell.pseudoClassStateChanged(flashHighlight, false);
}
}
});
return cell ;
}
);

更新:我突出显示了代码出错的地方,请参阅 PROBLEM 1,2,3多于。出现错误:the method cautionProperty() is undefined for the Type Double.

我还尝试添加 getTableRow().getItem()oldItem.cautionProperty().removeListener(cautionListener); <--- PROBLEM 1 , 变成 oldItem.getTableRow().getItem().cautionProperty().removeListener(cautionListener); .

我仍然遇到同样的错误:the method cautionProperty() is undefined for the Type Double.

UPDATE2:我也尝试替换 OldItemnewItemcell并将其转换回 Trade对象,但是当我编译时,我在以下几行中得到了一个 NullPointerException。

((Trade)cell.getTableRow().getItem()).cautionProperty().removeListener(cautionListener);


((Trade) cell.getTableRow().getItem()).cautionProperty().addListener(cautionListener);

错误日志:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at application.Controller.lambda$19(Controller.java:378)
at application.Controller$$Lambda$370/220504298.changed(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)

更新 3: 我尝试了另一种方法来解决这个问题。但是我仍然遇到类似的错误:NullPointerException在以下行中

 final BooleanExpression be = flashExtractor.apply((T) getTableRow().getItem());

方法二:

public static class AnimatedTableCell<T> extends TableCell<T,Double>{
private static final PseudoClass PS_Cell_Flash = PseudoClass.getPseudoClass("flash-cell-positive");

private final Function<T,BooleanExpression> flashExtractor;
private final ChangeListener<Boolean> flashListener = (fObs, fOld, fNew) -> flasherChanged(fNew);
private final Timeline flashTimeline;

// constructor
public AnimatedTableCell(Function<T, BooleanExpression> fFlashExtractor){
flashExtractor = fFlashExtractor;
flashTimeline = new Timeline(
new KeyFrame(Duration.seconds(0.5), e -> pseudoClassStateChanged(PS_Cell_Flash, true)),
new KeyFrame(Duration.seconds(1.0), e -> pseudoClassStateChanged(PS_Cell_Flash, false)));
flashTimeline.setCycleCount(Animation.INDEFINITE);
}

private void flasherChanged(boolean fNew) {
if (fNew) {
flashTimeline.play();
} else {
flashTimeline.stop();
pseudoClassStateChanged(PS_Cell_Flash, false);
}
}

//@SuppressWarnings("unchecked")
@Override
protected void updateItem(Double item, boolean empty) {
System.out.println("getItem(): " + (T) getTableRow().getItem());
if (getItem() != null) {
// Problem IN THIS LINE
final BooleanExpression be = flashExtractor.apply((T) getTableRow().getItem());
if (be != null) {
be.removeListener(flashListener);
}
}

super.updateItem(item, empty);

if (getItem() != null) {
final BooleanExpression be = flashExtractor.apply((T) getTableRow().getItem());
if (be != null) {
be.addListener(flashListener);
flasherChanged(be.get());
}
}
}

}

最佳答案

这是@eckig 解决方案的替代方案(非常好:这只是一种不同的方法)。

由于您基本上只是尝试更改样式,因此您可以在 TableRow 上设置 CSS 伪类。而不是 TableCell ,然后只需使用您的 CSS 样式表来更新您感兴趣的特定单元格的颜色。

这里的优势,也许是对于 TableRow 来说要容易得多。查看 Trade 中的任何属性比 TableCell 的类,还有你的 TableCell仍然是更直观的类型 ( TableCell<Trade, Double> ),其数据是显示的数据。

所以你会这样做

fxTransactionLog.setRowFactory(tv -> {
TableRow<Trade> row = new TableRow<>();
Timeline flasher = new Timeline(

new KeyFrame(Duration.seconds(0.5), e ->
row.pseudoClassStateChanged(flashHighlight, true)),

new KeyFrame(Duration.seconds(1.0), e ->
row.pseudoClassStateChanged(flashHighlight, false))
);

flasher.setCycleCount(Animation.INDEFINITE);

ChangeListener<Boolean> cautionListener = (obs, cautionWasSet, cautionIsNowSet) -> {
if (cautionIsNowSet) {
flasher.play();
} else {
flasher.stop();
row.pseudoClassStateChanged(flashHighlight, false);
}
};

cell.itemProperty().addListener((obs, oldItem, newItem) -> {
if (oldItem != null) {
oldItem.cautionProperty().removeListener(cautionListener);
}
if (newItem == null) {
flasher.stop();
row.pseudoClassStateChanged(flashHighlight, false);
} else {
newItem.cautionProperty().addListener(cautionListener);
if (newItem.cautionProperty().get()) { //<-- PROBLEM 3
flasher.play();
} else {
flasher.stop();
row.pseudoClassStateChanged(flashHighlight, false);
}
}
});
return row ;
});

现在你只需要给你想要对状态变化使用react的单元格一个样式类。您可以使用细胞工厂执行此操作:

fxTransactionLogVolume.setCellFactory(col -> {
TableCell<Trade, Double> cell = new TableCell<Trade, Double>() {
@Override
public void updateItem(Double volume, boolean empty) {
super.updateItem(volume, empty);
if (empty) {
setText(null);
} else {
setText(volume.toString());
}
}
};

cell.getStyleClass().add("trade-volume-cell");
return cell ;
}

现在在你的外部样式表中你可以做

.table-row-cell:flash-highlight .trade-volume-cell {
-fx-background-color: transparent, green ;
-fx-text-fill: yellow ;
}

请注意,您可以在此处使用您喜欢的任何单元实现;由于“闪烁”实际上是由表行控制的,因此不会造成干扰。所以如果你有一些更复杂的单元实现(例如编辑),你仍然可以使用它:

fxTransactionLogVolume.setCellFactory( col -> {
MySpecialTableCell cell = new MySpecialTableCell();
cell.getStyleClass().add("trade-volume-cell");
return cell ;
});

public class MySpecialTableCell extends TableCell<Trade, Double> {

// whatever you need to do here...

}

关于javafx:如何创建一个 cellFactory 来考虑一个对象的两个属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32273925/

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