Как исправить пробел в GridBagLayout

Я использую GridBagLayout для создания JPanel под названием «Preset», который несколько раз реплицируется в JFrame. Каждый пресет будет иметь несколько строк (JPanels). Моя цель состоит в том, чтобы отображалась только одна строка (первая), но при нажатии кнопки редактирования все они будут отображаться. Прямо сейчас кнопка редактирования работает, но между строками большой пробел. Я хочу, чтобы при сворачивании дополнительных строк каждый пресет находился прямо друг над другом (без пробела). На следующем рисунке вы можете увидеть, о чем я говорю.

Вот как это выглядит: введите здесь описание изображения

Вот как я хочу, чтобы это выглядело: введите здесь описание изображения

Я совершенно уверен, что мне нужно что-то сделать с GridBag, но я не знаю, что. Я прочитал несколько руководств и написал это так, как я думал, но не повезло.


package SSCCE;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

public class UI extends JFrame{
    private final static int HEIGHT = 600;
    private final static int WIDTH = 730;
    private JPanel pane; //Pane that stores accounts
    private JScrollPane scroller;
    private Preset[] branches;    

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

    public UI(){
        //Make the UI close when the exit button is clicked
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    

        //Sets the size of the UI
        this.setSize(WIDTH, HEIGHT);

        //Set the layout and add components to it
        this.setLayout(new BorderLayout());

        //Reads in the settings and sets up the branches
        populateBranches();

        pane = new JPanel();
        pane.setLayout(new GridLayout(branches.length,1));
        for (int i = 0; i < branches.length; i++){
            pane.add(branches[i]);
        }

        //Create the center pane of the BorderLayout
        scroller = new JScrollPane(pane);
        scroller.createVerticalScrollBar();
        this.add(scroller,BorderLayout.CENTER);

        //Makes the UI visible
        this.setVisible(true);
    }

    private void populateBranches(){
        //Populates the branches array based on what is read in, or not read in from the file
        branches = new Preset[15];

    for (int i = 0; i < branches.length; i++){
        branches[i] = new Preset();
        branches[i].setEnabled(false);
    }
}

public class Preset extends JPanel{
    private JTextField eName;
    private JButton edit;
    private JButton activate;
    private JComboBox printer;
    private JPanel line1;
    private JPanel line2;
    private String branchName;
    private String ipAddress;
    private boolean enableAll;

    public Preset(){
        eName = new JTextField(20);
        edit = new JButton("Edit");
        activate = new JButton("Activate");

        JPanel nameContainer = new JPanel();
        nameContainer.setLayout(new FlowLayout());
        nameContainer.add(eName);

        printer = new JComboBox();

        //
        line1 = new JPanel();
        line1.setLayout(new FlowLayout());
        line1.add(nameContainer);
        line1.add(edit);
        line1.add(activate);

        //
        line2 = new JPanel();
        line2.setLayout(new BorderLayout());
        line2.add(printer, BorderLayout.WEST);

        GridBagLayout grid = new GridBagLayout();
        GridBagConstraints cons = new GridBagConstraints();
        cons.fill = GridBagConstraints.BOTH;
        this.setLayout(grid);

        cons.ipady = 100;
        cons.ipadx = 100;
        cons.weighty = 0D;
        cons.gridx = 0;
        cons.gridy = 0;
        cons.gridwidth = 2;
        cons.gridheight = 1;
        grid.setConstraints(line1, cons);
        this.add(line1);

        cons.ipady = 100;
        cons.ipadx = 100;
        cons.weighty = 0D;
        cons.gridx = 0;
        cons.gridy = 1;
        cons.gridwidth = 2;
        cons.gridheight = 1;
        grid.setConstraints(line2, cons);
        this.add(line2);

        //Enable all components
        enableAll = true;
    }
}
}

person Kryptos    schedule 31.07.2013    source источник
comment
Можете ли вы смоделировать изображение, демонстрирующее то, что вы хотели бы видеть? Я не понимаю из вашего описания, что вы пытаетесь сделать.   -  person tuckermi    schedule 31.07.2013
comment
Только что обновил пост, надеюсь поможет.   -  person Kryptos    schedule 31.07.2013
comment
Я обновил код для SSCCE   -  person Kryptos    schedule 31.07.2013
comment
Поместите панель GridBagLayout внутрь другой панели JPanel с помощью FlowLayout.   -  person Gilbert Le Blanc    schedule 31.07.2013
comment
Если один из ответов является полным ответом, отметьте его как «ответ» на ваш вопрос. это часть того, как работает SO.   -  person arcy    schedule 04.08.2013
comment
Я знаю, как это работает. Есть причина, по которой я не отметил один как «ответ».   -  person Kryptos    schedule 05.08.2013


Ответы (4)


Удалите все операторы, которые назначают отступы по оси Y для GridBagConstraints из Preset JPanel, т.е.

cons.ipady = 100;
person Reimeus    schedule 31.07.2013
comment
Это действительно помогло. но не решил ее на 100%. Когда я расширяю кнопку редактирования, между каждым пресетом создается пространство. Вот картина того, что происходит. i.imgur.com/f2KUhId.png - person Kryptos; 31.07.2013
comment
Этого не происходит в вашем коде SSCCE. Очевидно, есть некоторая разница в том, как устроено реальное приложение. Попробуйте переделать реальный макет приложения на основе SSCCE - person Reimeus; 31.07.2013
comment
Правильно, отличий много. В реальном приложении кнопка редактирования отображает строку 2, в противном случае она скрыта. - person Kryptos; 31.07.2013
comment
Обновите свой SSCCE, чтобы он более точно (или даже точно) отражал реальное приложение, иначе люди просто прибегают к догадкам :) - person Reimeus; 31.07.2013

Я не считаю это «настоящим» ответом на ваш вопрос, но вам следует подумать: избавиться от gridbag. Я не вижу ничего в вашем желаемом макете, который требует этого. Создайте каждую панель с двумя подпанелями; вторая подпанель содержит то, что вы хотите сделать невидимым по умолчанию и отобразить позже, и используйте для этого setVisible().

Я никогда не чувствовал себя комфортно со всеми ограничениями GridBagConstraints, которые, похоже, взаимодействуют способами, для которых у меня нет четкой модели. По этой причине я избегаю GridBagLayout, поэтому я не могу сделать это с помощью GridBagLayout. Но я не понимаю, почему вы не можете сделать это с более простыми (и менее многословными) существующими контейнерами Swing и менеджерами компоновки.

person arcy    schedule 31.07.2013
comment
Я пробовал это. Я использую setVisible() для изменения видимости строки 2. Проблема с Swing заключается в том, что он работает, но в нем есть пустое место, где строка 2 (есть/должна быть). Я не хочу, чтобы были какие-то пустые места... где угодно. - person Kryptos; 31.07.2013

Это реальный ответ на фоновый вопрос (как получить желаемый эффект):

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

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class LinesOneAndTwo implements ActionListener
{
  private static final long serialVersionUID = 1L;
  JFrame mainWindow = new JFrame("LinesOneandTwo");

  JButton showButton = null;
  JButton hideButton = null;
  JPanel firstb = new JPanel();

  public static void main(String[] args)
  {
    LinesOneAndTwo main = new LinesOneAndTwo();
    main.go();
  }

  private void go()
  {
    mainWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    Container contentPane = mainWindow.getContentPane();
    contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
    JPanel first = new JPanel();
    JPanel firsta = new JPanel();

    JPanel second = new JPanel();
    JPanel seconda = new JPanel();
    JPanel secondb = new JPanel();

    first.setLayout(new BoxLayout(first, BoxLayout.Y_AXIS));
    firsta.setLayout(new BoxLayout(firsta, BoxLayout.X_AXIS));
    showButton = new JButton("show");
    hideButton = new JButton("hide");
    firsta.add(showButton);
    firsta.add(hideButton);
    firstb.setLayout(new BoxLayout(firstb, BoxLayout.X_AXIS));
    firstb.add(new JButton("one"));
    firstb.add(new JButton("two"));
    first.add(firsta);
    first.add(firstb);

    second.setLayout(new BoxLayout(second, BoxLayout.Y_AXIS));
    seconda.setLayout(new BoxLayout(seconda, BoxLayout.X_AXIS));
    secondb.setLayout(new BoxLayout(secondb, BoxLayout.X_AXIS));
    seconda.add(new JButton("hiya"));
    seconda.add(new JButton("there"));
    secondb.add(new JButton("not here"));
    second.add(seconda);
    second.add(secondb);
    secondb.setVisible(false);

    firstb.setVisible(false);
    showButton.addActionListener(this);
    hideButton.addActionListener(this);
    mainWindow.add(first);
    mainWindow.add(second);
    mainWindow.pack();
    mainWindow.setVisible(true);

  }

  public void actionPerformed(ActionEvent event)
  {
    if (event.getSource() == showButton)
    {
      firstb.setVisible(true);
      mainWindow.pack();
    }
    else if (event.getSource() == hideButton)
    {
      firstb.setVisible(false);
      mainWindow.pack();
    }
  }
}

Конечно, я не знаю, чем отличаются внутренние части ваших панелей или чем они отличаются в остальном, но кнопки «показать» и «скрыть» вызывают появление и исчезновение вторичной панели в верхней панели фрейма, оставляя нет пробелов.

Мне все еще не нравится GridBagLayout.

person arcy    schedule 31.07.2013

У меня возникла та же проблема, и я нашел решение на 70%. Если вы используете rowWeights и устанавливаете его равным 0 для всех компонентов, кроме последнего (с rowWeights 1.0), почти все пробелы исчезают. Если ваш содержащий компонент больше, чем все остальные компоненты, остается только зазор перед последним компонентом.

GridBagLayout gbl_panelFoo = new GridBagLayout();
gbl_panelFoo.rowWeights = new double[] {0.0, 0.0, 0.0, ... 0.0, 1.0};

Может это немного поможет

person Simeon    schedule 02.10.2013
comment
Исправлены остальные 30% Если вы установите привязку компонента последних строк на север, единственный оставшийся зазор будет между вашей последней строкой и нижней частью контейнера;) Нашел его здесь, stackoverflow.com/questions/13285619/ спасибо, Гийом Полет - person Simeon; 02.10.2013