2014-02-09 3 views
0

Я пытаюсь с макетами Swing оставлять пробел над элементами управления, которые вычисляются из текущего размера окна. Это в основном работает, за исключением того, что элемент управления перемещается только тогда, когда окно изменяется горизонтально - если я изменяю размер по вертикали, он остается там, где он есть, - затем изменяя размер 1 пиксель по горизонтали, он защелкивается в нужное место. Может ли кто-нибудь объяснить, почему изменение размера игнорируется, когда я только изменяю размер по вертикали?Swing layout игнорирует горизонтальное изменение размера

Я доказал, что элемент componentResized() по-прежнему вызывается с вертикальными размерами и что contentPane.getWidth() и contentPane.getHeight() все равно дают правильные значения. Таким образом, размер измерения задается правильно, просто игнорируется. Мне нравится, что мне нужно вызвать вызов contentPane.payAttentionToUpdatesSizesOfYourComponents(), но я не могу найти какой-либо метод, который сделает это. contentPane.invalidate() не влияет.

Также заметил, что если я удаляю BorderLayout и устанавливаю BoxLayout непосредственно в contentPane, то он работает так, как я хочу. Однако, хотя это хорошо для этого крошечного примера, у реального окна, в котором я столкнулся с этой проблемой, есть некоторые компоненты в JPanel, установленном в NORTH с вышеперечисленным промежутком, некоторые компоненты в другом JPanel, установленном на SOUTH, с пробелом ниже, а BorderLayout был единственным Я мог бы заставить их правильно позиционировать, поэтому я не могу это исключить.

Любые советы или предложения приветствуются!

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 

import javax.swing.Box.Filler; 
import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.WindowConstants; 

public final class ResizeOnlyWorksHorizontally 
{ 
    public static final void main (final String [] args) 
    { 
     final JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE); 

     final JPanel contentPane = new JPanel(); 
     frame.setContentPane (contentPane); 

     contentPane.setLayout (new BorderLayout()); 

     final JPanel top = new JPanel(); 
     top.setLayout (new BoxLayout (top, BoxLayout.Y_AXIS)); 
     contentPane.add (top, BorderLayout.NORTH); 

     // Put a space, then a label below it 
     final Dimension startSpace = new Dimension (0, 0); 
     final Filler filler = new Filler (startSpace, startSpace, startSpace); 
     top.add (filler); 

     top.add (new JLabel ("Text")); 

     contentPane.addComponentListener (new ComponentAdapter() 
     { 
      @Override 
      public final void componentResized (final ComponentEvent e) 
      { 
       // Just any calc based on contentPane width and height to demo problem 
       final int calc = (contentPane.getWidth() + contentPane.getHeight())/2; 

       // Alter the size of the space above the label 
       final Dimension newSpace = new Dimension (0, calc); 
       filler.setMinimumSize (newSpace); 
       filler.setPreferredSize (newSpace); 
       filler.setMaximumSize (newSpace); 
      } 
     }); 

     frame.pack(); 
     frame.setVisible (true); 
    } 
} 

ответ

1

Чтобы ответить на ваш вопрос, вам необходимо следующее после размеры изменяются, чтобы убедиться, что менеджер компоновки вызывается:

filler.revalidate(); 

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

Например, если вам нужен сменный зазор в рамке, то вы, вероятно, должны использовать BoxLayout, и вы можете добавить «клей» в начало и конец. Или, может быть, вы можете использовать GridBagLayout, потому что вы можете контролировать изменение размеров компонентов на основе доступного пространства.

Для получения дополнительной информации прочитайте учебник Swing по телефону Layout Managers.

+0

Большое спасибо за быстрый ответ - filler.revalidate() работает, я думаю, что мне не хватало в том, что в то время как я был изменения ограничений Наполнителя, мне нужно было «ткнуть», чтобы заставить изменение размера вступить в силу, а не его контейнер. – nigelg

0

Это не позволило мне поставить достаточно длинный комментарий под ваш ответ camickr :(Я хотел добавить, что после публикации этого я также нашел это, аналогичную, но не идентичную проблему с изменением размера BorderLayouts, и они описывают аналогичную ситуацию Элементы управления NORTH/SOUTH не обращают внимания на вертикальный размер - Java Swing BorderLayout resize difficulties

Я попытался на основе ответов на это, чтобы использовать GridBagLayout, и сделал это для работы после небольшого усилия. В основном его сетка 1x5 с ячейками, содержащими (пространство I насильственно изменяет размер, контролирует, клей, больше элементов управления, пространство, которое я насильно изменяю), и это сработало.

Вы не должны вручную рассчитывать размеры таких компонентов.

Единственное, что я вручную устанавливая размер является разрыв выше + ниже контрольной, все сами элементы управления я позволяю менеджеру сделки макета с.Размер этих пробелов должен соответствовать фоновому изображению на кадре, размер которого равен кадру, но сохраняющему соотношение сторон, поэтому ширина этой границы не является чем-то, что может определить менеджер макета, реальный код для «calc», бит в моем SSCCE выше:

final int edge = Math.min (contentPane.getWidth()/4, contentPane.getHeight()/3); 
final int imgHeight = edge * 3; 
final int borderSize = (contentPane.getHeight() - imgHeight)/2; 

Таким образом, если пользователь изменяет размер окна, чтобы быть широким, есть черные границы левый + правый изображения и borderSize = 0. Если пользователь изменяет размер окна, чтобы быть высоким, есть черные границы выше + под изображением, и я хочу, чтобы элементы управления не попадали туда, поэтому они всегда сидят в фоновом изображении.

Но большое спасибо за толчок в правильном направлении :)

Смежные вопросы