0

I'm trying to set up dragging of an image over a grid of Jlabels. it's working fine, but the image is "refreshing" and sometimes lags behind the mouse.

Is there a way to improve this and get a perfectly "smooth" movement of the image ?

EDIT: ok now, thanks to Andrew Thompson's advice I updated the paint() method to paintComponent(). But now why does my component disappear when I drag it? I'm probably missing something here...

EDIT2: why is the following behaviour: when using paint() method the component displays on top of the JLabels. But when using paintComponent() the component disappears being masked by the opaque Jlabels?

import java.awt.*;  
import java.awt.event.*;  
import java.io.*;  
import java.net.*;  

import javax.imageio.ImageIO;  
import javax.swing.*;  
import javax.swing.event.*;  

public class DragNDrop {

    public static void main(String[] args)  
    {  
        JFrame f = new JFrame("Test");  
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        f.setContentPane(new DragPanel());    
        f.pack();
        f.setLocation(200,200);  
        f.setVisible(true);  
    }  

}

class DragPanel extends JPanel {

    JLabel[][] labels;

    SelectableAction action;  
    Image image;  
    Point p;  

    public DragPanel()  
    {  

        p = new Point();  

        setOpaque(true);   
        createLabels();


        action = new SelectableAction(this);  
        addMouseListener(action);  
        addMouseMotionListener(action);  
    }  

    private void createLabels() {


            labels = new JLabel[8][8];

            Dimension dim50 = new Dimension(50,50);
            GridBagConstraints gbc = new GridBagConstraints();
            this.setLayout(new GridBagLayout());

            for (int x=0;x<8;x++){

                for (int y=0;y<8;y++){

                    labels[x][y] = new JLabel();
                    labels[x][y].setOpaque(true);
                    labels[x][y].setPreferredSize(dim50);
                    String str = new String("("+x+","+y+")");
                    labels[x][y].setText(str);

                    if ((x+y) % 2 == 0){
                        labels[x][y].setBackground(Color.lightGray);
                    } else
                    {
                        labels[x][y].setBackground(Color.white);
                    }

                    gbc.gridx = x;
                    gbc.gridy = 7-y;
                    this.add(labels[x][y],gbc);


                }
                URL url = getClass().getResource("images/50px-Knight.pgn");  
                Image img;
                try {
                    img = ImageIO.read(url);
                    labels[0][0].setIcon(new ImageIcon(img));
                } catch (IOException e) {

                    e.printStackTrace();
                }  



            }
    }

    public JLabel[][] getLabels()  
    {  
        return labels;  
    }  


    public void paintComponent(Graphics g)  
    {  
        super.paintComponent(g);  

        if(action.dragging)  
            g.drawImage(image, p.x, p.y, this); 

    }  

    public void setImage(Image i)  
    {  
        image = i;  
    }  

    public void setOrigin(Point p)  
    {  
        this.p = p;  
        repaint();  
    }  


}

/** 
 * Mouse code to enable image dragging 
 */  
class SelectableAction extends MouseInputAdapter  
{  
    DragPanel MyPanel;  
    Image selectedImage;  
    boolean dragging;  
    Rectangle r;  
    Point offset;  

    public SelectableAction(DragPanel dp)  
    {  
        MyPanel = dp;   
        dragging = false;  
        offset = new Point();  
    }  
    public void mousePressed(MouseEvent e)  
    {  
        Point p = e.getPoint();  
        JLabel[][] labels = MyPanel.getLabels();  
        for(int i = 0; i < labels.length; i++)  
        {  
            for (int j=0;j<labels[0].length;j++){

                r = labels[i][j].getBounds();  
                if(r.contains(p))  
                {  
                    if ( ((ImageIcon)labels[i][j].getIcon()).getImage() != null) {
                    selectedImage = ((ImageIcon)labels[i][j].getIcon()).getImage();  
                    MyPanel.setImage(selectedImage);  
                    labels[i][j].setIcon(null);
                    offset.x = p.x - r.x;  
                    offset.y = p.y - r.y;  
                    dragging = true;  
                    MyPanel.setOrigin(new Point(r.x, r.y));
                    break;  
                    }
                }  

            }

        }  
    }  

    public void mouseReleased(MouseEvent e)  
    {  
        Point p = e.getPoint();  
        JLabel[][] labels = MyPanel.getLabels();  
        for(int i = 0; i < labels.length; i++)  
        {  
            for (int j=0;j<labels[0].length; j++){

                r = labels[i][j].getBounds();  
                if(r.contains(p))  {

                    ImageIcon tmpIcon = new ImageIcon(selectedImage);
                    labels[i][j].setIcon(tmpIcon);
                    MyPanel.repaint();  
                    dragging = false;

                }
            }
        }

    }  

    public void mouseDragged(MouseEvent e)  
    {  
        if(dragging)  
        {  
            r.x = e.getX() - offset.x;  
            r.y = e.getY() - offset.y;  
            MyPanel.setOrigin(new Point(r.x, r.y));  
        }  
    }  
}  
  • 2
    Change `public void paint(Graphics g)` to `public void paintComponent(Graphics g)` (and change the call to `super` as well). – Andrew Thompson Dec 12 '12 at 14:01
  • thanks. Ive tried it already, but it causes the component to disappear during the dragging... – TerraNova993 Dec 12 '12 at 14:31
  • 2
    It disappears because you have opaque children components that paint themselves above. Otherwise, it runs correctly and smoothly on my computer. I tried with this image: "`http://i1195.photobucket.com/albums/aa398/EricMMann/Design1/Knight.png`" and it was ok. – Guillaume Polet Dec 12 '12 at 14:43
  • Why does that code not import anything from [`java.awt.dnd`](http://docs.oracle.com/javase/7/docs/api/java/awt/dnd/package-frame.html)? – Andrew Thompson Dec 12 '12 at 14:55
  • sorry, but when I try with this code: public void paintcomponent(Graphics g) { super.paintComponent(g); if(action.dragging) g.drawImage(image, p.x, p.y, this); }, the component dissapears and I don"t understand why. I should be missing something... – TerraNova993 Dec 12 '12 at 15:00
  • @Andrew Thompson: I found this code on the net to drag n drop components but I didn't look at java.awt.dnd – TerraNova993 Dec 12 '12 at 15:03

1 Answers1

3

+1 to AndrewThompson and GuillaumePolet comments. especially:

It disappears because you have opaque children components that paint themselves above.

to overcome this we dont need/want to override paintComponent(..) instead we want to override paintChildren(..) and call super.paintChildren(..) followed by our custom code. Thus all components will be drawn in call to super and our image will be drawn after, thus making it appear/visible above all others.

Replace the overridden paintComponent with below code and it will work:

@Override
protected void paintChildren(Graphics g) {
    super.paintChildren(g);

    if (action.dragging) {
        g.drawImage(image, p.x, p.y, null);//also notice i use null and not this, unless the class you are using extends ImageObserver no need for this
    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • 2
    See also this [example](http://stackoverflow.com/a/2562685/230513) and [variation](http://stackoverflow.com/a/2563350/230513). – trashgod Dec 12 '12 at 18:27
  • thanks!!! +1 it is working this way :-) But ... the component is still lagging ... maybe I could use an overridden paintComponent with a JLayeredPane ? – TerraNova993 Dec 12 '12 at 18:46
  • Its not lagging at all for me? No offence maybe PC a bit sluggish? But If you need to why not rather just draw the outline of the piece when dragging instead of the image itself? – David Kroukamp Dec 12 '12 at 18:47
  • My PC can't be sluggish!! it's a Linux !! (I'm joking ;-)) But I see a real difference of performance for instance if I set the JLabels to setOpaque(false) the image's movement is perfectly smooth. But if I put back the setOpaque(true) on the JLabels it's lagging. even with @Override paintChildren() – TerraNova993 Dec 12 '12 at 19:10