2012-04-30 2 views
0

Я создал JPanel, который содержит произвольное количество JLabels, выложенное с помощью менеджера макета потока с выравниванием по левому краю. Давайте назовем это FlowPanel.Работа с менеджерами компоновки Java

Каждый FlowPanel имеет глубину, и я хотел бы складывать произвольное количество этих FlowPanels друг над другом, каждый из которых имеет отступы с фиксированной глубиной *. В конечном счете, цель состоит в том, чтобы отображать эти панели в панели JScrollPane с вертикальной полосой прокрутки (если необходимо), но не с горизонтальной полосой прокрутки.

Я попытался уложить FlowPanels с GridBagLayout, и хотя было достаточно легко заставить их стекать вертикально и отступать так, как я хочу, я не могу понять, как правильно получить ширину. То есть FlowPanels просто запустили правую часть моей основной панели, не обращая внимания на отображаемую ширину.

Я пробовал использовать setPreferredSize, setSize, возиться с GridBagConstraints ... не повезло.

Пожалуйста, помогите! :)

несколько примеров кода, чтобы продемонстрировать проблему. Этот код имеет 2 проблемы: 1. Строки должны быть постоянной высоты, даже если всего несколько строк. 2. Строки прокручиваются с правой стороны экрана, когда FlowPanels содержат слишком много элементов.

public class FlowExample { 

public static void main(String[] args) throws Exception { 
    JFrame frame = new JFrame(); 

    StackPanel stackPanel = new StackPanel(); 
    frame.getContentPane().setLayout(new BorderLayout()); 
    frame.getContentPane().add(
      new JScrollPane(stackPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), 
      BorderLayout.CENTER); 

    frame.setLocation(200, 200); 
    frame.setSize(300, 300); 
    frame.setVisible(true); 

    List<FlowPanel> content = new ArrayList<FlowPanel>(); 
    for (int i = 0; i < 20; i++) { 
     FlowPanel flowPanel = new FlowPanel((int) (4 * Math.random())); 
     for (int j = 0; j < (int) (20 * Math.random()); j++) { 
      flowPanel.add(new JLabel("label " + j)); 
     } 
     content.add(flowPanel); 
     stackPanel.layoutGUI(content); 
     Thread.sleep(1000); 
    } 

    System.in.read(); 
    System.exit(0); 
} 
} 

class StackPanel extends JPanel { 

public StackPanel() { 
    setLayout(new BorderLayout()); 
} 

public void layoutGUI(final List<FlowPanel> content) { 
    if (!SwingUtilities.isEventDispatchThread()) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       layoutGUI(content); 
      } 
     }); 
     return; 
    } 

    JPanel mainPanel = new JPanel(); 
    mainPanel.setLayout(new GridLayout(content.size(), 1)); 
    for (FlowPanel flowPanel : content) { 
     flowPanel.setBorder(BorderFactory.createEmptyBorder(0, flowPanel.getDepth() * 10, 0, 0)); 
     mainPanel.add(flowPanel); 
    } 

    removeAll(); 
    add(mainPanel, BorderLayout.CENTER); 
    revalidate(); 
} 
} 

class FlowPanel extends JPanel { 

private int depth; 

public FlowPanel(int depth) { 
    setLayout(new FlowLayout(FlowLayout.LEFT)); 
    this.depth = depth; 
} 

public int getDepth() { 
    return depth; 
} 
} 

Вот пример кода с использованием GridBagLayout для прокладки основной панели. Это лучший результат я получил, но, как вы можете видеть, FlowPanels до сих пор не завернуть ...

JPanel mainPanel = new JPanel(); 
    mainPanel.setLayout(new GridBagLayout()); 
    GridBagConstraints constraints = new GridBagConstraints(); 
    constraints.weightx = 1; 
    constraints.gridwidth = GridBagConstraints.REMAINDER; 
    constraints.anchor = GridBagConstraints.LINE_START; 

    for (FlowPanel flowPanel : content) { 
     System.out.println("setting border to " + flowPanel.getDepth()); 
     flowPanel.setBorder(BorderFactory.createEmptyBorder(0, flowPanel.getDepth() * 10, 0, 0)); 
     mainPanel.add(flowPanel, constraints); 
    } 

    constraints.weighty = 1; 
    mainPanel.add(new JPanel(), constraints); 

    removeAll(); 
    add(mainPanel, BorderLayout.CENTER); 
    revalidate(); 
+1

вы пробовали просто складывая их (с помощью GridLayout было бы достаточно), но назначая левую единственную пустую границу для каждой панели? –

+0

Кажется, что не работает ... написание образца кода для демонстрации. –

+0

Какое поведение вы хотите, если FlowPanel шире, чем StackPanel? Должна ли она обернуться и увеличить ее глубину? Или вы хотите проверить, как вы добавляете JLabels, что вы не достигли максимума. ширина пока? –

ответ

1

GridLayout пытается уместить всё на экране для вас, поэтому, передавая ему список , он корректирует высоту каждый раз. Установив большую константу с самого начала, вы говорите ей, чтобы сделать достаточно места. Попробуйте изменить эту строку:

mainPanel.setLayout(new GridLayout(content.size(), 1)); 

в

mainPanel.setLayout(new GridLayout(500, 1)); 

Чтобы остановить скроллбар, возникающие с самого начала, альтернативой является использование BoxLayout вместо этого.

JPanel mainPanel = new JPanel(); 
Box box = Box.createVerticalBox(); 
mainPanel.add(box); 
for (FlowPanel flowPanel : content) { 
    flowPanel.setBorder(BorderFactory.createEmptyBorder(0, flowPanel.getDepth() * 10, 0, 0)); 
    box.add(flowPanel); 
} 
removeAll(); 
add(mainPanel, BorderLayout.CENTER); 
revalidate(); 

Проблема с упаковкой сводится к FlowLayout только с учетом setPreferredSize. Вы могли бы с существующим кодом установить один предпочтительный размер, чтобы соответствовать всем за счет требований к динамическому изменению размера. В качестве альтернативы, я использовал WrapLayout от Camickr в прошлом, и это хорошо работает.

http://tips4java.wordpress.com/2008/11/06/wrap-layout/

как есть, WrapLayout возвращает различные предпочтительные размеры в зависимости от того, был ли необходим обертка, лениво избежать с быстрым рубить, чтобы WrapLayout.java:

1). добавить минимальную ширину ширины

private int minWidth = -1; 

2).изменить метод «layoutSize» в последней строке:

if(minWidth != -1) { 
    dim.width = minWidth; 
} 
return dim; 

Как только это сделано, единственное изменение в вашем примере кода в конструкторе FlowPanel:

public FlowPanel(int depth) { 
    WrapLayout layout = new WrapLayout(FlowLayout.LEFT); 
    layout.setMinWidth(300); 
    setLayout(layout); 
    setSize(new Dimension(300, 30)); 
} 
+0

Спасибо за помощь! Отлично! :) –

+0

fyi, я в конечном итоге назвал int "preferredWidth" в WrapLayout, а затем использовал его в верхней части метода layoutSize, чтобы установить «targetSize» до того, как остальная часть метода вступит в силу. Кажется, это работает очень хорошо. –

+0

Согласен, это лучший подход. –

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