Search code examples
javaswinggraphics2d

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


I have a method (drawImages) that draws an arraylist of bufferedimages to the extended JPanel. However, it is only being called in the paintComponent method when another method (drawPerfectRect) is called.

This method (drawPerfectRect) is responsible for using co-ordinates passed to it to draw a rectangle using points clicked on by the user.

Essentially, the two problems I am having are:

  1. It does not paint the arraylist of bufferedimages until the user clicks and drags to create a rectangle (want the images to be painted at after selectDirectory (JButton) is clicked).
  2. It also paints the bufferedimages again for every subsequent rectangle that is painted.

It seems that the bufferedimages are only painted when the rectangles are painted.

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

Solution

  • Improve the action listener added to the selectDirectory button, as follows:

    1. Remove the repaint() call inside the action listener (will fix it later on).
    2. Clear the list of thumbnails each time the button is pressed. That is, thumbnailList.clear() inside the action listener. This way, only the last imported images will be displayed for each directory selection.
    3. Call repaint() inside the button's action listener after the for loop which adds the thumbnails in the list. This way, the panel will be repainted (with the new images) after the images are actually loaded into the list.

    As a result, the ImportWorkspace constructor can be written as follows:

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