Search code examples
javaswingrendering

How can I unconditionally make my swing component render above all others?


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.


Solution

  • 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
                }
            });
        }
    }