JScrollBars setValue not lowered
-
Used
JScrollPane
♪ It is.JTextArea
♪ I want to do it.JTextArea.setText()
and lower verticalScrollBar
To the bottom.Code:
final JTextArea text = new JTextArea(); JScrollPane panelSCROLL = new JScrollPane(text); text.setText(text.getText().concat(new String(БАЙТЫ ИЗ ФАЙЛА))); panelSCROLL.getVerticalScrollBar().setValue(panelSCROLL.getVerticalScrollBar().getMaximum());
But...
ScrollBar
It's not down to the bottom, it's up to the old position, that's the maximum that was before.setText
;Here's the example:
import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTextArea;
public class JavaApplication19 {
static JScrollPane scrollPane = null;
static JTextArea text = null;
public static void main(String[] args) {
JFrame testFrame = new JFrame();
testFrame.setTitle("TEST");text = new JTextArea(); scrollPane = new JScrollPane(text); javax.swing.GroupLayout group = new javax.swing.GroupLayout(testFrame); //testFrame.setLayout(group); group.setHorizontalGroup(group.createSequentialGroup() .addComponent(scrollPane,0, 0, Short.MAX_VALUE) ); group.setVerticalGroup(group.createSequentialGroup() .addComponent(scrollPane,0, 0, Short.MAX_VALUE) ); text.setText("TEST"); int a = 0; int max = 40; while(a!=max){ text.append("\nTEST"); a = a + 1; } testFrame.setSize(400, 400); testFrame.setVisible(true); new Thread(){ @Override public void run(){ try { Thread.sleep(1300); } catch (InterruptedException ex) {} text.append("\nTEST"); text.append("\nTEST"); scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); } }.start(); }
}
If you do it like that.
new Thread() {
@Override
public void run() {
try {
Thread.sleep(1300);
} catch (InterruptedException ex) {}
text.append("\nTEST");
text.append("\nTEST");
try {
Thread.sleep(200);
} catch (InterruptedException ex) {}
scrollPane.getVerticalScrollBar()
.setValue(scrollPane.getVerticalScrollBar().getMaximum());
}
}.start();
It's doing great, but it's 200 milliseconds to wait.
ScrollBar
It's bad.No.
text.setCaretPosition(text.getDocument().getLength());
I've gotugs working, even if I use objects, not just...JTextArea
♪
-
The reason for this is https://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D0%B5_%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8 between process adding data
JTextArea
(sighs)new Thread(){}
) andEventDispatchThread
- Swing/AWT working process.To solve the problem, all Swing components in EDT need to be carried out, for which methods are used http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingUtilities.html#invokeAndWait-java.lang.Runnable- and
SwingUtilities.invokeLater(Runnable doRun)
♪ Both methods add the code at the end of the EDT sequence. Since there is no need to wait for the operation to be completed, the last will be:new Thread(){ @Override public void run(){ try { Thread.sleep(1300); } catch (InterruptedException ex) {}
SwingUtilities.invokeLater( () -> { text.append("\nTEST"); text.append("\nTEST"); scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum()); }); }
}.start();
Race condition arises as Swing performs all UI renewal operations in EDT. When you change the text
JTextArea
the component decides that the dimensions need to be recalculated and redesigned, for which reasonJComponent.revalidate()
♪ Insiderevalidate()
It is verified that the current process is Event Dispatch Thread. Because it's not, the rewriting is in line with EDT events and the control is returning to your code. Your code further requests the maximum position for the lane of the cloth, and further depends on whether the size has been recalculated in EDT and whether your process will see a new size.There is no problem in the handling of Swing events (the knopok, etc.) as the processors are performed in EDT.
To avoid interface brakes, code transferred to
invokeLater
must be performed quickly, i.e.:// плохо
SwingUtilities.invokeLater( () -> {
text.append( getStringFromSlowNetwork() );
});// лучше так:
final String string = getStringFromSlowNetwork();
SwingUtilities.invokeLater( () -> {
text.append( string );
});
For long-term operations, class may be used http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html which provides a background template with the possibility of publishing intermediate results.
- Java Turtorials: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html