2013-07-22 6 views
12

Próbuję uzyskać TextArea do automatycznego przesuwania do dołu z nowym tekstem, który jest wprowadzany za pośrednictwem funkcji obsługi zdarzeń. Każda nowa pozycja to tylko jeden długi ciąg tekstu z każdym wpisem oddzielonym przez podział wiersza. Próbowałem obsługi zmian, który ustawia setscrolltop na Double.MIN_VALUE, ale bez skutku. Jakieś pomysły na to, jak można to zrobić?JavaFX TextArea i autoscroll

+1

Twój komentarz został usunięty (nie przeze mnie), ponieważ został opublikowany jako odpowiedź. Odpowiedziałem ci, że możesz zaakceptować odpowiedź, którą uważasz za słuszną, aby inni wiedzieli, że znalazłeś rozwiązanie, które cię satysfakcjonuje. Aby to zrobić, kliknij "V" oprócz odpowiedzi, którą wolisz, aby stała się zielona. Jest to również ważne dla twoich [własnych odpowiedzi] (http://stackoverflow.com/questions/19122056/camel-jpa-component-forcing-a-commit) – Math

Odpowiedz

20

Trzeba dodać detektor do elementu TextArea aby przewinąć do dołu, gdy jego wartość jest zmieniana:

@FXML private TextArea txa; 

... 

txa.textProperty().addListener(new ChangeListener<Object>() { 
    @Override 
    public void changed(ObservableValue<?> observable, Object oldValue, 
      Object newValue) { 
     txa.setScrollTop(Double.MAX_VALUE); //this will scroll to the bottom 
     //use Double.MIN_VALUE to scroll to the top 
    } 
}); 

Ale to słuchacz nie jest wyzwalany, gdy używasz metody setText(text), więc jeśli chcesz wyzwalać go po setText(text) użyć appendText(text) zaraz po nim:

txa.setText("Text into the textArea"); //does not trigger the listener 
txa.appendText(""); //this will trigger the listener and will scroll the 
        //TextArea to the bottom 

to brzmi bardziej jak robaka, raz setText() powinna wyzwalać changed słuchacza, jednak d nie. Jest to obejście, z którego korzystam i mam nadzieję, że ci to pomoże.

+2

'setScrollTop (Double.MIN_VALUE);' przewija do góry, natomiast 'MAX_VALUE' przewija się na sam dół. –

+0

@AdamJensen Zrobię tutaj test, ponieważ odpowiedziałem na to jakiś czas temu i po prostu nie pamiętam, patrząc na to. Dzięki za raport. – Math

+1

@AdamJensen miałeś absolutną rację. Właśnie to naprawiłem. Dzięki! – Math

7

txa.appendText ("") przewinie się na dół bez odbiornika. Staje się to problemem, jeśli chcesz przewinąć do tyłu, a tekst jest ciągle aktualizowany. txa.setText ("") umieszcza pasek przewijania z powrotem na górze i obowiązuje ten sam problem.

Moim rozwiązaniem było rozszerzenie klasy TextArea, dodanie tagu FXML z textArea do LogTextArea. Gdzie to działa, to oczywiście powoduje problemy w sceny konstruktora, ponieważ nie wiem, co ten składnik jest

import javafx.scene.control.TextArea; 
import javafx.scene.text.Font; 

public class LogTextArea extends TextArea { 

private boolean pausedScroll = false; 
private double scrollPosition = 0; 

public LogTextArea() { 
    super(); 
} 

public void setMessage(String data) { 
    if (pausedScroll) { 
     scrollPosition = this.getScrollTop(); 
     this.setText(data); 
     this.setScrollTop(scrollPosition); 
    } else { 
     this.setText(data); 
     this.setScrollTop(Double.MAX_VALUE); 
    } 
} 

public void pauseScroll(Boolean pause) { 
    pausedScroll = pause; 
} 

} 
3

alternatywą dla tego dziwnego setText bug bez użycia appendText

textArea.selectPositionCaret(textArea.getLength()); 
textArea.deselect(); //removes the highlighting 
1

Jeden dodatek Dodałbym do jamesarbrown-tych Odpowiedzią byłoby użycie właściwości boolowskiej, aby można było uzyskać do niej dostęp z poziomu FXML. Coś takiego.

import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.scene.control.TextArea; 

public class LogTextArea extends TextArea { 
    private final BooleanProperty pausedScrollProperty = new SimpleBooleanProperty(false); 
    private double scrollPosition = 0; 

    public LogTextArea() { 
     super(); 
    } 

    public void setMessage(String data) { 
     if (isPausedScroll()) { 
      scrollPosition = this.getScrollTop(); 
      this.setText(data); 
      this.setScrollTop(scrollPosition); 
     } else { 
      this.setText(data); 
      this.setScrollTop(Double.MAX_VALUE); 
     } 
    } 

    public final BooleanProperty pausedScrollProperty() { return pausedScrollProperty; } 
    public final boolean isPausedScroll() { return pausedScrollProperty.getValue(); } 
    public final void setPausedScroll(boolean value) { pausedScrollProperty.setValue(value); } 
} 

Jednak problem z tą odpowiedzią jest to, że jeśli masz zalany nieracjonalnie dużej ilości danych wejściowych (co może się zdarzyć podczas pobierania dziennik z IO Stream) nitka JavaFX będzie zamknąć, ponieważ TextArea dostaje za dużo danych.