3
votes

In my software, I have a ScrollPane whose view has a Box Layout and holds JPanels. A button allows to add a JPanel to that Box, and i'd like to find a way to place it in a certain position.

Here is a screenShot: theApp

Here is the example code:

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;
    }


}

I'd like to do something like:

int indexPosition = 2;
boxHolder.add(createPanel(), indexPosition);

UPDATE 1-2 First of all: thanks. I noticed that the example code provided does not reflect properly my code, and i have lost the objective while explaining my problem. I'll keep the previous question as it is since it can be usefull to someone else. Let's move on.

I need to replace a certain panel, so, what we did before with a given index, should be implemented with someting more dynamic. i've added a mouseListener to our Jpanels. On click, they should be replaced by a new panel. Something like:

    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); 

In my code i use a JLabel instead of a button. Its icon changes on mouseEntered/Exited, and add a certains panel onPressed. It sounds to me more appropriate, any suggestion will be appreciated btw.

1
Is my answer what you are after or did you mean something else in your question? - Dan
Instead of a MouseListener, add an ActionListener to your Button. - trashgod
Dan, thanks for your answer, it does properly what i meant. The problem is that it was not my problem, i was asking the wrong thing. I'm gonna edit the question to add the true problem xD - Robdll
@Koop4 so would you be able to tell me which panel it is meant to replace when you click on the button (or label or whatever component you use)? - Dan
@Koop4 Assuming you want to replace the panel when you click on it see edit 2 of my answer - Dan

1 Answers

3
votes

In this answer I add the extra code to your listener but that can easily be changed if you need to change it.

If you would like to add another panel at that position any index position you can use

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();
}

This will add a panel in at index position 2 and move current panel in index position 2 to index position 3.

If you would like to replace the current panel in index position 2 you can use

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();
}

This will remove the panel currently in index position 2 and add another one in its place.

However if you try to add a component to index position 2 without there being any components in index position 0 or 1 you will get the exception java.lang.IllegalArgumentException: illegal component position. Hence that is why the code for adding a panel in which ever index position your int variable, indexPosition, states is in a try catch block. It is the same reason for the remove method.

Edit

As trashgod said it would be better if you used an Action Listener so in your code it would be.

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

Edit 2

If you are looking to replace a JPanel when you click on the JPanel you could do something like this.

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;
}

As for suggestions on improvements. I would suggest changing your initScrollPane method to the following code so the scrolling is a speed you might be more familiar to.

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;
}