Принудительное немедленное размещение и рисование в Swing

Кажется, я не могу заставить макет в Swing. У меня есть JComponent, добавленный к JLayeredPane, и я установил границу на JComponent. Затем я хочу сразу все перерисовать — не в смысле «пожалуйста, сделайте это как можно скорее», как invalidate(), а синхронно и немедленно. Любая помощь? Кажется, я не могу найти правильный способ сделать это, и все, что я читал о invalidate(), validate(), repaint(), doLayout(), etc, только еще больше сбивает меня с толку!


person Hamy    schedule 21.01.2011    source источник


Ответы (3)


Согласно этому (см. раздел "Синхронное рисование") метод paintImmediately() должен работать.

person Jonathan    schedule 21.01.2011
comment
Я пробовал это - myComponent.paintImmediately(myComponent.getBounds). Не повезло :( Я думаю, это может быть связано с тем, что для изменения границы требуется новый проход макета из-за того, что граница использует несколько дополнительных пикселей с каждой стороны объекта. - person Hamy; 21.01.2011
comment
PaintImmediately может быть подходящим способом, но вам все равно нужно опубликовать его как событие, используя invokeLater или invokeAndWait, я думаю. - person phooji; 21.01.2011
comment
@Hamy Вы пытались вызвать его в родительском компоненте, что может позволить изменить макет. - person Jonathan; 21.01.2011

Самый надежный способ заставить Swing обновить отображение — использовать SwingUtilities.invokeLater. В вашем случае это будет выглядеть примерно так

SwingUtilities.invokeLater(new Runnable {
                             public void run() { 
                                somecomponent.repaint();
                             }
                           });

Я понимаю, что «invokelater» не совсем звучит так, как будто он делает что-то немедленно, но на практике события, опубликованные таким образом, имеют тенденцию выполняться довольно быстро по сравнению с простым вызовом, например. somecomponent.repaint() напрямую. Если вам абсолютно необходимо, чтобы ваш управляющий код ждал обновления графического интерфейса, то есть также invokeAndWait, но, по моему опыту, в этом редко возникает необходимость.

См. также: документ об отправке событий в Swing. .

person phooji    schedule 21.01.2011
comment
К сожалению, ни один из них не будет работать для моего внедрения: / Мне нужно, чтобы обновление графического интерфейса происходило немедленно, а не после обработки ожидающих событий. Мне это нужно из-за недостатка в моем дизайне, но, к сожалению, его изменение отбросит меня назад почти на две недели, и завтра у меня есть результат :/ - person Hamy; 21.01.2011
comment
Хорошо, попробуйте это: используйте invokeAndWait, затем внутри исполняемого вызова paintImmediately во внешнем контейнере. Я думаю, что это максимально близко к тому, что вы можете получить с помощью Swing - он переопределит предыдущие вызовы «перерисовки», если я не ошибаюсь. - person phooji; 21.01.2011
comment
К сожалению, это тоже не сработало. Чтобы вызвать invokeAndWait, вы должны создать новый поток. У меня есть очень медленное событие, происходящее сразу после этой отрисовки, и оно начинает выполнение до того, как запустится runnable, что приводит к зависанию графического интерфейса без выполнения этого вызова отрисовки. - person Hamy; 21.01.2011
comment
Вызов invokeAndWait не порождает новый поток — он просто добавляет ваш Runnable в очередь событий, а затем блокирует ваш текущий поток до тех пор, пока не будет вызвано событие. Если вы все еще не видите «изменения» при использовании invokeAndWait, то, скорее всего, вы перерисовываете не тот объект. Один из способов проверить — добавить вывод отладки в метод (g)paint вашего компонента. - person phooji; 22.01.2011

Это очень старое, но я нашел простое решение, которое я покажу с помощью JPasswordField:

var pw = new JPasswordField();
...
pw.paint(pw.getGraphics()); // paints immediately
person looncraz    schedule 26.10.2019