작업 : 항목이 ListView의 보이는 영역에 있는지 확인하십시오.JavaFX ListView 셀 팩터 리 렌더링 완료 이벤트
솔루션 : 렌더링 할 항목이 포함 된 JavaFX ListView가 있습니다. ListView의 가시 영역에있는 항목을 파악하기 위해 사용자에게 표시되는 항목의 수를 계산하는 셀 팩터 리를 구현했습니다.
1. 항목 추가를
2.을은 ListView를 보이는 경우 :
문제 : 항목을 계산하기 위해 , 항목 추가 스레드 항목이 작동하고 렌더링을 추가 완료 전지 공장까지 기다려야합니다 (스레드 호출). 그러나 JavaFX UI 스레드가 내부 Quantum Toolkit 기법을 사용하여 렌더링을 마치는 시점을 호출 스레드가 알 수 없으므로이를 구현하는 방법을 모르겠습니다. 셀 팩터 리 항목이 동기화 할 수없는 JavaFX 내부의 별도 스레드로 렌더링됩니다.
거친 호출 스레드 지연을 추가하면 스레드 동기화 문제를 명확하게 나타내는 문제가 해결되지만 더 우아하고 명확한 솔루션이 필요합니다. 크로스 스레드 관리를 엉망으로 며칠 후
public class MessengerServiceContext {
@Override
public void messageReceived(final MessageReceivedEvent messageReceivedEvent) {
...
//Calling thread method
messengerServiceControl.receiveMessage(messengerMessageData);
//Main thread is paused for several seconds to wait JavaFX UI threads.
//Ugly and erroneous
//Demonstrates the cause of the problem
try {
Thread.sleep(2000);
} catch (InterruptedException ex) { Logger.getLogger(MessengerServiceControl.class.getName()).log(Level.SEVERE, null, ex);
}
if (!messengerServiceControl.getMessageElementControlVisibility(messengerMessageData)) {
int newMessagesCount = getNewMessagesCount().get();
getNewMessagesCount().set(++newMessagesCount);
}
}
}
public class MessengerServiceControl implements Initializable {
...
private TrackingListCellFactory<MessageElementControl> messengerOutputWindowListViewCellFactory;
...
//Calling (message processing) thread method which inserts ListView item
public void receiveMessage(final MessengerMessageData messengerMessageData) {
//Calling MessengerServiceControl model method to insert items in ListView using JavaFX UI thread
MessageElementControl messageElementControl = model.createMessage(messengerMessageData, false);
//Tried scene and parent property
messageElementControl.sceneProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
if (!getMessageElementControlVisibility(messengerMessageData)) {
int newMessagesCount = getNewMessagesCount().get();
getNewMessagesCount().set(++newMessagesCount);
}
}
}
boolean getMessageElementControlVisibility(final MessengerMessageData messengerMessageData) {
return messengerOutputWindowListViewCellFactory.getItemVisibility(messengerMessageData);
}
//Cell factory class which is responsible for items rendering:
private static class TrackingListCellFactory<T extends MessageElementControl> implements Callback<ListView<T>, ListCell<T>> {
//Items which have cells visible to the user
private final Set<T> visibleItems = new HashSet();
TrackingListCellFactory() {
}
boolean getItemVisibility(final MessengerMessageData messengerMessageData) {
synchronized (this) {
Optional<T> messageElementControlOptional = visibleItems.stream().filter((item) -> {
return item.getMessageData().getMessageCreatedDate().isEqual(messengerMessageData.getMessageCreatedDate());
}).findFirst();
return messageElementControlOptional.isPresent();
}
}
@Override
public ListCell<T> call(ListView<T> param) {
//Create cell that displays content
ListCell<T> cell = new ListCell<T>() {
@Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
setGraphic(item);
}
}
};
//Add and remove item when cell is reused for different item
cell.itemProperty().addListener((observable, oldItem, newItem) -> {
synchronized (TrackingListCellFactory.this) {
if (oldItem != null) {
visibleItems.remove(oldItem);
}
if (newItem != null) {
visibleItems.add(newItem);
}
}
});
//Update set when bounds of item change
ChangeListener<Object> boundsChangeHandler = (observable, oldValue, newValue) -> {
synchronized (TrackingListCellFactory.this) {
T item = cell.getItem();
if (item != null) {
visibleItems.add(item);
}
}
});
//Must update either if cell changes bounds, or if cell moves within scene (e.g.by scrolling)
cell.boundsInLocalProperty().addListener(boundsChangeHandler);
cell.localToSceneTransformProperty().addListener(boundsChangeHandler);
return cell;
}
}
}
https://stackoverflow.com/questions/46474385/how-to-find-the-indices-of-the-visible-rows-in-a-tableview-in-javafx-9에서 살펴보십시오. 테이블 뷰 행에 대해 유사한 기능을 제공합니다. –
답장을 보내 주셔서 감사합니다. 내가 제공 한 샘플에 대한 빠른 코드 리뷰는 TableView에서 사용 된 것과 거의 동일한 기술을 보여줍니다. 그러나, 제 문제는 계산 논리보다는 멀티 스레딩 문제에 있습니다. 그래서 기본적으로 호출 스레드에서 getItemVisibility() 팩토리 메서드를 호출하기 전에 항목이 추가되고 공장에서 렌더링되었는지 확인해야합니다. – Andreas
http://stackoverflow.com/help/mcve – kleopatra