JScrollPane内部有多个自定义JPanels-调整/显示一个组件的大小会调整它们的大小

时间:2018-10-15 17:51:19

标签: java swing user-interface jscrollpane

所以我有一个自定义的JPanel,我使用它的多个实例来填充JScrollPane中的包装面板。我使用的自定义JPanel元素的数量取决于列表的大小。我遇到的问题是“自定义JPanel”的一部分,还有一个不可见的JPanel,当我单击它的父级时,它会扩展。我试图模仿的行为是Accordian UI元素的行为。在从事这个项目之前,我主要是一个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 :(得分:0)

  

JScrollPane中是否存在某种约束来调整其子JPanel组件的大小,以始终保持相同的高度?

滚动窗格不会调整任何大小。仅当添加的组件的首选大小大于滚动窗格的大小时,才会显示添加到滚动窗格的组件并添加滚动条。

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

另一方面,当您使用GridLayout时,是的,添加到网格的所有组件都将被调整为最大组件的大小。

因此,您不想为包装器面板使用GridLayout。

我建议您可以使用GridBagLayout或BoxLayout。作为面板。

然后,我建议您为可扩展面板使用BorderLayout。您将始终对CENTER可见的部分和可扩展部分添加到PAGE_END。然后,当您想扩展面板时,只需在PAGE_END中更改组件的可见性即可。

然后,布局管理器将完成所有工作,重新计算所有面板的正确大小。