들어오는 구매 판매 주문, 가격 등으로 목록을 업데이트하는 백그라운드 스레드가 있습니다. 내 브로커의 데이터를 비동기식으로 가져옵니다. 목록의 업데이트가 백그라운드 스레드에서 순차적으로 발생하는 것이 중요합니다.JavaFX 테이블의 백그라운드 스레드에서 목록의 변경 사항을 표시하는 방법은 무엇입니까?
"Not on FX 응용 프로그램 스레드 IllegalStateException"위험없이 javafx 테이블에 mainPortfolioList를 표시하려고합니다. 내가 찾은 가장 가까운 해결책은 JavaFX refresh TableView thread입니다. 그러나 목록이 다른 스레드에 있으면 이해할 수 있습니다.
저는 Java가 매우 새로워서 addlistener로 제 문제를 해결하려고했습니다. 나는 내가 원했던 것과 내가 지금까지 한 것을 보여주기 위해 간단한 예를 만들었다.
내 MainPortfolioList의 업데이트를 JavaFX 테이블에 표시하려면 어떻게합니까?
PortfolioController
import application.Test;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.NumberStringConverter;
public class PortfolioController {
@FXML private Button btnTest;
@FXML private TableView<Portfolio> tblPortfolio;
@FXML private TableColumn<Portfolio, String> colSymbol;
@FXML private TableColumn<Portfolio, Number> colQuantity;
@FXML private TableColumn<Portfolio, Number> colPrice;
private ObservableList<Portfolio> fxPortfolioList;
@FXML
private void initialize() {
tblPortfolio.setEditable(true);
colSymbol.setCellValueFactory(data -> data.getValue().colSymbolProperty());
colQuantity.setCellValueFactory(data -> data.getValue().colQuantityProperty());
colPrice.setCellValueFactory(data -> data.getValue().colPriceProperty());
colSymbol.setCellFactory(TextFieldTableCell.forTableColumn());
colQuantity.setCellFactory(TextFieldTableCell.<Portfolio, Number>forTableColumn(
new NumberStringConverter("#,##0.00")));
colQuantity.setOnEditCommit(event -> {
int newValue = event.getNewValue().intValue();
event.getRowValue().setColQuantity(newValue);});
colPrice.setCellFactory(TextFieldTableCell.<Portfolio, Number>forTableColumn(
new NumberStringConverter("#,##0.00")));
fxPortfolioList = FXCollections.observableArrayList();
tblPortfolio.setItems(fxPortfolioList);
Test.mainPortfolioList.addListener((ListChangeListener.Change<? extends Portfolio> c) -> {
while (c.next()) {
if (c.wasAdded()) {
Platform.runLater(() -> {
for (Portfolio asset : c.getAddedSubList()) {
fxPortfolioList.add(asset);
}
});
} else if (c.wasRemoved()) {
Platform.runLater(() -> {
for (Portfolio asset : c.getRemoved()) {
fxPortfolioList.remove(asset);
}
});
} else if (c.wasUpdated()) {
Platform.runLater(() -> {
for (int i = c.getFrom(); i < c.getTo(); ++i) {
fxPortfolioList.set(i, c.getList().get(i));
}
});
}
}
});
}
@FXML
void btnTestClicked(ActionEvent event) {
Test test = new Test();
test.dataStream(this);
}
}
포트폴리오
import javafx.beans.Observable;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.util.Callback;
public class Portfolio {
private final StringProperty colSymbol;
private final IntegerProperty colQuantity;
private final DoubleProperty colPrice;
public Portfolio(String symbol, int quantity, double price) {
this.colSymbol = new SimpleStringProperty(symbol);
this.colQuantity = new SimpleIntegerProperty(quantity);
this.colPrice = new SimpleDoubleProperty(price);
}
// extractor
public static Callback<Portfolio, Observable[]> extractor() {
return (Portfolio p) -> new Observable[] {
p.colSymbolProperty(),
p.colQuantityProperty(),
p.colPriceProperty(),
};
}
// property
public StringProperty colSymbolProperty() {
return colSymbol;
}
public IntegerProperty colQuantityProperty() {
return colQuantity;
}
public DoubleProperty colPriceProperty() {
return colPrice;
}
// getter
public String getColSymbol() {
return colSymbol.get();
}
public int getColQuantity() {
return colQuantity.get();
}
public double getColPrice() {
return colPrice.get();
}
// setter
public void setColSymbol(String newValue) {
colSymbol.set(newValue);
}
public void setColQuantity(int newValue) {
colQuantity.set(newValue);
}
public void setColPrice(double newValue) {
colPrice.set(newValue);
}
}
import controller.portfolio.Portfolio;
import controller.portfolio.PortfolioController;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Test {
public static ObservableList<Portfolio> mainPortfolioList =
FXCollections.observableArrayList(Portfolio.extractor());
public void dataStream(PortfolioController portfolioController) {
// Need to be sequentially
// The task only simulates simplified operations
Runnable task =() -> {
// add stock
mainPortfolioList.add(new Portfolio("AAPL", 13, 153.03));
mainPortfolioList.add(new Portfolio("MSFT", 31, 67.51));
// Change the quantity
for (Portfolio asset : mainPortfolioList) {
if (asset.getColSymbol().equals("AAPL")) {
asset.setColQuantity(55);
}
}
// run price updates
for (int k = 0; k < 15; k++) {
for (int m = 0; m < mainPortfolioList.size(); m++) {
double random = Math.random() * 50 + 1;
String symbol = mainPortfolioList.get(m).getColSymbol();
setTickPrice(symbol, 4, random);
randomSleep();
}
}
// remove stock
for (Portfolio asset : mainPortfolioList) {
if (asset.getColSymbol().equals("AAPL")) {
mainPortfolioList.remove(asset);
}
}
};
Thread t = new Thread(task, "Simulation");
t.setDaemon(true);
t.start();
}
public void setTickPrice(String symbol, int tickType, double price) {
for (Portfolio asset : mainPortfolioList) {
if (asset.getColSymbol().equals(symbol)) {
switch(tickType){
case 4: // Last Price
asset.setColPrice(price);
break;
}
}
}
}
private void randomSleep() {
try {
Thread.sleep((int)(Math.random() * 300));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
홈페이지 테스트 시뮬레이션
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/view/Portfolio.fxml"));
Scene scene = new Scene(root, 500, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
화면에 무언가를 바꿀 것 (IB 가정) 독자 스레드에서 오는3210
보기
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<BorderPane prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.portfolio.PortfolioController">
<top>
</top>
<center>
<TableView fx:id="tblPortfolio" prefHeight="200.0" prefWidth="200.0" tableMenuButtonVisible="true" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="colSymbol" maxWidth="80.0" minWidth="60.0" prefWidth="-1.0" text="Symbol" />
<TableColumn fx:id="colQuantity" maxWidth="60.0" minWidth="40.0" prefWidth="-1.0" text="Quantity" />
<TableColumn fx:id="colPrice" maxWidth="69.0" minWidth="49.0" prefWidth="-1.0" text="Price" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</center>
<bottom>
</bottom>
<top>
<HBox BorderPane.alignment="CENTER">
<children>
<Button fx:id="btnTest" mnemonicParsing="false" onAction="#btnTestClicked" text="Test">
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</top>
</BorderPane>
대화 형 중개인이 맞습니다. 나는 당신의 첫번째 해결책을 피하기를 희망했다. 두 번째 것은 꽤 흥미 롭습니다. 나는 나중에 그것을 시도 할 것이다 :) – akut
각 래퍼 메서드로 무엇을하는지 확신 할 수 없지만 고려해야 할 2 가지가있다. 'Platform.runLater'는 GUI 스레드에 대한 모든 처리를 수행하므로 길면 GUI 스레드가 응답하지 않게됩니다. 따라서 최소 금액 만하십시오. 그러나 리더 스레드를 오랫동안 처리하면 결국 소켓을 차단할 위험이 있습니다. 이것은 현대 하드웨어에서는 일반적으로 문제가되지 않습니다. 극한 상황에서 또 다른 계산 스레드가 필요한지 파악하기 위해서는 각 스레드에서 수행해야 할 작업을 결정하고 이러한 요구 사항을 조정해야합니다. – brian