Home > Mobile >  How to make a JLabel became dragable?
How to make a JLabel became dragable?

Time:12-19

Guys I want to know if there is a way to make this arrow to be dragable just with X axis. I am using a null layout here, and this arrow is a jlabel that has been add into the jframe. Here is the image for more info. Thank you in advance.

enter image description here

CodePudding user response:

Doing this kind of thing with a JLabel isn't impossible, it's just, complicated.

Personally, I'd be tempted to just use a custom painted route, as it gives you all the control.

For example...

enter image description here

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.RoundRectangle2D;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() throws IOException {
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new GridBagLayout());
            add(new SlideToUnlock());
        }

    }

    public class SlideToUnlock extends JPanel {

        private String text;
        private Image indicatorImage;
        private Rectangle indicatorBounds;

        private Integer clickXOffset; // I can make it null and then ignore it
        private Integer dragX; // The x position of the drag

        public SlideToUnlock() throws IOException {
            indicatorImage = ImageIO.read(getClass().getResource("/images/ArrowRight.png"));
            setText("Slide to unlock");

            MouseAdapter mouseAdapter = new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    resetTimer();

                    Rectangle bounds = getIndiciatorImageBounds();
                    if (bounds.contains(e.getPoint())) {
                        clickXOffset = e.getPoint().x - bounds.x;
                    } else {
                        clickXOffset = null;
                    }
                    dragX = null;
                    repaint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    invalidate();
                    repaint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    dragX = e.getPoint().x;
                    if (didReachTheOtherSide()) {
                        // Notifiy some kind of observer
                    }
                    repaint();
                }
            };

            addMouseListener(mouseAdapter);
            addMouseMotionListener(mouseAdapter);
        }

        @Override
        public Dimension getPreferredSize() {
            FontMetrics fm = getFontMetrics(getFont());
            Image indicatorImage = getIndicatorImage();
            Insets insets = getInsets();

            int imageWidth = 0;
            int imageHeight = 0;

            if (indicatorImage != null) {
                imageWidth = indicatorImage.getWidth(this);
                imageHeight = indicatorImage.getHeight(this);
            }

            int height = Math.max(fm.getHeight(), imageHeight)
                      1 // Border
                      8; // Inner track

            int width = 1   8   fm.stringWidth(getText())   imageWidth;

            width  = insets.left   insets.right;
            height  = insets.top   insets.top;

            return new Dimension(width, height);
        }

        @Override
        public void invalidate() {
            super.invalidate();
            indicatorBounds = null;
            clickXOffset = null;
            dragX = null;
        }

        @Override
        public void revalidate() {
            super.revalidate();
            indicatorBounds = null;
            clickXOffset = null;
            dragX = null;
        }

        protected boolean didReachTheOtherSide() {
            Rectangle bounds = getIndiciatorImageBounds();

            return bounds.x   bounds.width >= getWidth() - 1;
        }

        protected Rectangle getIndiciatorImageBounds() {
            if (getParent() == null) {
                return null;
            }

            if (dragX == null && indicatorBounds != null) {
                return indicatorBounds;
            }

            Image indicatorImage = getIndicatorImage();
            int indicatorX = 1;
            int indicatorY = (getHeight() - indicatorImage.getHeight(this)) / 2;
            indicatorBounds = new Rectangle(indicatorX, indicatorY, indicatorImage.getWidth(this), indicatorImage.getHeight(this));

            if (dragX != null) {
                indicatorBounds.x = (indicatorBounds.x - clickXOffset)   dragX;

                if (indicatorBounds.x   indicatorBounds.width > (getWidth() - 1)) {
                    indicatorBounds.x = getWidth() - indicatorBounds.width - 1;
                } else if (indicatorBounds.x < 1) {
                    indicatorBounds.x = 1;
                }
            }

            return indicatorBounds;
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public Image getIndicatorImage() {
            return indicatorImage;
        }

        public void setIndicatorImage(Image indicatorImage) {
            this.indicatorImage = indicatorImage;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int cornerRadius = 16;

            paintText(g2d);
            paintOverlay(g2d);
            paintIndicator(g2d);

            g2d.setColor(getForeground());
            g2d.draw(new RoundRectangle2D.Double(0, 0, getWidth() - 1, getHeight() - 1, cornerRadius, cornerRadius));

            g2d.dispose();
        }

        protected void paintOverlay(Graphics2D g) {
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(getBackground());
            Rectangle bounds = getIndiciatorImageBounds();
            g2d.fillRect(1, 1, bounds.x   bounds.width, getHeight() - 2);
            g2d.dispose();
        }

        protected void paintText(Graphics2D g) {
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(getForeground());
            FontMetrics fm = g2d.getFontMetrics();
            String text = getText();
            int xPos = getWidth() - 1 - 4 - fm.stringWidth(text);
            int yPos = ((getHeight() - fm.getHeight()) / 2)   fm.getAscent();
            g2d.drawString(text, xPos, yPos);
            g2d.dispose();
        }

        protected void paintIndicator(Graphics2D g) {
            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle bounds = getIndiciatorImageBounds();

            g2d.translate(bounds.x, bounds.y);
            Image indicatorImage = getIndicatorImage();
            g2d.drawImage(indicatorImage, 0, 0, this);
            g2d.dispose();
        }

    }
}

Ok, so, that "works", it does the job, but it's missing something

  • Related