.setVisible (true) немедленная перерисовка

#java #swing #transparency #visibility #repaint

#java #качать #прозрачность #видимость #перерисовка

Вопрос:

В коротком методе я скрываю JFrame с помощью setVisible(false) . Затем я делаю снимок экрана и восстанавливаю JFrame с помощью setVisible(true) .

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

Проблема в том, что после вызова setVisible(true) окно отображается со старым содержимым за долю секунды до вызова paintComponent и отображения обновленного состояния.

Вероятно, я мог бы обойти это некрасивым способом, но я хотел знать, есть ли лучшие решения.

Заранее спасибо за любую помощь

редактировать: при подготовке примера я заметил, что эффект почти никогда не наблюдался, если не использовать прозрачность, как я делаю в своей программе. Вероятно, следовало бы упомянуть об этом. Вот что я придумал:

 import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JPanel;

import com.sun.awt.AWTUtilities;
public class Test {

    static boolean flag = false;
    static Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();

    public static void main(String[] args) throws InterruptedException {
        JFrame frame = new JFrame();
        frame.setUndecorated(true);
        AWTUtilities.setWindowOpaque(frame, false);  //draw on a transparent window
        frame.setSize(scrSize.width, scrSize.height);
        frame.setContentPane(new JPanel() {
            protected void paintComponent(Graphics g) 
            {
                if (Test.flag) {
                    g.setColor(Color.RED);
                    g.drawRect(50, 50, scrSize.width - 100, scrSize.height - 100);
                }
                else {
                    g.setColor(Color.GREEN);
                    g.fillOval(50, 50, scrSize.width - 100, scrSize.height - 100);
                }
            }
        });
        frame.setVisible(true); //green oval shown
        Thread.sleep(1000);
        frame.setVisible(false);
        flag = true; // next draw produces red rectangle
        Thread.sleep(1000);
        frame.setVisible(true); // before the next draw, 
                                // you can see a flash of the green oval
    }

}
  

Комментарии:

1. Установите изображение до того, как рамка снова станет видимой. Убедитесь, что код выполняется в потоке отправки событий. Опубликуйте свой SSCCE , если вам нужна дополнительная помощь.

2. Используется EventQueue.invokeLater() для упорядочивания изменений.

3. не удается воспроизвести, время для sscce, как уже предлагал @camickr

Ответ №1:

Это связано с тем, что каждое окно AWT имеет изображение вне экрана, которое синхронизируется с изображением на экране. Когда отображается окно, его содержимое отображается непосредственно из закадрового изображения. Это происходит в потоке инструментария, а не в потоке отправки событий.

Только после отображения окна рамка перерисовывается в потоке отправки событий.

До Java 1.6 в AWT не было двойной буферизации для каждого окна, поэтому вы бы увидели серый фон, который был печально известной проблемой «серого прямоугольника».

Единственный обходной путь, о котором я знаю, — это каждый раз создавать новый фрейм. Вы можете повторно использовать панель содержимого старого фрейма, так что накладные расходы будут не такими высокими.

Комментарии:

1. звучит как-то разумно — просто: я вообще не могу воспроизвести проблему. Поэтому, прежде чем переходить к вновь созданному фрейму, я бы посоветовал выяснить истинную причину 🙂

2. Это происходит только для сложных фреймов и только в том случае, если вы что-то меняете в фрейме, пока он невидим. Причина объясняется в моем ответе. AFAIK, вы ничего не можете с этим поделать, кроме создания нового фрейма.

3. как я уже сказал: рассуждения звучат хорошо, и я, конечно, изменяю содержимое перед повторным показом (как еще я мог попытаться воспроизвести <g> ). Таким образом, разница может быть сложной частью, насколько сложной это будет?

4. Рамка отображается и отображается из закадрового изображения, и только после этого корневая панель проверяется и перерисовывается. В зависимости от того, как это регистрируется, вы все равно некоторое время видите старое содержимое.

5. да, я понимаю рассуждения … все еще не убежден, пока не увижу это (упрямый я:) в конце концов попробую на моем нетбуке. Спасибо

Ответ №2:

Я понимаю, что этот ответ предлагается через год после того, как был задан вопрос, но у меня была похожая проблема, и, конечно, я немного исследовал, прежде чем попытался ее решить. Для всех, кто сталкивается с этим вопросом, попробуйте удалить свое окно / фрейм перед упаковкой и сделать его видимым.

Комментарии:

1. ЭТО должно быть принятым ответом. Создание нового фрейма для каждого отображения диалогового окна недопустимо.

2. Вы уверены, что удаление окна можно сделать? Я думал, что читал в документах Oracle, что это освобождает собственные ресурсы и должно выполняться только после завершения работы с фреймом / окном.