Несколько пользовательских JPanels внутри JScrollPane - изменение размера / показ компонентов на одном изменяет размер их всех - PullRequest
0 голосов
/ 15 октября 2018

Итак, у меня есть пользовательский JPanel, который я использую несколько раз для заполнения панели-оболочки внутри JScrollPane.Количество пользовательских элементов JPanel, которые я использую, зависит от размера списка.Проблема, с которой я сталкиваюсь, состоит в том, что часть моего Custom JPanel имеет еще одну невидимую JPanel, которая расширяется, когда я нажимаю на ее родителя.Поведение, которое я пытаюсь имитировать, это поведение аккордеонного элемента пользовательского интерфейса.До того, как я участвовал в этом проекте, я был в первую очередь webdev, и хотя я много работал с Java, я все еще относительно новичок в Swing.

Вот пример поведения - панель прокрутки со всеми элементамизакрыто.(прости меня за быстрые комментарии по окраске. Я попытался подчеркнуть то, что вижу неправильно).

https://i.stack.imgur.com/Wk90N.png

Далее приведено изображениеПервый элемент расширен - что неожиданно расширяет все остальные элементы.

https://i.stack.imgur.com/e9n3t.png

Следует отметить, что я нацеливаюсь только на первую панель и настраиваю видимость, но при этом длина всех остальных повторяющихся панелей увеличивается, но, очевидно, компоненты внутри остаются невидимыми.

Наконец, вот мой последний желаемый результат:

https://i.stack.imgur.com/GvSjn.png

Есть ли какой-тоограничение в JScrollPane, которое изменяет размеры дочерних компонентов JPanel, чтобы всегда сохранять одинаковую высоту?Кажется, я не могу найти способ обойти это, и я играл со всевозможными обертками и макетами, но все безрезультатно.

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

Спасибо, Марек

PS: да, я обязательно должен использовать Swing.

РедактироватьВот статичная, быстрая и грязная, урезанная реализация моего кода, предложенная Родди из «Замороженного горошка»

ExampleScrollPane:

public class ExampleSrollPane extends JPanel {
private static ExampleSrollPane instance = null;
private JScrollPane contentScrollPanel = new JScrollPane();
private Vector<ExamplePanel> exPanels;
private JPanel wrapPanel = new JPanel();

public ExampleSrollPane() {
    super();
    this.setLayout(new BorderLayout());
    this.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.white,
            Color.white, new Color(115, 114, 105), new Color(165, 163, 151)));

    exPanels = new Vector<ExamplePanel>();
    init();
}

private void init() {

    contentScrollPanel.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    contentScrollPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
    contentScrollPanel.setBorder(new CompoundBorder(new EmptyBorder(5, 5, 5, 5), new SoftBevelBorder(BevelBorder.LOWERED)));
    this.add(contentScrollPanel, BorderLayout.CENTER);

    initPanels();
}

public void initPanels() {
    int numUnits = 15;
    // Init one empty panel at least
    if (numUnits == 0) numUnits = 15;
    wrapPanel.setLayout(new GridLayout(numUnits, 1));

    for (int i = 0; i < numUnits; i++) {
        ExamplePanel exPan = new ExamplePanel(i);
        exPanels.add(i, exPan);
        wrapPanel.add(exPan);
    }
    contentScrollPanel.setPreferredSize(new Dimension(575, 100));
    contentScrollPanel.getViewport().add(wrapPanel);
}
/**
 * Method: viewPanel()
 *
 */
private static void viewPanel() {
    JFrame frame = new JFrame();
    frame.setLayout(new BorderLayout());
    frame.setLocationRelativeTo(null);
    frame.add(getInstance());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setSize(new Dimension(600, 350));
    frame.setAlwaysOnTop(true);
    frame.setVisible(true);
}

public static ExampleSrollPane getInstance() {
    if (instance == null) {
        instance = new ExampleSrollPane();
    }
    return instance;
}
/**
 * The main method.
 * 
 * @param args the arguments
 */
public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            viewPanel();
        }
    });
}

}

Это здесьв методе showHideTable, который создает проблему.

ExamplePanel (мой пользовательский JPanel):

public class ExamplePanel extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;

private static final Border STAT_BORDER = BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.white,
        Color.white, new Color(115, 114, 105), new Color(165, 163, 151));

public static final EmptyBorder PAD_BORDER = new EmptyBorder(10, 10, 10, 10);

public int indx;
private JLabel unitLabel;
private JLabel statLabel;
private JLabel invLabel;
private JLabel targetLabel;
private JLabel timeLabel;

// Custom BasicArrowButton to expand/hide the "table"
private UnitToggleButton unitToggleButton;
// The expandable JPanel
public ExpanableTable elementTable;

private String id;
private String unitStatusString;
private String invStatusString;
private String targetString;
private String timeString;

public Color componentColor;

private JPanel topPanel = new JPanel();
public JPanel tablePanel = new JPanel();

public ExamplePanel(int index) {
    super();
    this.indx = index;
    id = "Unit # 00000";
    id = "Unit #00000";
    unitStatusString = "PENDING";
    invStatusString = "PENDING";
    elementTable = new ExpanableTable();
    targetString = "AZ501";
    timeString = "11:18:27";
    componentColor = this.getBackground();
    init();

}

private void init() {
    topPanel.setLayout(new GridBagLayout());
    topPanel.setBorder(PAD_BORDER);

    unitLabel = new JLabel(id); // TODO unit.getID();
    statLabel = new JLabel(unitStatusString); // TODO: unit.getStatus();
    invLabel = new JLabel(invStatusString); // TODO: unit.getInventoryStatus();

    targetLabel = new JLabel(targetString);
    timeLabel = new JLabel(timeString);

    buildLabel(statLabel);
    buildLabel(invLabel);
    buildLabel(targetLabel);
    buildLabel(timeLabel);

    unitToggleButton = new UnitToggleButton(BasicArrowButton.EAST, indx);

    GridBagConstraints gbc = new GridBagConstraints();
    gbc.anchor = GridBagConstraints.FIRST_LINE_START;
    gbc.fill = GridBagConstraints.FIRST_LINE_END;
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.weightx = .1;
    gbc.weighty = 1;
    gbc.insets = new Insets(0, 0, 5, 0);

    // Add toggle button far-left, row 1
    topPanel.add(unitToggleButton, gbc);

    // Add empty space far-left, row 2
    gbc.gridy = 1;
    topPanel.add(new JLabel("     "), gbc);

    // Add unit label row 1 column 2
    gbc.gridy = 0;
    gbc.gridx = 1;
    gbc.weightx = .3;
    topPanel.add(unitLabel, gbc);

    // Add Status label row 1 column 3
    gbc.gridx = 2;
    topPanel.add(statLabel, gbc);

    // Add inventory label row 1 column 4
    gbc.gridx = 3;
    topPanel.add(invLabel, gbc);

    // Add tasking label row 2 column 2
    gbc.gridy = 1;
    gbc.gridx = 1;
    topPanel.add(new JLabel("   Tasking: "), gbc);

    // Add target label row 2 column 3
    gbc.gridx = 2;
    topPanel.add(targetLabel, gbc);

    // Add mission Label row 2 column 4
    gbc.gridx = 3;
    topPanel.add(timeLabel, gbc);

    gbc.gridx = 0;
    gbc.gridy = 2;
    gbc.weighty = 1;
    gbc.weightx = 1;
    gbc.gridwidth = 4;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.insets = new Insets(0, 0, 0, 0);
    JSeparator sep = new JSeparator(JSeparator.HORIZONTAL);
    topPanel.add(sep, gbc);

    gbc.gridy = 3;
    topPanel.add(elementTable, gbc);
    revalidate();

    this.setLayout(new BorderLayout());
    this.add(topPanel, BorderLayout.NORTH);
    this.add(tablePanel, BorderLayout.CENTER);
    HSIUtils.setColoredBorder(tablePanel, Color.RED);
    tablePanel.add(elementTable);

    // Do NOT show the table on initialization
    tablePanel.setVisible(false);
    unitToggleButton.addActionListener(this);
}

/**
 * Method: buildLabel()
 *
 * @param label
 */
private void buildLabel(JLabel label) {
    label.setBorder(STAT_BORDER);
    label.setMinimumSize(new Dimension(80, 20));
    label.setPreferredSize(new Dimension(100, 25));
    label.setOpaque(true);
    label.setHorizontalAlignment(SwingConstants.CENTER);
    label.setHorizontalTextPosition(SwingConstants.CENTER);
    label.setBackground(componentColor);
}

private void showHideTable(boolean show) {
    tablePanel.setVisible(!show);
}

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == this.unitToggleButton) {
        showHideTable(unitToggleButton.isExpanded());
    }

}

}

ExpandableTable:

public class ExpanableTable extends JPanel {

    public ExpanableTable () {
        super();
        this.setLayout(new BorderLayout());
        add(new JButton("Test1"), BorderLayout.WEST);
        add(new JButton("Test2"), BorderLayout.CENTER);
        add(new JButton("Test3"), BorderLayout.EAST);
    }
}

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

1 Ответ

0 голосов
/ 15 октября 2018

Есть ли какое-то ограничение в JScrollPane, которое изменяет размеры дочерних JPanel-компонентов, чтобы всегда сохранять одинаковую высоту?

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

wrapPanel.setLayout(new GridLayout(numUnits, 1));  

С другой стороны, когда вы используете GridLayout, тогда да, все компоненты, добавленные в сетку, будут изменены до размера самого большого компонента.

Так что вы не хотите использовать GridLayout для панели оболочки.

Я бы предложилВы можете использовать GridBagLayout или BoxLayout.В качестве панели.

Тогда я бы предложил, чтобы для вашей расширяемой панели вы использовали BorderLayout.Вы добавляете деталь, которая всегда видима для CENTER, и расширяемую деталь к PAGE_END.Затем, когда вы захотите расширить панель, вы просто измените видимость компонента в PAGE_END.

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

...