0

I have a JComponent, specifically a JLabel, that I want to render above all other components in my UI. I've made it draggable via this code, and I'd like it to render above everything else in the UI while being dragged.

I've attempted to use a JLayeredPane, but I couldn't get it to work with my UI, which is huge and complicated. Ideally there's some sort of solution that I can simply implement in the component's paint(Graphics) method.

Andrej Istomin
  • 2,527
  • 2
  • 15
  • 22
ix0rai
  • 37
  • 1
  • 8
  • 3
    I’d consider looking into using the “glassPane” – MadProgrammer Jan 04 '23 at 04:01
  • 2
    *I'd like it to render above everything else in the UI while being dragged.* - Check out: https://stackoverflow.com/questions/6811247/drawing-in-jlayeredpane-over-exising-jpanels/6811800#6811800 for an example that uses a JLayeredPane to drag a JLabel around a chess board. – camickr Jan 04 '23 at 04:40
  • that question is a start, but I'm having issues with a. setting the correct position while dragging and b. adding to the correct panel after dragging completes – ix0rai Jan 05 '23 at 03:54
  • the glass pane seems promising though! I'll look into it tomorrow – ix0rai Jan 05 '23 at 03:55

1 Answers1

0

solved this myself through the usage of a glass pane! this code should work in nearly every case, the only issue I've found is that the mouse/component position may not be exactly synced if the user has a taskbar position other than bottom.

thanks to https://stackoverflow.com/users/992484/madprogrammer for suggesting I use swing's glass pane to fix it.

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class DraggableLabel extends JLabel {
    private JComponent initialParent;

    public DraggableLabel(String text) {
        super(text);
        this.setOpaque(false);

        this.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // no-op
            }

            @Override
            public void mousePressed(MouseEvent e) {
                // save parent for re-addition after dragging is finished
                DraggableLabel.this.initialParent = (JComponent) DraggableLabel.this.getParent();

                // configure object to be on the glass pane instead of its former pane
                DraggableLabel.this.setVisible(false);
                JPanel glassPane = (JPanel) SwingUtilities.getRootPane(DraggableLabel.this).getGlassPane();
                DraggableLabel.this.initialParent.remove(DraggableLabel.this);
                glassPane.add(DraggableLabel.this);

                // repaint former panel to display removal of element
                DraggableLabel.this.initialParent.repaint();

                // set up glass pane to actually display elements
                glassPane.setOpaque(false);
                glassPane.setVisible(true);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                // remove from glass pane
                JPanel glassPane = (JPanel) SwingUtilities.getRootPane(DraggableLabel.this).getGlassPane();
                glassPane.remove(DraggableLabel.this);

                // add to former panel
                DraggableLabel.this.initialParent.add(DraggableLabel.this);
                DraggableLabel.this.initialParent.repaint();

                DraggableLabel.this.initialParent = null;
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                // no-op
            }

            @Override
            public void mouseExited(MouseEvent e) {
                // no-op
            }

        });
        this.addMouseMotionListener(new MouseMotionListener() {
            @Override
            public void mouseDragged(MouseEvent e) {
                // get task bar height
                Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                Rectangle windowSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
                int taskBarHeight = (int) (screenSize.getHeight() - windowSize.getHeight());

                int mouseScreenX = e.getXOnScreen();
                int mouseScreenY = e.getYOnScreen();

                // calculate, offsetting y for the task bar
                // note: task bar offsetting will probably break if people have their taskbar at the top of the screen!
                // good thing I don't care!
                JFrame frame = (JFrame) SwingUtilities.getRoot(DraggableLabel.this);
                int mouseFrameX = mouseScreenX - frame.getX();
                int mouseFrameY = mouseScreenY - frame.getY() - taskBarHeight;

                // set location and ensure visibility
                DraggableLabel.this.setLocation(mouseFrameX, mouseFrameY);
                DraggableLabel.this.setVisible(true);
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                // no-op
            }
        });
    }
}
ix0rai
  • 37
  • 1
  • 8