如何在同一个 class 中分别绘制 2d 图形和图像到同一个 JPanel

How to paint 2Dgraphics and images separately in the same class to the same JPanel

我有一个方法 (drawImages) 可以将缓冲图像的数组列表绘制到扩展的 JPanel。但是,它仅在调用另一个方法 (drawPerfectRect) 时在 paintComponent 方法中被调用。

此方法 (drawPerfectRect) 负责使用传递给它的坐标来使用用户单击的点绘制矩形。

基本上,我遇到的两个问题是:

  1. 直到用户单击并拖动创建一个矩形(希望在单击 selectDirectory (JButton) 后绘制图像)后,它才会绘制 bufferedimages 的数组列表。
  2. 它还会为每个后续绘制的矩形再次绘制缓冲图像。

bufferedimages好像只有在绘制矩形的时候才绘制。

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;

import com.sun.tools.internal.ws.wsdl.document.Import;
import net.coobird.thumbnailator.*;
import com.mortennobel.imagescaling.*;

import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.geom.RoundRectangle2D;
import java.io.IOException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.Timer;

public class ImportWorkspace extends JPanel{

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int x, y, x2, y2;
ArrayList<BufferedImage> thumbnailList = new ArrayList<BufferedImage>();
int ContentPanelWidth;
private boolean addThumbnails = false;

    public ImportWorkspace(){

    x = y = x2 = y2 = 0;
    setLayout(null);
    setBackground(Color.decode("#2a2e37"));
    setBounds(85, 0, screenSize.width-85, screenSize.height);
    //System.out.println("W: " + super.getWidth() + ", H: " + super.getHeight());
    ContentPanelWidth = getWidth();
    System.out.println(ContentPanelWidth);

        JLabel dataIcon =  new JLabel(new ImageIcon(new ImageIcon ("folder.png").getImage().getScaledInstance(256,256, Image.SCALE_DEFAULT)));
        dataIcon.setBounds((getWidth()/2)-128, (getHeight()/2)-200, 256, 256);
        add(dataIcon);

        JLabel askImport = new JLabel("No Data Files have been selected: To begin importing data please select a directory.");
        askImport.setFont(new Font("Helvetica", Font.PLAIN, 20));
        askImport.setForeground(Color.white);
        askImport.setBounds((getWidth()/2)-375, (getHeight()/2)+50, 750, 100);
        add(askImport);

        JButton selectDirectory = new JButton("Select Directory");
        selectDirectory.setBounds((getWidth()/2)-75, (getHeight()/2)+150, 150, 50); //+half of width or height
        add(selectDirectory);

        selectDirectory.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                removeAll();
                revalidate();
                repaint();
                setLayout(new FlowLayout(FlowLayout.LEFT));

                ImportingImages getImages = new ImportingImages();
                getImages.importFiles();

                File curDir = new File("");
                File[] files = curDir.listFiles();
                long noFiles = curDir.length();

                for (File f : files) {
                    String fileName = f.getName();
                    String hiddenFile = ".DS_Store";
                    if (fileName.equals(hiddenFile)){
                        //System.out.println("Do nothing");
                    } else {

                        String thumbnailPath = curDir + "/" + f.getName();
                        try {
                            BufferedImage thumbnailIcon = ImageIO.read(new File(thumbnailPath));
                            thumbnailList.add(thumbnailIcon);
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }

                    }
                }

                MyMouseListener listener = new MyMouseListener();
                addMouseListener(listener);
                addMouseMotionListener(listener);

                //DisplayImages(thumbnailList, ContentPanelWidth);
            }
        });
    }

        public void setStartPoint(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void setEndPoint(int x, int y) {
        x2 = (x);
        y2 = (y);
    }


    public void drawPerfectRect(Graphics g, int x, int y, int x2, int y2) {
        int px = Math.min(x,x2);
        int py = Math.min(y,y2);
        int pw = Math.abs(x-x2);
        int ph = Math.abs(y-y2);

        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int alpha = 100; // 127 50% transparent
        Color cyanTransparent = new Color(0,206,209, alpha);
        g2.setColor(cyanTransparent);
        g2.fillRoundRect(px, py, pw, ph, 5, 5);

        g2.setColor(Color.cyan);
        g2.setStroke(new BasicStroke(1));
        g2.drawRoundRect(px, py, pw, ph, 5, 5);

    }

    public void drawImages(Graphics g){
            int xSpacing = 10;
            int ySpacing = 20;
            int noImages = 0;
            for (BufferedImage thumbnail : thumbnailList){
                g.drawImage(thumbnail, xSpacing, ySpacing,null );
                if ((xSpacing+100) > (ContentPanelWidth-100)){
                    ySpacing = ySpacing + 77;
                    xSpacing = 10;
                } else{
                    xSpacing = xSpacing + 110;
                }
                noImages = noImages + 1;
                //System.out.println(noImages);
            }
    }

    class MyMouseListener extends MouseAdapter {

        public void mousePressed(MouseEvent e) {
            setStartPoint(e.getX(), e.getY());
        }

        public void mouseDragged(MouseEvent e) {
            setEndPoint(e.getX(), e.getY());
            revalidate();
            repaint();
        }

        public void mouseReleased(MouseEvent e) {
            setEndPoint(e.getX(), e.getY());
            revalidate();
            repaint();
        }
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        System.out.println(addThumbnails);
        drawImages(g2);
        drawPerfectRect(g2, x, y, x2, y2);  
    }
}

改进添加到selectDirectory按钮的动作监听器,如下:

  1. 删除动作侦听器中的 repaint() 调用(稍后会修复)。
  2. 每次按下按钮时都会清除 缩略图列表。即,动作侦听器中的 thumbnailList.clear()。这样,对于每个目录选择,只会显示最后导入的图像。
  3. 在按钮的动作侦听器中调用 repaint() for 循环之后将缩略图添加到列表中。这样,面板将在图像实际加载到列表后重新绘制(使用新图像)。

因此,ImportWorkspace构造函数可以这样写:

public ImportWorkspace(){

    x = y = x2 = y2 = 0;
    setLayout(null);
    setBackground(Color.decode("#2a2e37"));
    setBounds(85, 0, screenSize.width-85, screenSize.height);
    //System.out.println("W: " + super.getWidth() + ", H: " + super.getHeight());
    ContentPanelWidth = getWidth();
    System.out.println(ContentPanelWidth);

    JLabel dataIcon =  new JLabel(new ImageIcon(new ImageIcon ("folder.png").getImage().getScaledInstance(256,256, Image.SCALE_DEFAULT)));
    dataIcon.setBounds((getWidth()/2)-128, (getHeight()/2)-200, 256, 256);
    add(dataIcon);

    JLabel askImport = new JLabel("No Data Files have been selected: To begin importing data please select a directory.");
    askImport.setFont(new Font("Helvetica", Font.PLAIN, 20));
    askImport.setForeground(Color.white);
    askImport.setBounds((getWidth()/2)-375, (getHeight()/2)+50, 750, 100);
    add(askImport);

    JButton selectDirectory = new JButton("Select Directory");
    selectDirectory.setBounds((getWidth()/2)-75, (getHeight()/2)+150, 150, 50); //+half of width or height
    add(selectDirectory);

    selectDirectory.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {

            removeAll();
            revalidate();
            //repaint();           //Removed this line. It is not necessary in this place. Will be re-added AFTER the `for` loop below...
            thumbnailList.clear(); //Added this line.
            setLayout(new FlowLayout(FlowLayout.LEFT));

            ImportingImages getImages = new ImportingImages();
            getImages.importFiles();

            File curDir = new File("");
            File[] files = curDir.listFiles();
            long noFiles = curDir.length();

            for (File f : files) {
                String fileName = f.getName();
                String hiddenFile = ".DS_Store";
                if (fileName.equals(hiddenFile)){
                    //System.out.println("Do nothing");
                } else {

                    String thumbnailPath = curDir + "/" + f.getName();
                    try {
                        BufferedImage thumbnailIcon = ImageIO.read(new File(thumbnailPath));
                        thumbnailList.add(thumbnailIcon);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }

                }
            }

            repaint(); //Added this line! Now the newly loaded images shall be painted.

            MyMouseListener listener = new MyMouseListener();
            addMouseListener(listener);
            addMouseMotionListener(listener);

            //DisplayImages(thumbnailList, ContentPanelWidth);
        }
    });
}