Swing: изменение метки на скрытой рамке, а затем отображение рамки происходит в обратном порядке на EDT - PullRequest
0 голосов
/ 13 октября 2009

Проблема

Я создаю диалоговое окно на качелях (JRE 6, обновление 10, Ubuntu linux). Когда пользователь закончил использовать диалоговое окно, оно скрыто. Когда пользователи нажимают кнопку в другом кадре, метка на блоке изменяется в соответствии с кнопкой, а затем блок снова отображается.

Проблема, с которой я столкнулся, заключается в том, что поле отображается до того, как метка меняется, хотя программно я звоню в обратном порядке. Это приводит к тому, что появляется окно, за которым следует изменение метки, которое выглядит «глючно» на нашем медленном целевом HW. Похоже, что EDT планирует кадр setVisible (true) перед меткой setText (....) ; это дает приоритет этому вызову. Есть ли способ заставить EDT запланировать выполнение setVisible (true) после setText (....) ?

Обратите внимание, что код вызывается нажатием кнопки, которая уже выполняется в EDT, поэтому нельзя использовать SwingUtilities.invokeAndWait . Я пытался использовать метод invokeLater , но EDT все еще перепланирует его.

Воспроизвести

Запустите следующий код в среде IDE в режиме отладки и вставьте код действия showButton после отображения и скрытия фрейма «диалога». Изменение метки setText (....) не окажет немедленного влияния на GUI, но будет setVisible (true) фрейма. Затем пройдитесь по EDT, и вы увидите, что setText в конечном итоге происходит дальше по расписанию EDT.

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;

public class DemonstrateFramePaintEDTPriority {

static class MyFrame extends JFrame {

    private JFrame frame;
    private JLabel label;
    int i = 0;

    public MyFrame() {
        // Some label strings
        final String string[] = new String[] { "label text one",
                "label 2222222", "3 3 3 3 3 3 3" };

        // Create GUI components.
        frame = new JFrame("Dialog");
        label = new JLabel("no text set on this label yet");
        frame.setSize(500, 200);
        frame.setLayout(new FlowLayout());
        frame.add(label);

        // Add show and hide buttons.
        JButton showButton = new JButton("show dialog");
        showButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // Set the label text - THIS HAPPENS AFTER frame.setVisible
                label.setText(string[i]);

                // Select new label text for next time.
                i++;
                if (i >= string.length) {
                    i = 0;
                }

                // Show dialog - THIS HAPPENS BEFORE label.setText
                frame.setVisible(true);
            }

        });

        JButton hideButton = new JButton("hide dialog");
        hideButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                label.setText("label removed");
                frame.setVisible(false);
            }

        });
        setSize(500, 200);
        setLayout(new FlowLayout());
        add(showButton);
        add(hideButton);
    }
}

public static void main(String[] args) {
    JFrame frame = new MyFrame();
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
}
}

Ответы [ 3 ]

1 голос
/ 31 декабря 2009

Не думаю, что это проблема рисования Linux. Я могу воспроизвести вашу проблему на Windows 7 64-битной (JDK 1.6.0_18 (ранний доступ)). Вы очень близки к ответу - вы знаете о SwingUtilities.invokeLater, но вы не думаете об использовании его там, где это необходимо.

Скажи это со мной:

Вы должны инициализировать и изменить компоненты Swing на EDT

Если вы этого не сделаете, произойдут плохие вещи. В этом случае ваше странное поведение перерисовки является результатом отсутствия создания JFrame и содержащихся в нем компонентов на EDT. Если вы поместите эту строку в SwingUtilities.invokeLater, это исправит вашу проблему:

JFrame frame = new MyFrame();

Вы правы - ваш setText происходит в EDT, но инициализация самого компонента не произошла в EDT, и это является основной причиной.

Если вы сомневаетесь в том, что данный код происходит в EDT, вы можете использовать SwingUtilities.isEventDispatchThread (), чтобы узнать.

Я настоятельно рекомендую прочитать Filthy Rich Clients , если вы планируете много заниматься Swing. Я сейчас читаю его.

0 голосов
/ 30 декабря 2009

Я только что столкнулся с подобной проблемой на OS X. Мое решение было:

frame.invalidate()
frame.pack()
frame.setVisible(true)

Похоже, что заставляет Swing перерисовывать кадр в памяти перед его отображением.

0 голосов
/ 13 октября 2009

Проблема не в том, что текст компонента метки не изменился. Это то, что перекрас был запланирован, но еще не произошло. Это и Linux имеет тенденцию быть чрезвычайно медленным, чтобы открывать окна (проблема с оконным менеджером или подобным?) java.awt.EventQueue работает по приоритетам, хотя я не могу вспомнить детали.

JComponent.paintImmediately выглядит как вероятный метод. Возможно, вы захотите найти (хороший) текст по анимации в Swing / AWT. (Это или запустить без оконного менеджера.)

...