JavaFX 2: Tworzenie ScrollPane automatycznie przewija do krawędzi po dodaniu zawartości
Korzystając z JavaFX 2, mam podstawowy przykład aScrollPane
który zawieraHBox
zLabel
s. Chcę być w stanie dodaćLabel
doHBox
i jednocześnie przewiń do prawej krawędziScrollPane
więc nowo dodanyLabel
jest widoczny. Moja obecna metoda używasetHvalue()
aby ustawić pozycję przewijania igetHmax()
aby uzyskać maksymalną dozwoloną odległość przewijania.
Problem polega na tym, że kiedy ustawiam pozycję przewijania za pomocągetHmax()
, jest tak jakby został dodanyLabel
nie jest obliczany wScrollPanel
szerokość przewijania. Czy istnieje sposób na zaktualizowanie tej wewnętrznej szerokości przed próbąsetHvalue
?
Zobacz ten prosty przykładowy kod, który pokazuje problem.
W szczególności zwróć uwagę naaddChatItem(String item)
metoda, która zawiera logikę przewijania do krawędziScrollPane
.
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class ScrollPaneTest extends Application {
static int defaultFontSize = 30;
ScrollPaneTest scrollPaneTest = this;
ScrollPane chatBoxScrollPane = new ScrollPane();
HBox chatBox = new HBox();
Chatter chatter = new Chatter();
public static void main(String[] args) {
launch(args);//default
}
@Override
public void stop() throws Exception {
super.stop();
System.exit(0);
}
@Override
public void start(Stage primaryStage) {
BorderPane borderPane = new BorderPane();
StackPane chatBoxStackPane = new StackPane();
chatBoxScrollPane.setContent(chatBox);
//chatBoxScrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
chatBoxScrollPane.setMaxHeight(50);
chatBoxStackPane.getChildren().add(chatBoxScrollPane);
borderPane.setCenter(chatBoxStackPane);
Scene scene = new Scene(borderPane, 800, 600);
primaryStage.setScene(scene);
primaryStage.setTitle("Scroll Demo");
primaryStage.show();
new Thread("mainGameControlThread") {
public void run() {
chatter.chatLoop(scrollPaneTest);
}
}.start();
}
public void addChatItem(String chatString) {
Label title = new Label(chatString);
title.setFont(new Font("Verdana", defaultFontSize));
chatBox.getChildren().add(title);
chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax());
}
class Chatter {
public void chatLoop(final ScrollPaneTest test) {
Timer closingCeremonyTimer = new Timer();
closingCeremonyTimer.schedule(new TimerTask() {
public void run() {
Platform.runLater(new Runnable() {
@Override
public void run() {
test.addChatItem("Hello World. ");
}
});
chatLoop(test);
}
}, (long) (0.5*1000));
}
}
}
Oto obraz problemu, zauważ, jakScrollPane
nie przewinął się do prawej krawędzi.
Edytować:
Wymyśliłem obejście, ale jest to dalekie od ideału. Moim rozwiązaniem jest uruchomienie timera, który będzie używałsetHvalue()
po upływie wystarczającego czasuScrollPane
odkryć prawdziwą szerokość jego treści. mójaddChatItem()
metoda wygląda teraz tak:
public void addChatItem(String chatString) {
Label title = new Label(chatString);
title.setFont(new Font("Verdana", defaultFontSize));
chatBox.getChildren().add(title);
Timer closingCeremonyTimer = new Timer();
closingCeremonyTimer.schedule(new TimerTask() {
public void run() {
chatBoxScrollPane.setHvalue(chatBoxScrollPane.getHmax());
}
}, (long) 50);
}
Niestety, liczba 50 w tej metodzie musi być większa niż czas potrzebnyScrollPane
aby zaktualizować szerokość wewnętrznej zawartości, a to wydaje się być dalekie od zagwarantowania.