Search code examples
javaswingjava-8java-7mousemotionlistener

adding dragged component to JPanel on java8


I have (JScrollPane) scroll which contains:

  • (JPanel) mainPanel (scroll size)
    • (JPanel) boxPanel (boxPanel is added to mainPanel)
      • (ArrayList < JPanel >) rowPanel (all components in List are added to boxPanel)

I want rowPanel components to be draggable and update their position in boxPanel depending on place they are dragged onto.

Code bellow works fine with java 7, but doesn't work with java 8.

On java 8 code stops working at:

boxPanel.add(tempItem, temp);

Whenever I try to add JPanel, which is being dragged to a boxPanel, program doesn't do it. I get no errors or exceptions. I can't understand why it is not working with java 8.

private void handleDrag(final JPanel panel){

    panel.addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent me) {
             panelY = me.getY();    
             panelNo = rowPanel.indexOf(panel);
             tempItem = rowPanel.get(panelNo);
        }
    });

   panel.addMouseMotionListener(new MouseMotionAdapter() {
      @Override
        public void mouseDragged(MouseEvent mep) {
            mep.translatePoint(0, mep.getComponent().getLocation().y - panelY);

 // get new position of row 

            int temp;

            if(((mep.getY() - panelY) / mep.getComponent().getSize().height) < 0){
                temp = 0;
            }
            else if(((mep.getY() - panelY) /  mep.getComponent().getSize().height) < (elementsAmount - 1)){
                double d = ((double)(mep.getY() - panelY) /  mep.getComponent().getSize().height + 1);
                temp = (int) Math.round(d);
                if(temp > (elementsAmount - 1)){
                    temp = elementsAmount - 1;
                }
            }
            else{
                temp = (elementsAmount - 1);
            }


// rowPanel ArrayList<JPanel> containing all rows within boxPanel
            rowPanel.remove(tempItem); 
            rowPanel.add(temp, tempItem);
// boxPanel JPanel with BoxLayout
            boxPanel.add(tempItem, temp);

            scroll.revalidate();
        }
    });
}

Solution

  • You have to ensure that the modified Container gets revalidated and repainted afterwards, e.g. by calling the similarly named methods on it. But generally, removing and adding components while a mouse event processing is ongoing, is a bad idea. Thankfully, you don’t have to implement it that complicated. Here is a simple, self-contained example of components in a BoxLayout, reorderable via mouse dragging:

    JFrame frame=new JFrame("Box ordering test");
    Box box=Box.createVerticalBox();
    frame.setContentPane(box);
    box.add(new JLabel("One"));
    box.add(new JLabel("Two"));
    box.add(new JLabel("Three"));
    box.add(new JLabel("Four"));
    box.add(new JLabel("Five"));
    MouseMotionListener l=new MouseMotionAdapter() {
        @Override
        public void mouseDragged(MouseEvent e) {
            Component c=e.getComponent();
            Container p=c.getParent();
            int count = p.getComponentCount();
            int newPos=Math.max(0, Math.min(count,
                (e.getY()+c.getY())*count/p.getHeight()));
            if(newPos!=p.getComponentZOrder(c)) {
                p.setComponentZOrder(c, newPos);
                p.revalidate();
                p.repaint();
            }
        }
    };
    for(Component c: box.getComponents()) c.addMouseMotionListener(l);
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);