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.
CodePudding user response:
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
}
});
}
}