Я изучаю JavaFX и сейчас смотрю на TableView. Я хочу поместить цены на акции в таблицу и мигать / мигать фоном ячейки при обновлении.
Я много искал и видел несколько предложений, однако не смог найти то, что я ищу , Кроме того, мне кажется, что у меня проблемы с пониманием логики c таблиц, в частности, когда и как создаются и обновляются ячейки.
Рассмотрим следующий код (в основном заимствованный из http://jaakkola.net/juhani/blog/?p=233 ):
public class FlashingTableCell<S, T> extends TableCell<S, T> {
private static final Color INCREASE_HIGHLIGHT_COLOR = Color.rgb(0, 255, 0, 0.8);
private static final Color DECREASE_HIGHLIGHT_COLOR = Color.rgb(255, 0, 0, 0.8);
private static final Color HIGHLIGHT_COLOR = Color.rgb(0, 255, 0, 0.8);
private static final Duration HIGHLIGHT_TIME = Duration.millis(600);
private final Background bgIncrease = new Background(new BackgroundFill(INCREASE_HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
private final Background bgDecrease = new Background(new BackgroundFill(DECREASE_HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
private final Background bgChange = new Background(new BackgroundFill(HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
private final BorderPane background = new BorderPane();
private final Label lblText = new Label("");
private final FadeTransition animation = new FadeTransition(HIGHLIGHT_TIME, background);
private final StackPane container = new StackPane();
private T prevValue;
private S prevItem;
final private Comparator<T> comparator;
public FlashingTableCell(Comparator<T> comparator, Pos alignment) {
super();
this.comparator = comparator;
lblText.textProperty().bindBidirectional(textProperty());
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setPadding(Insets.EMPTY);
container.getChildren().addAll(background, lblText);
container.setAlignment(alignment);
setGraphic(container);
}
@Override
protected void updateItem(T value, boolean empty) {
super.updateItem(value, empty);
System.out.println("updateItem " + this.hashCode() + " " + getIndex() + " value=" + value + " (" + prevValue + ")" + empty);
S currentItem = getTableRow() != null && getTableRow().getItem() != null ? (S) getTableRow().getItem() : null;
/*
* We check that the value has been updated and that the row model/item
* under the cell is the same. JavaFX table reuses cells so item is not
* always the same!
*/
boolean valueChanged = (prevValue == null && value != null) || (value != null && (prevValue.hashCode() != value.hashCode()));
boolean sameItem = currentItem != null && prevItem != null && currentItem == prevItem;
if (valueChanged && sameItem) {
if (comparator != null) {
int compare = comparator.compare(value, prevValue);
if (compare > 0) {
background.setBackground(bgIncrease);
} else if (compare < 0) {
background.setBackground(bgDecrease);
}
} else {
background.setBackground(bgChange);
}
lblText.setText(String.format("%1.2f", value));
animation.setFromValue(1);
animation.setToValue(0);
animation.setCycleCount(1);
animation.setAutoReverse(false);
animation.playFromStart();
}
prevValue = value;
prevItem = currentItem;
}
}
и эта фабрика ячеек:
public class FlashingTableCellFactory<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {
@Override
public TableCell<S, T> call(TableColumn<S, T> p) {
System.out.println("************** CREATING FLASHING TABLE CELL **************");
FlashingTableCell<S,T> cell = new FlashingTableCell<S,T>(null, Pos.CENTER);
return cell;
}
}
И я использую это так:
public class Main extends Application {
Timer timer = new Timer();
@Override
public void start(Stage primaryStage) {
TableView<InstrumentPrice> table = new TableView<>();
ObservableList<InstrumentPrice> data = getInitialTableData();
table.setItems(data);
TableColumn<InstrumentPrice, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(new PropertyValueFactory<>("instrumentName"));
TableColumn<InstrumentPrice, Double> openCol = new TableColumn<>("Open");
openCol.setCellValueFactory(new PropertyValueFactory("open"));
// Flashing table cell
FlashingTableCellFactory<tabletest1.InstrumentPrice, Double> ftc2 = new FlashingTableCellFactory<tabletest1.InstrumentPrice, Double>();
openCol.setCellFactory(ftc2);
table.getColumns().setAll(nameCol, openCol);
timer.schedule(new TimerTask() {
@Override
public void run() {
// Get and update first item in data array
InstrumentPrice p = data.get(0);
p.setOpen(p.getOpen()+1.0);
data.set(0, p);
}
}, 10*1000, 5*1000); // 10 seconds
StackPane rootLayout = new StackPane(table);
Scene scene = new Scene(rootLayout, 1000, 300);
primaryStage.setTitle("Example");
primaryStage.setScene(scene);
primaryStage.setX(0);
primaryStage.setY(0);
primaryStage.show();
}
private ObservableList<InstrumentPrice> getInitialTableData() {
List list = new ArrayList<InstrumentPrice>();
list.add(new InstrumentPrice("ABC", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("DEF", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("GHI", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("JKL", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("MNO", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("PQR", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("STU", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
list.add(new InstrumentPrice("VWX", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
ObservableList<InstrumentPrice> data = FXCollections.observableList(list);
return data;
}
public static void main(String[] args) {
launch(args);
}
}
Я печатаю отладку на консоль, и вот некоторые из них:
************** CREATING FLASHING TABLE CELL 1299017468
updateItem 1299017468 0 value=0.0 (null)false
updateItem 1299017468 1 value=0.0 (0.0)false
updateItem 1299017468 2 value=0.0 (0.0)false
updateItem 1299017468 3 value=0.0 (0.0)false
updateItem 1299017468 4 value=0.0 (0.0)false
updateItem 1299017468 5 value=0.0 (0.0)false
updateItem 1299017468 6 value=0.0 (0.0)false
updateItem 1299017468 7 value=0.0 (0.0)false
updateItem 1299017468 -1 value=null (0.0)true
************** CREATING FLASHING TABLE CELL 312035237
updateItem 312035237 0 value=0.0 (null)false
updateItem 312035237 -1 value=null (0.0)true
************** CREATING FLASHING TABLE CELL 616040193
updateItem 616040193 0 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 1836880566
updateItem 1836880566 1 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 1717614984
updateItem 1717614984 2 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 114981818
updateItem 114981818 3 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 151715918
updateItem 151715918 4 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 1690114806
updateItem 1690114806 5 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 397552694
updateItem 397552694 6 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 705642570
updateItem 705642570 7 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 575848070
updateItem 575848070 8 value=null (null)true
************** CREATING FLASHING TABLE CELL 349657094
updateItem 349657094 9 value=null (null)true
************** CREATING FLASHING TABLE CELL 221445895
updateItem 221445895 10 value=null (null)true
************** CREATING FLASHING TABLE CELL 666967962
updateItem 666967962 11 value=null (null)true
updateItem 616040193 -1 value=null (0.0)true
updateItem 1836880566 -1 value=null (0.0)true
updateItem 1717614984 -1 value=null (0.0)true
updateItem 114981818 -1 value=null (0.0)true
updateItem 151715918 -1 value=null (0.0)true
updateItem 1690114806 -1 value=null (0.0)true
updateItem 397552694 -1 value=null (0.0)true
updateItem 705642570 -1 value=null (0.0)true
updateItem 666967962 0 value=1.0 (null)false
updateItem 666967962 0 value=1.0 (1.0)false
updateItem 221445895 1 value=0.0 (null)false
updateItem 221445895 1 value=0.0 (0.0)false
updateItem 349657094 2 value=0.0 (null)false
updateItem 349657094 2 value=0.0 (0.0)false
updateItem 575848070 3 value=0.0 (null)false
updateItem 575848070 3 value=0.0 (0.0)false
updateItem 705642570 4 value=0.0 (0.0)false
updateItem 705642570 4 value=0.0 (0.0)false
updateItem 397552694 5 value=0.0 (0.0)false
updateItem 397552694 5 value=0.0 (0.0)false
updateItem 1690114806 6 value=0.0 (0.0)false
updateItem 1690114806 6 value=0.0 (0.0)false
updateItem 151715918 7 value=0.0 (0.0)false
updateItem 151715918 7 value=0.0 (0.0)false
updateItem 114981818 8 value=null (0.0)true
updateItem 114981818 8 value=null (0.0)true
updateItem 1717614984 9 value=null (0.0)true
updateItem 1717614984 9 value=null (0.0)true
updateItem 1836880566 10 value=null (0.0)true
updateItem 1836880566 10 value=null (0.0)true
updateItem 616040193 11 value=null (0.0)true
updateItem 616040193 11 value=null (0.0)true
Есть много проблем, но в основном мне интересно:
- Почему метод updateItem () вызывается дважды для каждого обновления?
- Когда я обновляю только строку 0, почему я получаю вызовы updateItem () для строк 1..n? Я не изменяю размеры таблицы или чего-либо еще.
- Лог "sameItem" c, похоже, не работает вообще
- Что я должен делать, когда updateItem вызывается с пустым == true ?
Каким-то образом я считаю, что все эти вопросы связаны, и что это как-то вызвано моим неправильным пониманием чего-то с фабрикой клеток и созданием клеток. Я делал подобные вещи во многих других языках / структурах, и никогда не был так смущен, как сейчас ...
Буду признателен за любую информацию о том, что я сделал неправильно!