Java Swing - 实现期望的布局有困难

3
我正在使用Swing编写Java GUI。目前,我试图创建一个“模块”(黄色块),它在左侧和右侧具有小部件容器(黑色条)。每个容器将容纳几个小块,并且我想要以垂直线显示它们。下面是一张图片:
示例模块: enter image description here 我希望能够使品红/青色块在小部件容器中均匀分布。
我查看了几个Swing教程,并尝试将小部件容器的布局实现为GridLayout和BoxLayout,但都没有成功。单列GridLayout似乎是这里的自然选择,但即使我编写了小型测试程序,也无法使其正常工作。
布局管理器在简单示例中运行,但在这个稍微复杂的程序中却无法工作,这让我感到困惑。
在我的程序中:
- 模块是一个JPanel - 小部件容器/黑条也是JPanel - 小部件本身(青/品红块)目前是JPanel,但我也尝试过将它们设置为JLabel和JButton。我只是希望它们能够监听鼠标事件并具有区域和颜色。
另外,我还遇到了关于模块本身布局的问题,以将小部件容器放置在左侧和右侧。我尝试使用水平BoxLayout(holder,horizontal glue,holder),还尝试使用BorderLayout(使用EAST/WEST分别作为容器),但无论我做什么,容器都不会移动 - 因此,尽管我不想这样做,我使用了setBounds()来定位它们。
模块类(小部件容器为inputLine和outputLine):
public class Module extends JPanel
{
private static final int MOD_WIDTH  = 86;
private static final int MOD_HEIGHT = 60;

private int screenX, screenY, myX, myY;

private boolean moving = false;

// figure out the layout !
private JPanel inputLine, outputLine;

public Module()
{
    //super(new BorderLayout());

    initPanel();
    initWidgets();
    initMouse();

    setLayout(null);

    list();
}

private final void initPanel()
{
    this.setSize(new Dimension(MOD_WIDTH, MOD_HEIGHT));
    this.setBackground(Color.ORANGE);
}

private void initWidgets()
{
    inputLine   = new JPanel(new GridLayout(0, 1, 5, 5));
    outputLine  = new JPanel(new GridLayout(0, 1, 5, 5));

    inputLine.setBounds (0, 0, 18, 60);
    outputLine.setBounds(68, 0, 18, 60);

    this.add(inputLine);
    this.add(outputLine);

    /* adding IOWidgets to test */
    inputLine.add(new InputWidget());
    inputLine.add(new InputWidget());
    inputLine.add(new InputWidget());

    outputLine.add(new OutputWidget());
    outputLine.add(new OutputWidget());
    outputLine.add(new OutputWidget());
    outputLine.add(new OutputWidget());

    inputLine.setBackground(Color.BLACK);
    outputLine.setBackground(Color.BLACK);
}

这是IOWidget类的摘要,两种类型的小部件(输入[品红色]和输出[青色])都从它派生。稍后将添加功能。
public abstract class IOWidget extends JLabel
{   

    private static final int EDGE_SIZE = 8;

    public IOWidget()
    {
        this.setSize(new Dimension(EDGE_SIZE, EDGE_SIZE));
    }
}

这是InputWidget类。目前,它与OutputWidget完全相同,直到我添加额外的功能,因此我将仅发布这一个:
public class InputWidget extends IOWidget
{
    public InputWidget()
    {
        this.setBackground(Color.MAGENTA);
    }
}

在我的应用程序中,模块被添加到一个较大的JPanel中。我希望模块的布局与它如何添加到另一个JComponent无关,因此我将省略其余代码。

当运行程序时,它看起来像这样:

enter image description here

为了完整起见,以下是调用单个模块列表的输出:

rhopkins.honors.Dataflow.Module[,0,0,86x60,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
 javax.swing.JPanel[,0,0,18x60,invalid,layout=java.awt.GridLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
  rhopkins.honors.Dataflow.InputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
  rhopkins.honors.Dataflow.InputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
  rhopkins.honors.Dataflow.InputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
 javax.swing.JPanel[,68,0,18x60,invalid,layout=java.awt.GridLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]
  rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
  rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
  rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]
  rhopkins.honors.Dataflow.OutputWidget[,0,0,8x8,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=8,height=8]]

我非常希望知道我做错了什么。此外,我知道自己对Swing和GUI开发都很新,所以对于风格/约定或任何方面的批评都欢迎。


2
这是一个包含10个组件的复杂布局。根据您的描述,您似乎正在正确地处理它。但如果没有一个简短、自包含、正确可运行的代码片段,恐怕我无法为您提供更多帮助。 - Gilbert Le Blanc
嗯。我刚刚写了一个小的Tester类,它只是扩展了JFrame,创建了一个新的Module,并将其添加到其中。在这种情况下,Module以我想要的方式进行格式化。此外,我注意到当我最小化窗口并将其恢复时,模块会正确地显示自己。所以我想这只是重新绘制或重新验证的问题。 - MIlkywayw
1个回答

4
不要使用null布局。
您的主要面板可能应该是BorderLayout。您可以将小部件容器添加到主面板的WEST和EAST位置。
小部件面板应该能够使用垂直BoxLayout。每次向面板中添加小部件之前/之后,都需要添加glue。由于BoxLayout尊重组件的大小,因此您需要覆盖getPreferredSize()、getMinimumSize()和getMaximumSize()方法,让它们都返回相同的值。这样,面板中任何多余的空间应该会平均分配在您添加的glue之间。

谢谢,我本来不想使用空布局,但最终还是用了因为似乎这是唯一的让它“强制”工作的方式。现在我将其恢复回了BorderLayout,并且它完美地运行了(在我修复了潜在问题之后)!此外,感谢您提供BoxLayout建议-它太完美了!这样我就不必处理边框或其他任何东西了。 - MIlkywayw
请务必接受回答这个(或任何其他)stackoverflow问题的答案。 - arcy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接