Java 如何将JComponent添加到框的某个索引中

Java 如何将JComponent添加到框的某个索引中,java,swing,layout,Java,Swing,Layout,在我的软件中,我有一个滚动窗格,它的视图有一个方框布局,并保存JPanel。 一个按钮允许将JPanel添加到该框中,我想找到一种方法将其放置在某个位置 以下是一个屏幕截图: 下面是示例代码: public class MyClass { //run a swing App public static void main(String[] args) throws IOException { SwingUtilities.invokeLater(new S

在我的软件中,我有一个滚动窗格,它的视图有一个方框布局,并保存JPanel。 一个按钮允许将JPanel添加到该框中,我想找到一种方法将其放置在某个位置

以下是一个屏幕截图:

下面是示例代码:

public class MyClass {

    //run a swing App
    public static void main(String[] args) throws IOException   {
        SwingUtilities.invokeLater(new ScrollPaneExample());        
    }
}


class ScrollPaneExample implements Runnable{

    private Box boxHolder;
    private JPanel scrollPaneContainer;

    //show a JFrame
    @Override
    public void run(){           
        JFrame mainFrame = initFrame();
        mainFrame.setPreferredSize(new Dimension(300, 200));
        mainFrame.setLocationRelativeTo(null);
        mainFrame.pack();
        mainFrame.setVisible(true);
    }

    //init JFrame and add to it a scrollpane and a button
    private JFrame initFrame() {
        JFrame mainFrame = new JFrame("MyFrame");
        mainFrame.setLayout(new BorderLayout());
        mainFrame.getContentPane().add(initScrollPane(),BorderLayout.CENTER);
        mainFrame.getContentPane().add(initButtonAdd(),BorderLayout.SOUTH);
        return mainFrame;
    }

    //init scrollpane which contains a boxholder for colored panels
    private Component initScrollPane() {
        scrollPaneContainer = new JPanel( new BorderLayout() );
        boxHolder = Box.createVerticalBox(); 
        scrollPaneContainer.add(boxHolder, BorderLayout.PAGE_START);
        return new JScrollPane(scrollPaneContainer);
    }

    //init a button which add a panel to the boxholder on pressed
    private Component initButtonAdd() {
        JButton button = new JButton("addPanel");
        button.setBackground(Color.green);
        button.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) {
               boxHolder.add(createPanel());
               scrollPaneContainer.revalidate();
           }
        });
        return button;
    }

    //create a panel setting its background to a random color
    private Component createPanel() {
        JPanel panel = new JPanel();
        panel.setBackground(randomColor());
        panel.setPreferredSize(new Dimension(100,50));
        panel.addMouseListener(new MouseListener() {
           public void mousePressed(MouseEvent e) {
                /** TODO code to replace the clicked panel with a new one*/     
           }
           @Override public void mouseClicked(MouseEvent e) {}
           @Override public void mouseReleased(MouseEvent e) {}
           @Override public void mouseEntered(MouseEvent e) {}
           @Override public void mouseExited(MouseEvent e) {}
        });
        panel.add(new JLabel("a colored Panel"));
        return panel;
    }

    //generate a randomColor
    private Color randomColor() {
        Random rand = new Random();
        float r = rand.nextFloat() / 2f ;
        float g = rand./***/nextFloat() / 2f;
        float b = rand.nextFloat() / 2f;
        Color randomColor = new Color(r, g, b);
        return randomColor;
    }


}
我想做一些类似的事情:

int indexPosition = 2;
boxHolder.add(createPanel(), indexPosition);
    JPanel replacePanel = createPanel();
   // next istruction leads to a compilation error since Box do not has this method
    int indexOfClickedPanel= boxHolder.indexOf(this);
    boxHolder.add(replacePanel,indexOfClickedPanel); 
更新1-2 首先:谢谢。 我注意到提供的示例代码没有正确反映我的代码,在解释我的问题时,我失去了目标。 我将保留前一个问题,因为它对其他人有用。 让我们继续

我需要替换一个特定的面板,所以,我们以前用给定的索引所做的,应该用一些更动态的东西来实现。 我在JPanel上加了一个鼠标听器。单击后,应将其替换为新面板。比如:

int indexPosition = 2;
boxHolder.add(createPanel(), indexPosition);
    JPanel replacePanel = createPanel();
   // next istruction leads to a compilation error since Box do not has this method
    int indexOfClickedPanel= boxHolder.indexOf(this);
    boxHolder.add(replacePanel,indexOfClickedPanel); 

在我的代码中,我使用JLabel而不是按钮。其图标在鼠标进入/退出时更改,并在按下时添加特定面板。对我来说,这听起来更合适,任何建议都将不胜感激。

在这个回答中,我为您的听众添加了额外的代码,但如果您需要更改,可以很容易地更改

如果您想在该位置添加另一个面板,可以使用任何索引位置

public void mouseClicked(MouseEvent e) {
    boxHolder.add(createPanel());
    int indexPosition  = 2;
    try //Will only add here if you have a component in index position 1
    {
        boxHolder.add(createPanel(),indexPosition);
    }
    catch(Exception ex){}
    scrollPaneContainer.revalidate();
}
这将在索引位置2添加一个面板,并将索引位置2的当前面板移动到索引位置3

如果要替换索引位置2的当前面板,可以使用

public void mouseClicked(MouseEvent e) {
    boxHolder.add(createPanel());
    int indexPosition  = 2;
    try //Will only remove it if there is already a panel or other component there
    {
        boxHolder.remove(indexPosition);
    }
    catch(Exception ex){}
    try //Will only add here if you have a component in index position 1
    {
        boxHolder.add(createPanel(),indexPosition);
    }
    catch(Exception ex){}
    scrollPaneContainer.revalidate();
}
这将移除当前处于索引位置2的面板,并在其位置添加另一个面板

但是,如果尝试将组件添加到索引位置2,而索引位置0或1中没有任何组件,则会出现异常
java.lang.IllegalArgumentException:非法组件位置
。因此,这就是为什么添加一个面板的代码位于
try catch
块中,在该面板中,int变量的索引位置为
indexPosition
。这与删除方法的原因相同

编辑

如前所述,如果您使用
操作侦听器会更好,因此在您的代码中应该是这样的

button.addActionListener(new ActionListener() 
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        //Rest of your code
    }
});
编辑2

如果您希望在单击
JPanel
时替换
JPanel
,您可以这样做

private Component createPanel() {
    JPanel panel = new JPanel();
    panel.setBackground(randomColor());
    panel.setPreferredSize(new Dimension(100,50));
    panel.add(new JLabel("a colored Panel"));
    panel.addMouseListener(new MouseListener() {
        @Override 
        public void mouseClicked(MouseEvent e) {
            int indexPosition  = boxHolder.getComponentZOrder(panel);
            try
            {
                boxHolder.remove(indexPosition);
            }
            catch(Exception ex){}
            try //Will only add here if you have a component in index position 1
            {
                boxHolder.add(createPanel(),indexPosition);
            }
            catch(Exception ex){}
            scrollPaneContainer.revalidate();
        }
        @Override public void mousePressed(MouseEvent e) {}
        @Override public void mouseReleased(MouseEvent e) {}
        @Override public void mouseEntered(MouseEvent e) {}
        @Override public void mouseExited(MouseEvent e) {}
    });
    return panel;
}
至于改进建议。我建议将您的
initScrollPane
方法更改为以下代码,以便您可能更熟悉滚动的速度

private Component initScrollPane() {
    scrollPaneContainer = new JPanel( new BorderLayout() );
    boxHolder = Box.createVerticalBox(); 
    scrollPaneContainer.add(boxHolder, BorderLayout.PAGE_START);
    JScrollPane jSP = new JScrollPane(scrollPaneContainer);
    jSP.getVerticalScrollBar().setUnitIncrement(16);
    return jSP;
}

我的答案是你想要的还是你的问题中的其他意思?在你的
按钮
上添加一个
动作监听器,而不是
鼠标监听器
。丹,谢谢你的回答,它完全符合我的意思。问题是这不是我的问题,我问错了。我将编辑问题以添加真正的问题xD@Koop4那么,当你点击按钮(或标签或任何你使用的组件)时,你能告诉我它要替换哪个面板吗?@Koop4假设你想在点击面板时替换它,请参见我的回答中的编辑2关于编辑2:getComponentZOrder(面板)该方法工作正常。还感谢重新实现initScrollPane()。在未来,我将需要为这些面板实现可比性。在每次操作之后,我应该在滚动窗格中对它们进行排序。“你认为我应该处理一些事情吗?”Koop4只要仔细阅读你的评论。你会如何比较你的面板?我还没学过技术。在我的软件中,这些JPanel包含一个具有特定int字段的对象,我将轻松实现可比较的接口。假设我们的面板变成了对象,在其构造函数中计算了一个随机(0-100)int字段,并有一个新按钮将它们从上到下排列(递增)。您认为这样的实现对这样做有好处吗?我相信我们可以做到,但我仍然想知道使用BoxLayout是否适合这种管理方式。再次感谢您,如果您需要一些示例代码,我将提供@Koop4来执行您可能希望查看或使用的类似操作。它们显示冒泡排序和合并排序等排序。因此,最好的方法是从所有JPanel中获取INT,然后对它们进行排序。然后根据排序重新排列JPaneloutcome@Koop4至于使用
BoxLayout
这实际上是个人喜好的问题。对于这个特定的程序,由于函数
getComponentZOrder
,它似乎工作得很好。然而,如果你寻找另一个布局,这可能是我的最爱之一