0

I want to be able to click on a JTextArea and drag it around my JPanel. I'm not sure the method on doing so. What I'm trying to do is change the x,y coordinates of the JTextArea as it is dragged, I'm not dragging a JTextArea above or below another. Just around on the screen, similar to moving Text Boxes in a program like Microsoft PowerPoint

The only method I can think of is using a MouseListener but I'm wondering if there is an easier way to implement it other than detecting a hover/press/drag on the JTextArea. Any ideas on how I can start?

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextArea;

public class UMLEditor {

    public static void main(String[] args) {
        JFrame frame = new UMLWindow();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(30, 30, 1000, 700);
        frame.getContentPane().setBackground(Color.white);
        frame.setVisible(true);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class UMLWindow extends JFrame {
    Canvas canvas = new Canvas();

    private static final long serialVersionUID = 1L;

    public UMLWindow() {
        addMenus();
    }

    public void addMenus() {

        getContentPane().add(canvas);

        JMenuBar menubar = new JMenuBar();

        JMenuItem newTextBox = new JMenuItem("New Text Box");
        newTextBox.setMnemonic(KeyEvent.VK_E);
        newTextBox.setToolTipText("Exit application");
        newTextBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                canvas.addTextBox();
            }
        });

        menubar.add(newTextBox);

        setJMenuBar(menubar);

        setSize(300, 200);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
}

class Canvas extends JPanel {

    JTextArea commentTextArea = new JTextArea(10, 10);

    public Canvas() {
        this.setOpaque(true);
        MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
        addMouseListener(myMouseAdapter);
        addMouseMotionListener(myMouseAdapter);
    }

    public void addTextBox() {

        commentTextArea.setLineWrap(true);
        commentTextArea.setWrapStyleWord(true);
        commentTextArea.setVisible(true);
        commentTextArea.setLocation(0, 0);
        this.add(commentTextArea);
        commentTextArea.setBounds(0, 0, 100, 100);

        revalidate();
        repaint();
    }

    class MyMouseAdapter extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {

        }

        @Override
        public void mouseDragged(MouseEvent e) {

        }

        @Override
        public void mouseMoved(MouseEvent e) {

        }
    }
}
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Harry
  • 772
  • 10
  • 32
  • 1
    Beware of mixing heavy (AWT) and light (Swing) weight components, there are z-ordering issues – MadProgrammer Oct 28 '14 at 01:48
  • All `JTextComponent`s have a concept of "drag" which you don't want to mess with, instead, you should provide an area "around" the component from within which the user can click and drag, which will then allow them top position the component – MadProgrammer Oct 28 '14 at 01:49
  • I have tried to create a rectangle using the coordinates/dimensions of the JTextArea by this: `MouseMoved` -> `if(rectangle.contains(e.getPoint()) { System.out.println("Testing hit") } ` and it isn't detecting the "hover" over the JTextArea. Is this conceptually what you meant? – Harry Oct 28 '14 at 01:51
  • Not over the text area, around it... – MadProgrammer Oct 28 '14 at 01:56
  • I just tried this and it works. Is this the best I can do? I can't check if the JTextArea itself contains the point? – Harry Oct 28 '14 at 01:57
  • I already gave you an answer in one of your previous questions that showed how you can drag any component around the screen. – camickr Oct 28 '14 at 01:58
  • I wouldn't, as I said, `JTextComponent`s have functionality that allows them to drag and select text, you don't want to compete or upset this functionality – MadProgrammer Oct 28 '14 at 01:58
  • @camickr in which question...? – Harry Oct 28 '14 at 02:00
  • @MadProgrammer I see what you are saying now. What type of functionality do JTextComponents provide? And why can't (or shouldn't) they be used? – Harry Oct 28 '14 at 02:01
  • Well you made a comment that you would look at the code. Apparently you didn't, so I'll let you search your previous questions. – camickr Oct 28 '14 at 02:05
  • @camickr I'll have to double check...must be going crazy lol thanks – Harry Oct 28 '14 at 02:06

1 Answers1

3

You don't really want to try and "drag" on JTextComponents, they already have functionality enabled which allows the user to click and drag to highlight text, you really don't want to be competing within this.

Instead, you want to define a "hot zone" area around the component which would allow you "highlight" the component in some and allow the user to drag the component via it.

For example...

Move Handel

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class DragMe {

    public static void main(String[] args) {
        new DragMe();
    }

    public DragMe() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JTextArea ta = new JTextArea(10, 20);
                ta.setText("Bananas in pajamas");
                JScrollPane sp = new JScrollPane(ta);

                DragProxyPane proxy = new DragProxyPane(sp);
                proxy.setSize(proxy.getPreferredSize());
                proxy.setLocation(100 - proxy.getWidth() / 2, 100 - proxy.getHeight()/ 2);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setContentPane(new JPanel() {
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(300, 300);
                    }
                });
                frame.add(proxy);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class DragProxyPane extends JPanel {

        public static final int BUFFER_ZONE = 10;

        private boolean mouseInHouse;
        private JComponent component;

        private List<HotZone> hotZones;

        public DragProxyPane(JComponent comp) {
            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mouseEntered(MouseEvent e) {
                    mouseInHouse = true;
                    repaint();
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    mouseInHouse = false;
                    repaint();
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                    Cursor cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
                    for (HotZone hz : hotZones) {
                        if (hz.getBounds(getSize()).contains(e.getPoint())) {
                            cursor = hz.getCursor();
                            break;
                        }
                    }
                    setCursor(cursor);
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);

            setOpaque(false);
            setLayout(new BorderLayout());
            add(comp);

            setBorder(new EmptyBorder(BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE));

            hotZones = new ArrayList<>(8);
            // Top left, middle, right
            hotZones.add(new HotZone(0f, 0f, Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)));
            hotZones.add(new HotZone(0.5f, 0f, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)));
            hotZones.add(new HotZone(1f, 0f, Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)));
            // Left, right
            hotZones.add(new HotZone(0f, 0.5f, Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)));
            hotZones.add(new HotZone(1f, 0.5f, Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)));
            // Bottom left, middle, right
            hotZones.add(new HotZone(0f, 1f, Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)));
            hotZones.add(new HotZone(0.5f, 1f, Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)));
            hotZones.add(new HotZone(1f, 1f, Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)));

        }


        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (mouseInHouse) {
                g2d.setColor(Color.BLACK);
                for (HotZone hotZone : hotZones) {
                    g2d.draw(hotZone.getBounds(getSize()));
                }
            }
            g2d.dispose();
        }

        public class HotZone {

            private float x, y;
            private Cursor cursor;

            public HotZone(float x, float y, Cursor cursor) {
                this.x = x;
                this.y = y;
                this.cursor = cursor;
            }

            public Cursor getCursor() {
                return cursor;
            }

            public Rectangle getBounds(Dimension size) {

                return getBounds(size.width - 1, size.height - 1);

            }

            public Rectangle getBounds(int width, int height) {

                int halfBuffer = BUFFER_ZONE / 2;

                float xPos = (width * x) - halfBuffer;
                float yPos = (height * y) - halfBuffer;

                xPos = Math.min(Math.max(0, xPos), width - BUFFER_ZONE);
                yPos = Math.min(Math.max(0, yPos), height - BUFFER_ZONE);

                return new Rectangle(Math.round(xPos), Math.round(yPos), BUFFER_ZONE, BUFFER_ZONE);

            }

        }

    }

}

This sets up a simple proxy component which acts as the hot zone manager, detecting the mouse coming into or out of it and updating the cursor based on its location within in it, but it does not disrupt the normal operations of the component.

Now, this example doesn't drag, sorry, you have plenty of other examples which should be able to get you over the line, but, you could simply add a MouseListener/MouseMoitionListener to the proxy to detect when the user drags, but you will need to add some more functionality to it to determine what that drag actually means (resize or move) ;)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • don't be sorry for not completing the entire thing! This is just what I needed to get started. Thanks a ton – Harry Oct 28 '14 at 02:37
  • Equally, you could self contain the component, keeping the dragging/resizing login within the proxy, this way, you could just drop a bunch of these on the screen and let them work themselves out ;) – MadProgrammer Oct 28 '14 at 02:39
  • What do you mean by "self contain the component" ? – Harry Oct 28 '14 at 02:51
  • It's functionality is self contained, you don't need to add more functionality to it (like adding mouse listeners to perform the drag/sizing operations), because the component is capable of doing it all itself... – MadProgrammer Oct 28 '14 at 02:52
  • Gotchya, looking into implementing. Thanks again – Harry Oct 28 '14 at 02:55