Mouse Goes behind part of the panel where it has been drawn on

56 Views Asked by At

So I am currently making a canvas painter in the style of Microsoft paint in Java. One of the features I was currently working on is the color picker. Now I got it to change the icon cursor but the issue comes with its implementation. I wish to get the color of the pixel that the cursor clicked on (which I already got it working). However, When I try to hover the curser over something I drew on the panel, the mouse goes behind the drawing that I made. To better explain this, I have added a Gif of the aforementioned issue.

Here is the code for my program

Main.java

import javax.swing.JPanel;

public class Main {

    public static void main(String[] args) {
        new Controller(new View(),new Model());

    }

}

View.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;

import javax.imageio.ImageIO;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SpringLayout;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.PanelUI;

import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.net.URL;
import java.nio.channels.NonReadableChannelException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import org.kordamp.ikonli.swing.FontIcon;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.GridBagConstraints;

public class View extends JFrame implements MouseListener{
    protected static int imgNum = new File("src//imgs").listFiles().length;
    private Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    private double width = screenSize.getWidth(), height = screenSize.getHeight();
    protected static JPanel panel = new JPanel();
    private JPanel buttonsPanel = new JPanel(), colPre = new JPanel();
    private static JLabel[] toolsButtonSetIcons = new JLabel[imgNum];
    private JMenuBar menuBar = new JMenuBar();
    private ImageIcon[] icons = new ImageIcon[imgNum];
    protected static URL[] iconURLs = new URL[imgNum];
    private JMenu menu = new JMenu("File"), edit = new JMenu("Edit");
    protected JMenuItem picImport = new JMenuItem("Import Picture"), pencilSizeChangeMenu = new JMenuItem("Change Pen Size");
    private GridBagConstraints gbc = new GridBagConstraints();
    private JSlider redSlider,greenSlider,blueSlider;
    URL[] tempURLArr;
    private static String[] toolNameStrings = { "Eraser", "Cutter", "Pencil", "Color Chooser", "Color Picker",
            "Transform", "Picture", "Color Slider","Move" };
    JLabel imgLabel;
    
    public View() {
    }

    public void setupDisplay() {
        this.setSize(new Dimension((int) width - 20, (int) height - 60));
        this.setTitle("Canvas Painter");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setResizable(false);
        this.setLocationRelativeTo(null);
        this.add(panel);
        this.add(buttonsPanel, BorderLayout.WEST);
        this.setJMenuBar(menuBar);
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                | UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        menu.add(picImport);
        menuBar.add(menu);
        menuBar.add(edit);
        buttonsPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        
        setupToolButtonSet();
        new Controller().setupPicImportMenuAction(picImport, panel,imgLabel);
        System.out.printf("JFrame width: %d and height: %d\n", this.getWidth(), this.getHeight());
        this.setVisible(true);
    }

    private void setupToolButtonSet() {
        buttonsPanel.setPreferredSize(new Dimension(150, 100));

        System.out.println(imgNum);
        for (int i = 0; i < imgNum; i++) {
            // buttonsPanel.add(Box.createRigidArea(new Dimension(5, 35)));
            iconURLs[i] = getClass().getResource(String.format("./imgs/icon%d.png", i));
            System.out.println(String.format("./imgs/icon%d.png", i));
            icons[i] = new ImageIcon(
                    new ImageIcon(iconURLs[i]).getImage().getScaledInstance(20, 20, Image.SCALE_DEFAULT));
            toolsButtonSetIcons[i] = new JLabel(icons[i]);
            toolsButtonSetIcons[i].setToolTipText(toolNameStrings[i]);
            buttonsPanel.add(toolsButtonSetIcons[i]);

        }

    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    protected static JLabel[] getLabelSet() {
        return toolsButtonSetIcons;
    }

    protected static String[] getLabelNameArray() {
        return toolNameStrings;
    }
    
    protected static URL[] getURLArray() {return iconURLs;}

    protected void displayColorSliderDialogue() {
        JPanel colorDialogPanel = new JPanel(), westColorDialoguePanel = new JPanel(), colorPreviewPanel = new JPanel();
        JButton colorDialogValidateButton = new JButton("Ok");
        JDialog colorDialog = new JDialog(this, "Color Customization");
        JSlider rSlider = new JSlider(0, 255), gSlider = new JSlider(0, 255), bSlider = new JSlider(0, 255);
        colorDialog.setSize(new Dimension(400, 240));
        colorDialog.add(westColorDialoguePanel, BorderLayout.WEST);
        colorDialog.add(colorPreviewPanel, BorderLayout.CENTER);
        colorDialog.add(colorDialogPanel, BorderLayout.SOUTH);
        westColorDialoguePanel.add(Box.createRigidArea(new Dimension(5, 5)));
        westColorDialoguePanel.setLayout(new BoxLayout(westColorDialoguePanel, BoxLayout.Y_AXIS));
        westColorDialoguePanel.add(new JLabel("R"));
        westColorDialoguePanel.add(rSlider);
        westColorDialoguePanel.add(Box.createRigidArea(new Dimension(5, 20)));
        westColorDialoguePanel.add(new JLabel("G"));
        westColorDialoguePanel.add(gSlider);
        westColorDialoguePanel.add(Box.createRigidArea(new Dimension(5, 20)));
        westColorDialoguePanel.add(new JLabel("B"));
        westColorDialoguePanel.add(bSlider);
        colorDialogPanel.add(colorDialogValidateButton);
        colorPreviewPanel.setBackground(new Color(rSlider.getValue(), gSlider.getValue(), bSlider.getValue()));
        new Controller().setupColorChangeDialogAction(rSlider,gSlider,bSlider,colorDialogValidateButton,colorPreviewPanel);
        colorDialog.setLocationRelativeTo(null);
        colorDialog.setVisible(true);
        colorDialog.setResizable(false);
        colorDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    }

    protected JSlider getRSlider() {return redSlider;}
    protected JSlider getGSlider() {return greenSlider;}
    protected JSlider getBSlider() {return blueSlider;}
    protected JPanel getColPrevLab() {return colPre;}
    protected ImageIcon [] getIconArray() {return icons;}

    private class Panel extends JPanel {
        
    }
}

Controller.java

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.TimerTask;
import java.awt.event.MouseListener;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Robot;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.plaf.ColorUIResource;
import javax.swing.text.AttributeSet.ColorAttribute;
import java.awt.MouseInfo;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Toolkit;

/**
 * 
 * @author Malik
 *
 */
public class Controller extends View implements MouseListener, MouseMotionListener {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Graphics g;
    private static Color drawColor;
    private JLabel[] buttonLabels = getLabelSet();
    private String[] labelNameStrings = getLabelNameArray();
    private URL[] urlArray = getURLArray();
    private final int ERASER = 0, CUTTER = 1, PENCIL = 2, COLOR_CHOOSER = 3, COLOR_PICKER = 4, TRANSFORM = 5,
            PICTURE = 6, COLOR_SLIDER = 7;
    private final Color defaultColor = new Color(0, 0, 0);
    private static boolean colorChanged = false;
    private String currentTool = "pencil";
    private JSlider rSlider = super.getRSlider(), gSlider = super.getGSlider(), bSlider = super.getBSlider();
    private JPanel colPreview = super.getColPrevLab();
    private JLabel imgLb;
    private Image image;

    public Controller(View v, Model m) {
        System.out.println("inside controller");
        v.setupDisplay();
        setLabelVisibility(buttonLabels);
        View.panel.addMouseListener(this);
        View.panel.addMouseMotionListener(this);

        for (int i = 0; i < buttonLabels.length; i++)
            buttonLabels[i].addMouseListener(this);
    }

    public Controller() {

    }

    @Override
    public void mouseClicked(MouseEvent e) {

        for (int i = 0; i < buttonLabels.length; i++) {

            if (e.getSource() == buttonLabels[COLOR_CHOOSER]) {
                // g.setColor();
                System.out.printf("You clicked: %s\n", labelNameStrings[COLOR_CHOOSER]);
                drawColor = JColorChooser.showDialog(this, "Select a color", Color.RED);
                colorChanged = true;
                break;
            }

            if (e.getSource() == buttonLabels[ERASER]) {
                currentTool = "eraser";
                System.out.printf("You clicked: %s\n", labelNameStrings[COLOR_CHOOSER]);
                break;
            }

            if (e.getSource() == buttonLabels[PENCIL]) {
                currentTool = "pencil";
                super.panel.setCursor(null);
                System.out.printf("You clicked: %s\n", labelNameStrings[PENCIL]);
                break;
            }

            if (e.getSource() == buttonLabels[COLOR_SLIDER]) {
                currentTool = "Color Slider";
                super.displayColorSliderDialogue();
                System.out.printf("You clicked: %s\n", labelNameStrings[COLOR_SLIDER]);
                break;
            }

            if (e.getSource() == buttonLabels[COLOR_PICKER]) {
                currentTool = "Color Picker";
                // System.out.println(urlArray[0].toString());
                System.out.printf("You clicked: %s", labelNameStrings[COLOR_PICKER]);
                changeCursor(super.panel, buttonLabels[COLOR_PICKER], urlArray[COLOR_PICKER]);
                super.panel.addMouseListener(new MouseListener() {

                    @Override
                    public void mouseClicked(MouseEvent e) {
                        int xValue = MouseInfo.getPointerInfo().getLocation().x;
                        int yValue = MouseInfo.getPointerInfo().getLocation().y;
                        Robot robot;
                        try {
                            robot = new Robot();
                            Color color = robot.getPixelColor(xValue, yValue);
                            System.out.println(color);
                            panel.revalidate();
                        } catch (AWTException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }
                        
                    }

                    @Override
                    public void mousePressed(MouseEvent e) {
                        // TODO Auto-generated method stub
                        
                    }

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        // TODO Auto-generated method stub
                        
                    }

                    @Override
                    public void mouseEntered(MouseEvent e) {
                        // TODO Auto-generated method stub
                        
                    }

                    @Override
                    public void mouseExited(MouseEvent e) {
                        // TODO Auto-generated method stub
                        
                    }
                    
                });
                break;
            }

        }

        // View.panel.repaint();

    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (e.getSource() == View.panel && currentTool == "pencil") {
            g = View.panel.getGraphics();
            if (colorChanged == false)
                g.setColor(defaultColor);
            else
                g.setColor(drawColor);

            g.fillOval(e.getX() - 15, e.getY() - 20, 30, 30);
            System.out.println("Test");
            mouseDragged(e);

        }

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        for (int i = 0; i < buttonLabels.length; i++) {
            buttonLabels[i].setOpaque(true);
            if (e.getSource() == buttonLabels[i]) {
                buttonLabels[i].setBackground(Color.GRAY);
            }
        }

    }

    @Override
    public void mouseExited(MouseEvent e) {
        for (int i = 0; i < buttonLabels.length; i++) {
            if (e.getSource() == buttonLabels[i] && buttonLabels[i].getBackground() == Color.GRAY)
                buttonLabels[i].setBackground(new JButton().getBackground());
        }

    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (e.getSource() == View.panel && currentTool == "pencil") {
            g = View.panel.getGraphics();
            if (colorChanged == false)
                g.setColor(defaultColor);
            else
                g.setColor(drawColor);
            g.fillOval(e.getX() - 15, e.getY() - 20, 30, 30);
            System.out.println("Test");
        }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    private void setLabelVisibility(JLabel[] labelArray) {
        for (int i = 0; i < labelArray.length; i++)
            labelArray[i].setOpaque(true);
    }

    public static void setColor(Color c) {
        colorChanged = true;
        drawColor = c;
    }

    public void setupColorChangeDialogAction(JSlider r, JSlider g, JSlider b, JButton confirmBtn, JPanel colPreview) {
        r.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                colPreview.setBackground(new Color(r.getValue(), g.getValue(), b.getValue()));
            }
        });
        g.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                colPreview.setBackground(new Color(r.getValue(), g.getValue(), b.getValue()));
            }
        });
        b.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                colPreview.setBackground(new Color(r.getValue(), g.getValue(), b.getValue()));
            }
        });
        confirmBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                colPreview.setBackground(new Color(r.getValue(), g.getValue(), b.getValue()));
                Controller.setColor(new Color(r.getValue(), g.getValue(), b.getValue()));
                dispose();
            }

        });
    }

    public void setupPicImportMenuAction(JMenuItem picImportButton, JPanel panel, JLabel imgLbl) {
        picImportButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JFileChooser jfc = new JFileChooser();
                FileNameExtensionFilter pngOnly = new FileNameExtensionFilter(".png", "png");
                FileNameExtensionFilter jpegOnly = new FileNameExtensionFilter(".jpg", "jpg");
                jfc.addChoosableFileFilter(pngOnly);
                jfc.addChoosableFileFilter(jpegOnly);

                jfc.setAcceptAllFileFilterUsed(false);
                int response = jfc.showOpenDialog(null);
                if (response == JFileChooser.APPROVE_OPTION) {

                    try {
                        BufferedImage ii = ImageIO.read(new FileInputStream(jfc.getSelectedFile().getAbsolutePath()));
                        addImageToCanvas(panel, ii, imgLbl);
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                    System.out.println(jfc.getSelectedFile().getAbsolutePath());

                }
            }

        });
    }

    protected void addImageToCanvas(JPanel panel, BufferedImage bi, JLabel label) {
        label = new JLabel(new ImageIcon(bi));
        imgLabel = label;
        panel.add(label);
        panel.revalidate();
        label.setOpaque(true);
    }


    private void changeCursor(JPanel panel, JLabel newCursorImageLabel, URL iconURL) {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        image = toolkit.getImage(iconURL);
        System.out.println("\ninside changeCursor  " + iconURL.toString());
        panel.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(0, 0), "img"));
    }

    public void getClickedComponentColor() {

    }

    private class drag {

    }

    private class drop {

    }
}

Model.java


public class Model {

}

I have also provided a zip file containing the entire project. The reason for providing this zip file is because my code requires the images that are located in a folder inside the src folder.

If anyone could help me with the issue regarding the mouse going behind the part of screen that has been drawn on that would be much appreciated

1

There are 1 best solutions below

0
On

I also believe the cursor is on top but black on black. Therefore I see two ways out of this:

  • Surround your shape with a thin line of white pixels so you can see the cursor regardless of a dark or light background

  • configure your cursor not to be black/transparent on whatever.Instead make the black pixels just 'invert' the background. I guess this is an XOR operation instead of an overwrite