Компонентът на Swing трепти, когато се актуализира много

Имам няколко хиляди реда код някъде и забелязах, че моят JTextPane трепти, когато го актуализирам твърде много.. Написах опростена версия тук:

import java.awt.*;
import javax.swing.*;

public class Test
{
    static JFrame f;
    static JTextPane a;
    static final String NL = "\n";

    public static void main(String... args)
    {
        EventQueue.invokeLater(new Runnable(){
        public void run()
        {
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        f.setSize(400, 300);
        f.setLocationRelativeTo(null);

        a = new JTextPane();
        f.add(new JScrollPane(a));

        new Thread(new Runnable(){
            public void run()
            {
                int i = 0;
                StringBuffer b = new StringBuffer();
                while(true)
                {
                    b.append(++i+NL);
                    a.setText(b.toString());
                    a.setCaretPosition(b.length());
                    try{Thread.sleep(10);}catch(Exception e){}
                }
            }
        }).start();
        }
        });

    }
}

Това е за GUI компонент в стил терминал (cmd)--

Мисля, че направих всички оптимизации, които можех тук, включително \n като крайна променлива, така че да не се конструира стотици пъти. Все пак трептенето е забележимо и неприемливо. След няколко минути компонентът замръзва напълно. Трябва да актуализирам компонента много бързо и панелът трябва да се превърти до дъното, когато се актуализира.

Мислех да направя своя собствена версия на JTextPane от нулата, но бих искал да видя дали вие имате по-лесно решение.


person Bai Li    schedule 21.03.2009    source източник
comment
Защо любопитното наблягане върху думата експерти? Мислехте ли, че ще получите по-добър отговор, като ни обидите?   -  person Paul Tomblin    schedule 22.03.2009
comment
Съжалявам, без да се обиждам. Редактирано.   -  person Bai Li    schedule 22.03.2009


Отговори (2)


Част от вашата грешка е, че имате достъп до Swing компонент извън нишката на събитието! Да, setText( ) е безопасен за нишки, но методите на Swing не са безопасни за нишки, освен ако не са изрично декларирани като такива. Така, setCaretPosition() не е Thread-safe и трябва да бъде достъпен от нишката на събитието. Почти сигурно това е причината, поради която вашето приложение в крайна сметка замръзва.

ЗАБЕЛЕЖКА: JTextPane наследява своя setText() метод от JEditorPane и своя setCaretPosition метод от JTextComponent, което обяснява връзките в предишния параграф, които не водят до JTextPane JavaDoc страница.

За да бъдете Thread-safe, наистина трябва поне да извикате setCaretPosition() от нишката на събитието, което можете да направите с код като този:

SwingUtilities.invokeAndWait(new Runnable() {
  public void run() {
    a.setText(b.toString());
    a.setCaretPosition(b.length());
  }
}

И тъй като трябва да извикате setCaretPosition() от нишката на събитието, можете също да извикате setText() от същото място.

Възможно е да не се наложи ръчно да задавате позицията на каретката. Разгледайте раздела „Caret Changes“ в JavaDoc за JTextComponent.

И накрая, може да искате да разгледате поредица от две статии:

person Eddie    schedule 22.03.2009
comment
Не мога наистина да сложа всичко това в EDT, защото sleep() ще го задръсти толкова много, че компонентът ще замръзне напълно. - person Bai Li; 22.03.2009
comment
Не сънят! Но setCaretPosition трябва да е в EDT. В противен случай ще изпитате случайни (или не толкова случайни) прекъсвания. - person Eddie; 23.03.2009
comment
A v. добър отговор; просто има нужда от ); добавяне в края на кода. - person Steve Smith; 08.11.2017

Не съм сигурен дали това ще работи, но можете да опитате да използвате метода insertString() на екземпляра Document на текстовия панел. Бих се опитал да има един интервал в края на документа и да запазя каретката позиционирана след това пространство; но когато вмъквате низ, вмъкнете го преди интервала. По този начин позицията на каретката автоматично ще остане в края на документа.

Мисля, че текстовият панел може да се преначертава два пъти, веднъж, когато извикате setText() и веднъж, когато извикате setCaretPosition(), и това може да допринася за трептенето. Не съм сигурен обаче (мина известно време, откакто работих със Swing).

person David Z    schedule 21.03.2009