如何制作4象限Java Swing GUI,其边缘总是符合黄金比例?

时间:2015-05-12 15:22:06

标签: java swing user-interface layout

我想要一个带有4个象限的矩形GUI。 JFrame的高度与宽度的比率(不包括最小化/最大化/关闭按钮)应为1到phi,其中phi等于黄金比率(大约1.62)。

Four quadrant GUI with sides corresponding to the golden ratio

现在,对于JFrame内的四个象限。 JFrame具有水平分界线,将高度分成两部分,上部和下部。鞋面的高度与下部的高度之间的比率也应该是phi到1。最后,JFrame有一条垂直分界线,将宽度分成两部分,左边和右边。左侧和右侧之间的比率也应该是1。见上图。

现在,这是艰难的部分。我希望这四个组件始终遵循比率,无论Swing组件(JScrollPane,JList,JTextArea,JPanel,JTree或JButton)放入相应的网格位置。例如,我希望能够从四个网格位置中的四个JButton开始,然后将其中一个JPanel与一个具有JList的JScrollPane交换,而内部组件不会改变外部组件的相对比例,即使内部组件中包含一些文本或数据。见下图。

Adding a JTree messed up the ratios of the dividing lines

无论我多么努力地实现它(使用GridBadLayout和一组约束),我都无法让网格线保持不变。如何使网格线保持原位?

到目前为止,我的源代码如下所示:

public static final double GOLDEN_RATIO = 1.6180339887498948482;
public static final double RELATIVE_LENGTH_OF_LONGER_SIDE = 1 / GOLDEN_RATIO;
public static final double RELATIVE_LENGTH_OF_SHORTER_SIDE = 1 - (1/GOLDEN_RATIO);

// ...

    // make GridBagLayout
    pane.setLayout(new GridBagLayout());
    final GridBagConstraints c = new GridBagConstraints();

    // Make 4 components to put in the four grid spaces.
    JButton filler1 = new JButton();
    c.fill = GridBagConstraints.BOTH;
    c.weightx = RELATIVE_LENGTH_OF_SHORTER_SIDE;
    c.weighty = RELATIVE_LENGTH_OF_LONGER_SIDE;
    c.gridx = 0;
    c.gridy = 0;
    filler1.setMinimumSize(new Dimension(0,0));
    filler1.setPreferredSize(new Dimension(0,0));
    pane.add(filler1, c);

    JButton filler2 = new JButton();
    c.fill = GridBagConstraints.BOTH;
    c.weightx = RELATIVE_LENGTH_OF_LONGER_SIDE;
    c.weighty = RELATIVE_LENGTH_OF_LONGER_SIDE;
    c.gridx = 1;
    c.gridy = 0;
    filler2.setMinimumSize(new Dimension(0,0));
    filler2.setPreferredSize(new Dimension(0,0));
    pane.add(filler2, c);

    JButton filler3 = new JButton();
    c.fill = GridBagConstraints.BOTH;
    c.weightx = RELATIVE_LENGTH_OF_SHORTER_SIDE;
    c.weighty = RELATIVE_LENGTH_OF_SHORTER_SIDE;
    c.gridx = 0;
    c.gridy = 1;
    filler3.setMinimumSize(new Dimension(0,0));
    filler3.setPreferredSize(new Dimension(0,0));
    pane.add(filler3, c);

    JButton filler4 = new JButton();
    c.fill = GridBagConstraints.BOTH;
    c.weightx = RELATIVE_LENGTH_OF_LONGER_SIDE;
    c.weighty = RELATIVE_LENGTH_OF_SHORTER_SIDE;
    c.gridx = 1;
    c.gridy = 1;
    filler4.setMinimumSize(new Dimension(0,0));
    filler4.setPreferredSize(new Dimension(0,0));
    pane.add(filler4, c);

    // Set the size of the enclosing panel.
    this.setPreferredSize(new Dimension(
            (int)(screen_height_*RELATIVE_LENGTH_OF_LONGER_SIDE), 
            (int)(screen_height_*RELATIVE_LENGTH_OF_SHORTER_SIDE))
    );

另外,无论我制作的尺寸有多小,它都不应该像这样: Ratios way off

2 个答案:

答案 0 :(得分:1)

您应该创建自己的LayoutManager。我认为你真正需要实现的唯一方法是layoutContainer。在此方法中,您可以使用您指定的比率设置子组件(应为4)

答案 1 :(得分:1)

您可以使用GroupLayout为您完成工作。

修改:添加了交换按钮

示例:

test1

test1 test1

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.WindowConstants;

public class Test extends JFrame {

    public static final double GOLDEN_RATIO = 1.6180339887498948482;
    public static final double RELATIVE_LENGTH_OF_LONGER_SIDE = 1 / GOLDEN_RATIO;
    public static final double RELATIVE_LENGTH_OF_SHORTER_SIDE = 1 - (1 / GOLDEN_RATIO);
    private static final int screenHeight = 500;
    private static final int LENGTH_OF_LONGER_SIDE_FOR_RATIO = (int) (screenHeight * RELATIVE_LENGTH_OF_LONGER_SIDE);
    private static final int LENGTH_OF_SHORTER_SIDE_FOR_RATIO = (int) (screenHeight * RELATIVE_LENGTH_OF_SHORTER_SIDE);
    private static final int MIN_LENGTH_OF_LONGER_SIDE_FOR_RATIO = (int) (50 * RELATIVE_LENGTH_OF_LONGER_SIDE);
    private static final int MIN_LENGTH_OF_SHORTER_SIDE_FOR_RATIO = (int) (50 * RELATIVE_LENGTH_OF_SHORTER_SIDE);

    public Test() {
        buildGUI();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }

    private void buildGUI() {
        JPanel pane = new JPanel();
        // make GridBagLayout
        GroupLayout layout = new GroupLayout(pane);
        pane.setLayout(layout);

        // Make 4 components to put in the four grid spaces.
        JButton filler1 = new JButton("Press here to swap");
        JButton filler2 = new JButton("Press here to swap");
        JButton filler3 = new JButton("Press here to swap");
        Object[] objects = new Object[50];
        for (int i = 0; i < 50; i++) {
            objects[i] = "Test" + i;
        }
        JTree jTree = new JTree(objects);
        JScrollPane scrollPane = new JScrollPane(jTree);
        JButton button = new JButton("Press here to swap");
        JPanel filler4 = new JPanel(new BorderLayout());
        filler4.add(button);
        ActionListener l = (e) -> {
            if (filler4.getComponents()[0] instanceof JButton) {
                filler4.remove(button);
                filler4.add(scrollPane, BorderLayout.CENTER);
            } else {
                filler4.remove(scrollPane);
                filler4.add(button, BorderLayout.CENTER);
            }
            filler4.repaint();
            filler4.revalidate();
        };
        filler1.addActionListener(l);
        filler2.addActionListener(l);
        filler3.addActionListener(l);
        button.addActionListener(l);
        layout.setVerticalGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addComponent(filler1, MIN_LENGTH_OF_LONGER_SIDE_FOR_RATIO, LENGTH_OF_LONGER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                        .addComponent(filler2, MIN_LENGTH_OF_LONGER_SIDE_FOR_RATIO, LENGTH_OF_LONGER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                )
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addComponent(filler3, MIN_LENGTH_OF_SHORTER_SIDE_FOR_RATIO, LENGTH_OF_SHORTER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                        .addComponent(filler4, MIN_LENGTH_OF_SHORTER_SIDE_FOR_RATIO, LENGTH_OF_SHORTER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                ));
        layout.setHorizontalGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addComponent(filler1, MIN_LENGTH_OF_SHORTER_SIDE_FOR_RATIO, LENGTH_OF_SHORTER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                        .addComponent(filler3, MIN_LENGTH_OF_SHORTER_SIDE_FOR_RATIO, LENGTH_OF_SHORTER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                )
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addComponent(filler2, MIN_LENGTH_OF_LONGER_SIDE_FOR_RATIO, LENGTH_OF_LONGER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                        .addComponent(filler4, MIN_LENGTH_OF_LONGER_SIDE_FOR_RATIO, LENGTH_OF_LONGER_SIDE_FOR_RATIO, Short.MAX_VALUE)
                ));
        add(pane);
        setSize(new Dimension(200, 200));
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            new Test().setVisible(true);
        });
    }

}