JScrollBars setValue not lowered



  • Used JScrollPane♪ It is. JTextArea♪ I want to do it. JTextArea.setText() and lower vertical ScrollBar 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(){}) and EventDispatchThread - 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 JTextAreathe component decides that the dimensions need to be recalculated and redesigned, for which reason JComponent.revalidate()♪ Inside revalidate() 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



Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2