让JScrollPanel围绕静态JPanel调整大小

时间:2018-03-19 16:04:28

标签: java swing

我正在创建一个我正在创建的游戏的编辑器,并且我在实现可滚动级别概述时遇到问题。概述应该有这样的布局:

enter image description here

Canvas应该总是具有1280x720的大小,所以我想使用JScrollPane来在JFrame变小时仍然能够查看整个画布。 现在为了实现这一点,我使用了GridBagLayout并在画布上设置了一个优先大小。问题是扩展JFrame最终会允许您将画布扩展到其优先大小之外。为了阻止这种情况,我将scrollpanes视口的布局设置为FlowLayout,以防止它调整其持有的视图的大小。这似乎产生了两个问题:

1:当扩展到完全屏幕时,GridBagLayout不再正确分配空间。

Problem1

2:当您使ScrollPane小于其视口视图时,视图会被切断,滚动似乎也无效。

enter image description here

总结我的问题:

是否有其他/更好的方法来实现此UI,如果不是,我如何解决gridbaglayout在扩展到全屏并切断视口视图时无法正确分配空间的问题?

这里是我用于示例的代码:

public class Main extends JFrame {

public Main() {
    this.setSize(800, 400);
    this.setMinimumSize(new Dimension(400, 400));
    this.setLocationRelativeTo(null);

    JPanel optionsPanel = new JPanel();
    optionsPanel.setBackground(Color.red);

    JPanel scrollContentPane = new JPanel();
    scrollContentPane.setPreferredSize(new Dimension(700,700));
    scrollContentPane.setBorder(BorderFactory.createLineBorder(Color.red));

    JScrollPane scrollPane = new JScrollPane();
    scrollPane.getViewport().setLayout(new FlowLayout());
    scrollPane.getViewport().setView(scrollContentPane);
    scrollPane.setHorizontalScrollBarPolicy(scrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane.setVerticalScrollBarPolicy(scrollPane.VERTICAL_SCROLLBAR_ALWAYS);


    JPanel contentPanel = new JPanel();
    contentPanel.setLayout(new GridBagLayout());

    GridBagConstraints gc = new GridBagConstraints();
    gc.fill = gc.BOTH;
    gc.weightx = 1.0;
    gc.weighty = 1.0;

    gc.gridx = 0;
    gc.gridy = 0;
    contentPanel.add(optionsPanel, gc);

    gc.gridx = 1;
    contentPanel.add(scrollPane, gc);

    this.setContentPane(contentPanel);
    this.setVisible(true);

}

public static void main(String[] args) {
    Main main = new Main();
}

}

以下是我在程序中使用的实际代码:

    previewPanel = new PreviewPanel(this);
    controlPanel = new ControlPanel(this);

    centerPanel = new JPanel();
    centerPanel.setLayout(new GridBagLayout());

    GridBagConstraints c = new GridBagConstraints();
    c.fill = c.BOTH;
    c.weightx = 1;
    c.weighty = 1;

    // #HACK, fill grids with empty labels
    c.gridx = 0;
    c.gridy = 0;
    centerPanel.add(new JLabel(), c);

    c.gridx = 1;
    centerPanel.add(new JLabel(), c);

    c.gridx = 2;
    centerPanel.add(new JLabel(), c);

    c.gridx = 3;
    centerPanel.add(new JLabel(), c);

    c.gridx = 0;
    c.gridy = 0;
    c.gridwidth = 1;

    centerPanel.add(controlPanel, c);

    c.gridx = 1;
    c.gridy = 0;
    c.gridwidth = 3;

    centerPanel.add(previewPanel, c);


    setLayout(new BorderLayout());
    add(centerPanel, BorderLayout.CENTER);
    add(menuBar, BorderLayout.NORTH);
}

2 个答案:

答案 0 :(得分:2)

不要使用视口的布局管理器

如果要控制添加到视口的面板大小,请将面板添加到包装面板中。类似的东西:

https://<user>.github.io/<repo>/

答案 1 :(得分:2)

边境被切断;这是因为JScrollPane无法将边框识别为组件的一部分。因此,当您一直滚动到边缘时,您将看到组件的第一个非边框像素。要解决此问题而不是在视口上设置布局,请创建另一个面板,将画布添加到此新面板,并将此新面板设置为滚动窗格中的视口。

JPanel scrollContentPane = new JPanel();
// to set the size properly see later
JPanel scrollContentPaneViewport = new JPanel(new FlowLayout());
scrollContentPaneViewport.add(scrollContentPane);
JScrollPane scrollPane = new JScrollPane();
scrollPane.getViewport().setView(scrollContentPaneViewport);

要限制画布的大小(scrollContentPane),您不应该设置大小调整提示set[minimum|preferred|maximum]sizereason is here),而应该是子类化面板并覆盖get[minimum|preferred|maximum]size方法,覆盖您需要的但如果您想使面板始终固定大小,您应该覆盖所有三个。

JPanel scrollContentPane = new JPanel() {
    // this is important never return this dimension always make a copy
    private final Dimension d = new Dimension(700, 700);

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(d);
    }
    @Override
    public Dimension getMinimumSize() {
        return new Dimension(d);
    }
    @Override
    public Dimension getMaximumSize() {
        return new Dimension(d);
    }
};

要确保optionsPanel和scrollPane始终均分,请使用GridLayout代替GridBagLayout

修改:GridBagLayout组件相对分布

您应该为布局提供有关如何处理额外空间的信息。这可以通过设置rowWeightscolumnWeights字段来完成。

JPanel contentPanel = new JPanel();
GridBagLayout gbl_contentPanel = new GridBagLayout();
// This tells the layout that first row should take all available space (there is only one row)
gbl_contentPanel.rowWeights = new double[]{1.0};
// This tells the layout that second column should be 3 times bigger than first column (3 is 3 times bigger than 1)
gbl_contentPanel.columnWeights = new double[]{1.0, 3.0};
contentPanel.setLayout(gbl_contentPanel);

这应该告诉GridBagLayout如何分配额外的空间,但它仍然不起作用。

这是因为GridBagLayout是考虑从组件返回的首选大小的布局之一。您添加的两个组件是“告诉”布局它们的最小最大值和优先大小和布局在计算组件应该获得多少空间时将其考虑在内。

要解决此问题,您应该在两个组件中覆盖getPreferredSize()以返回相同的尺寸。 (我想返回0,0)

JPanel optionsPanel = new JPanel() {
    @Override
    public Dimension getPreferredSize() {
        return new Dimension();
    }
};