0

我正在尝试设置在 Jlabels 网格上拖动图像。它工作正常,但图像“刷新”,有时落后于鼠标。

有没有办法改善这一点并获得完美“平滑”的图像移动?

编辑:好的,感谢 Andrew Thompson 的建议,我将paint() 方法更新为paintComponent()。但是现在为什么我拖动它时我的组件消失了?我可能在这里遗漏了一些东西......

EDIT2:为什么会出现以下行为:使用 paint() 方法时,组件显示在 JLabels 之上。但是当使用paintComponent() 时,组件会被不透明的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));  
        }  
    }  
}  
4

1 回答 1

3

+1 对 AndrewThompson 和 GuillaumePolet 的评论。尤其:

它消失了,因为您有不透明的子组件在上面绘制自己。

为了克服这个问题,我们不需要/想要覆盖,paintComponent(..)而是我们想要覆盖paintChildren(..)并调用super.paintChildren(..)我们的自定义代码。因此,所有组件都将在调用中绘制super,我们的图像将在之后绘制,从而使其在所有其他组件之上出现/可见。

用下面的代码替换覆盖paintComponent,它将起作用:

@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
    }
}
于 2012-12-12T18:10:40.413 回答