Search code examples
javaimageswingdraggable

How to add multiple draggable images to a JFrame in Java?


I have got questions about my java code. My goal is to make a JFrame, in which I can have multiple draggable images which snap to a grid.

The Problems:

I can add only one draggable image. The dragging and snapping to grid works fine. As soon as I try to add more draggable images to the JFrame (Which i try to do near the bottom of the MainScreen.java file), it displays only the last one I added.

The Code:

MainScreen.java

package systematics;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class MainScreen extends JFrame {

    private static Image img = Toolkit.getDefaultToolkit().getImage("C:/Users/lenar_000/Pictures/splitter skin.png");
    public static JFrame main = new JFrame();
    public static Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
    public static JPanel content = new JPanel();
    public static JMenuBar menubar = new JMenuBar();
    public static ArrayList<JMenuItem> menuitem = new ArrayList<JMenuItem>();
    public static ArrayList<JMenu> menu = new ArrayList<JMenu>(20);
    public static ArrayList<JComponent> gates = new ArrayList<JComponent>();
    public static componentGate gate = new componentGate(0, 1, 1, null);
    public static int imageWidth = 60, imageHeight = 60, imageX, imageY, gridw = 10, gridh = 10;
    public static DragImage componentimage = new DragImage(img, 300, 300, 200, 200);
    public static DragImage componentimage1 = new DragImage(img, 50, 50, 50, 50);

    public static JFrame createmain() {     
        //location and size of the window
        main.setJMenuBar(createmenu());
        main.setExtendedState(JFrame.MAXIMIZED_BOTH); 
        int w = (int) screensize.getWidth();
        int h = (int) screensize.getHeight();
        main.setSize((int) (w / 2), (int) (h / 2));
        int w1 = (int) main.getSize().getWidth();
        int h1 = (int) main.getSize().getHeight();
        int x = (screensize.width-w1)/2;
        int y = (screensize.height-h1)/2;
        main.setLocation(x, y);

        //other stuff
        main.setVisible(true);
        main.setTitle("systematic");
        main.setDefaultCloseOperation(EXIT_ON_CLOSE);
        return main;
    }

    //unused
    public static JPanel createcontent() {
        content.setBackground(Color.DARK_GRAY);
        content.setVisible(true);
        content.setOpaque(true);
        return content ;
    }

    //to make the menubar
    public static JMenuBar createmenu() {

        //add the items to the arrays which hold the menu's and the menuitems
        menu.add(0, new JMenu());
        menu.add(1, new JMenu());
        menu.add(2, new JMenu());
        menuitem.add(0, new JMenuItem());
        menuitem.add(1, new JMenuItem());
        menuitem.add(2, new JMenuItem());

        //some settings for the menubar
        menubar.setOpaque(true);
        menubar.setVisible(true);
        menubar.setBackground(new Color(255, 255, 255));



        //adding the first menu which contains a submenu
        menu.get(0).setText("File");
        menu.get(0).setOpaque(true);
        menu.get(0).setBackground(new Color(255, 255, 255));
        menubar.add(menu.get(0), 0);

        menuitem.get(0).setText("new file");
        menuitem.get(0).setToolTipText("creates and opens a new file");
        menuitem.get(0).setOpaque(true);
        menuitem.get(0).setBackground(new Color(255, 255, 255));
        menu.get(0).add(menuitem.get(0), 0);



        //adding the second menu which contains a submenu
        menu.get(1).setText("Toolbars");
        menu.get(1).setOpaque(true);
        menu.get(1).setBackground(new Color(255, 255, 255));
        menubar.add(menu.get(1), 1);

        menuitem.get(1).setText("components");
        menuitem.get(1).setToolTipText("toggle for the components toolbar");
        menuitem.get(1).setOpaque(true);
        menuitem.get(1).setBackground(new Color(255, 255, 255));
        menu.get(1).add(menuitem.get(1), 0);



        //adding the third menu which contains a submenu
        menu.get(2).setText("Toolbars");
        menu.get(2).setOpaque(true);
        menu.get(2).setBackground(new Color(255, 255, 255));
        menubar.add(menu.get(2), 2);

        menuitem.get(2).setText("components");
        menuitem.get(2).setToolTipText("toggle for the components toolbar");
        menuitem.get(2).setOpaque(true);
        menuitem.get(2).setBackground(new Color(255, 255, 255));
        menu.get(2).add(menuitem.get(2), 0);


        return menubar;
    }


    public static void main(String[] args) {
        createmain();
        //creategrid();
        main.getContentPane().add(componentimage, 0);
        main.getContentPane().add(componentimage1, 1);

    }

    //unused
    private static void creategrid() {
        DrawingLine line1 = new DrawingLine();
        main.getContentPane().add(line1,-1);

    }

    private static final long serialVersionUID = 1L;
}

DragImage

package systematics;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;

public class DragImage extends JComponent implements MouseMotionListener, MouseListener {

    private static final long serialVersionUID = 1L;
    private int imageWidth, imageHeight, gridw = 50, gridh = 50, imageX/* = gridw / 2 - imageWidth / 2*/, imageY/* = gridh / 2 - imageHeight / 2*/, onObject, checked;

    private Image image;

    DragImage(Image i, int imgX, int imgY, int imagewidth, int imageheight) {
        this.imageWidth = imagewidth;
        this.imageHeight = imageheight;
        this.imageX = imgX;
        this.imageY = imgY;
        this.image = i.getScaledInstance(imageWidth, imageHeight, 0);
        addMouseMotionListener(this);
        addMouseListener(this);
    }

    public void mouseDragged(MouseEvent e) {
        //first checking if "onObject" is 1 to make sure that the mouse is on the image when it started dragging
        if(this.onObject == 1) {
            if((int) (Math.floor(e.getX() / this.gridw) * this.gridw + (this.gridw / 2) - (this.imageWidth / 2)) != this.imageX || (int) (Math.floor(e.getY() / this.gridh) * this.gridh + (this.gridh / 2) - (this.imageHeight / 2)) != this.imageY) {
                this.imageX = (int) (Math.floor(e.getX() / this.gridw) * this.gridw + (this.gridw / 2) - (this.imageWidth / 2));
                this.imageY = (int) (Math.floor(e.getY() / this.gridh) * this.gridh + (this.gridh / 2) - (this.imageHeight / 2));
                this.repaint();
            }
        }
    }

    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        //repainting the object that you are dragging at the new location, which is determined by the math in "mouseDragged"
        g2.drawImage(this.image, this.imageX, this.imageY, this);
    }

    @Override
    public void mousePressed(MouseEvent e) {
        // TODO Auto-generated method stub
        //this checks if the mouse is on the object when you start dragging, for the method mouseDragged runs when you drag, regardless of the mouse position
        System.out.println("");
        System.out.println("pressed, checked is now: " + this.checked);
        if(this.checked == 0 && (e.getX() >= this.imageX) && (e.getY() >= this.imageY) && (e.getX() <= this.imageX + (this.imageWidth)) && (e.getY() <= this.imageY + (this.imageHeight))) {
            this.onObject = 1;
            System.out.println("onObject: " + this.onObject);
        }
        //checked is a parameter, which is used to make sure that this method doesn't run all the time, but only when the mouse started dragging
        this.checked = 1;
        System.out.println("checked: " + this.checked);
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub
        System.out.println("");
        System.out.println("released, checked is now: " + this.checked);
        this.onObject = 0;
        System.out.println("onObject: " + this.onObject);
        //setting checked to 0 when the mouse stops dragging, so when it starts dragging, it can check wether the mouse is on the image yes or no
        checked = 0;
        System.out.println("checked: " + this.checked);
    }


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

    }

    @Override
    public void mouseClicked(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

    }
}

Btw, I'm quite proud of that math to do the snapping to grid :)

Any solution is highly appreciated


Solution

  • The default layout of JFrame's contentPane is BorderLayout. You are doing

        main.getContentPane().add(componentimage, 0);
        main.getContentPane().add(componentimage1, 1);
    

    the second parameter should be one of BorderLayout.CENTER, BorderLayout.NORTH, etc.

    But your other problem is that DragImage.getPreferredSize() is going to return (0,0) since you haven't added anything to it. You need to override getPreferredSize or use setPreferredSize on your DragImages for them to be allotted space in the ContentPane.