java swing GroupLayout - 如何交换组件的位置

Posted

技术标签:

【中文标题】java swing GroupLayout - 如何交换组件的位置【英文标题】:java swing GroupLayout - Howto exchange position of components 【发布时间】:2014-05-15 12:21:26 【问题描述】:

我在 GroupLayout 中有一个 JFrame 布局。当用户单击按钮时,我想交换此 JFrame 中两个组件的位置。我在 GroupLayout 中使用了replace() 方法将一个替换为另一个。这是我要交换两个按钮位置的代码:buttons[0]buttons[1]

groupLayout.replace(buttons[1], buttons[2]);
groupLayout.replace(buttons[2], buttons[1]);

但是,当我运行它时,程序会触发NullPointerException。该异常没有提供任何有用的信息:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at javax.swing.GroupLayout$ComponentInfo.setBounds(Unknown Source)
    at javax.swing.GroupLayout.layoutContainer(Unknown Source)
    at java.awt.Container.layout(Unknown Source)
    at java.awt.Container.doLayout(Unknown Source)
    at java.awt.Container.validateTree(Unknown Source)
    at java.awt.Container.validateTree(Unknown Source)
    at java.awt.Container.validateTree(Unknown Source)
    at java.awt.Container.validate(Unknown Source)
    at javax.swing.RepaintManager$2.run(Unknown Source)
    at javax.swing.RepaintManager$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at javax.swing.RepaintManager.validateInvalidComponents(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

(一开始我以为是因为buttons[2]已经被删除了。但是当我尝试replace(buttons[1],buttons[3])之前没有将buttons[3]添加到groupLayout中时,没有任何问题。所以我还是想不通出了什么问题。)

然后,我想出了一个想法,即维护对 Group 的引用,该引用仅包含我想要更改的组件,以便以后对其进行操作。这是我的代码:

if(count % 2 == 1) 
    groupLayout.replace(buttons[1], buttons[2]);
    button2HorizontalGroup.addComponent(buttons[1]);
    button2VerticalGroup.addComponent(buttons[1]);
else 
    groupLayout.replace(buttons[2], buttons[1]);
    button2HorizontalGroup.addComponent(buttons[2]);
    button2VerticalGroup.addComponent(buttons[2]);

但这可能更像是一种技巧而不是解决方案。另外,如果要交换大量组件,可能会很麻烦。有没有更好的解决方案来交换 GroupLayout 中的组件? (也欢迎其他布局中的解决方案:))

谢谢。


更新:

@user1803551: 这是我的代码(GroupLayoutTest 是一个扩展 JFrame 的类):

public GroupLayoutTest() 
    // Allow group layout to automatically creat the gap between components and containers.
    groupLayout.setAutoCreateGaps(true);
    groupLayout.setAutoCreateContainerGaps(true);
    setLayout(groupLayout);


    buttons = new JButton[4];
    buttons[0] = new JButton("small 1");
    buttons[1] = new JButton("medium 2");
    buttons[2] = new JButton("big 3");

    buttons[1].addActionListener(replaceHandler);
    buttons[2].addActionListener(replaceHandler);

    button1HorizontalGroup.addComponent(buttons[1]);
    button1VerticalGroup.addComponent(buttons[1]);
    button2HorizontalGroup.addComponent(buttons[2]);
    button2VerticalGroup.addComponent(buttons[2]);

    groupLayout.setHorizontalGroup(
            groupLayout.createParallelGroup()
            .addGroup(groupLayout.createSequentialGroup()
                    .addGap(39)
                    .addComponent(buttons[0])
                    // Make it like a Spring
                    .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGap(10)
                    .addGroup(button1HorizontalGroup)
                    .addGap(52))
            .addGroup(groupLayout.createSequentialGroup()
                    .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGap(0)
                    .addGroup(button2HorizontalGroup)
                    .addContainerGap(GroupLayout.DEFAULT_SIZE, 160))
    );
    groupLayout.setVerticalGroup(
            groupLayout.createSequentialGroup()
            .addContainerGap(50, 50)
            .addGroup(groupLayout.createParallelGroup()
                    .addComponent(buttons[0])
                    .addGroup(button1VerticalGroup) )
            .addGap(10)
            .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(button2VerticalGroup)
            .addContainerGap(168, 168));

    groupLayout.linkSize(SwingConstants.HORIZONTAL, buttons[1],buttons[2]);
    pack();
    setLocationRelativeTo(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


private class ReplaceHandler implements ActionListener 

    private int count = 0;
    @Override
    public void actionPerformed(ActionEvent e) 
        count += 1;
        if(count % 2 == 1) 
            groupLayout.replace(buttons[1], buttons[2]);
            button2HorizontalGroup.addComponent(buttons[1]);
            button2VerticalGroup.addComponent(buttons[1]);
        else 
            groupLayout.replace(buttons[2], buttons[1]);
            button2HorizontalGroup.addComponent(buttons[2]);
            button2VerticalGroup.addComponent(buttons[2]);
        
        groupLayout.linkSize(SwingConstants.HORIZONTAL, buttons[1],buttons[2]);
    


@camickr:正如您从上面的代码中看到的那样,我对 GroupLayout 的第一次体验感到很开心。我想让一个按钮(“中”和“小”)在我单击时相互交换。毕竟,谢谢你的建议。 :)

【问题讨论】:

不要使用 GroupLayout。该布局旨在供 IDE 使用,并且不容易手动编码,尤其是在进行动态更改时。通过学习手动创建 GUI 而不是依赖 IDE,您将受益更多。 @camickr 我经常手动使用GroupLayout 编码,它的复杂性被高估了,只是习惯的问题。 重点是:你可以在很多布局中交换组件的位置,你到底有什么,你想实现什么? 【参考方案1】:

我对 GroupLayout 的第一次体验很开心。

嗯,你应该先学习其他布局管理器

我想让一个按钮(“中”和“小”)在我单击时相互交换。

创建一个 JPanel 以包含您的两个按钮并将面板添加到布局中。

使一个按钮可见而另一个按钮不可见。当您单击按钮时,您会切换两个按钮的可见性状态。

【讨论】:

1. 呃,我在使用其他组件时遇到了一些困难。在大多数布局管理器中固定某些东西(尤其是大小)总是很困难的,不是吗。所以我尝试了grouplayout。 2. 切换按钮的可见性不会改变它们的位置。此外,我的两个按钮位于两个单独的位置。很难将它们全部放在一个 JPanel 中。 @we-taper,当你说“互相交换”时,在我看来这两个按钮占据了同一个地方,但一次只能看到一个,这就是我制作我的建议。如果按钮位于面板上的不同位置,那么您应该能够切换可见性。当然,这假设 GroupLayout 确实尊重组件的可见性。 谢谢。我可以问你为什么我有这样一个NullPointerException(在我的第一个例子中)?没有提供有用的信息。我什至无法捕捉到这个异常(我试过但失败了)。 我猜不出为什么你有基于几行代码的 NPE。当您提出问题时,您应该始终包含一个 SSCCE 来证明问题。但是,由于我对 GroupLayout 一无所知,因此无法提供帮助。

以上是关于java swing GroupLayout - 如何交换组件的位置的主要内容,如果未能解决你的问题,请参考以下文章

GroupLayout:值得学习吗?

显示图标

在 Java 中重写 GroupLayout 构造函数

学习 Java 布局 groupLayout

Java - 如何在 GroupLayout 中调整组件的大小

Java GroupLayout定位