DnD - Why is dragged label displayed below other components?

六眼飞鱼酱① 提交于 2019-12-11 04:54:45

问题


I've written a basic DnD program that has four JLabels in a row. I've noticed that when I drag a label to the left, it is displayed below the next label. However, when I drag the label to the right, it is displayed above the next label. The labels are added in order, left to right. So the dragged label is being displayed below other labels that were added before the dragged label, and displayed above other labels that were added after the dragged label. Can anyone explain why this happens? Can anyone offer a fix so that the dragged label is displayed above the other labels? Thanks.

source code:

public class LabelDnd extends JPanel {

    private JLabel[] labels;
    private Color[] colors = { Color.BLUE, Color.BLACK, Color.RED, Color.MAGENTA };

    public LabelDnd() {
        super();
        this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
        this.setBackground(Color.WHITE);
        this.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));

        JPanel basePanel = new JPanel();
        basePanel.setLayout(new GridLayout(1, 4, 4, 4));
        basePanel.setBackground(Color.CYAN);

        MouseAdapter listener = new MouseAdapter() {

            Point p = null;

            @Override
            public void mousePressed(MouseEvent e) {
              p = e.getLocationOnScreen();
            }

            @Override
            public void mouseDragged(MouseEvent e) {
              JComponent c = (JComponent) e.getSource();
              Point l = c.getLocation();
              Point here = e.getLocationOnScreen();
              c.setLocation(l.x + here.x - p.x, l.y + here.y - p.y);
              p = here;
            }
          };

        this.labels = new JLabel[4];

        for (int i = 0; i < this.labels.length; i++) {
            this.labels[i] = new JLabel(String.valueOf(i), JLabel.CENTER);
            this.labels[i].setOpaque(true);
            this.labels[i].setPreferredSize(new Dimension(100, 100));
            this.labels[i].setBackground(this.colors[i]);
            this.labels[i].setForeground(Color.WHITE);
            this.labels[i].addMouseListener(listener);
            this.labels[i].addMouseMotionListener(listener);
            basePanel.add(this.labels[i]);
        }

        this.add(basePanel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("LabelDnd");
                frame.getContentPane().setLayout(new BorderLayout());

                LabelDnd panel = new LabelDnd();

                frame.getContentPane().add(panel, BorderLayout.CENTER);

                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

回答1:


You are not changing the order that the labels have been added or are being painted in your code. Consider elevating the JLabel to the glasspane when dragging (after removing it from the main container), and then re-adding it to the main container on mouse release.

For example:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.*;
import java.util.Comparator;
import java.util.PriorityQueue;

import javax.swing.*;

@SuppressWarnings("serial")
public class LabelDnd extends JPanel {
   private static final String X_POS = "x position";
   private JLabel[] labels;
   private Color[] colors = { Color.BLUE, Color.BLACK, Color.RED, Color.MAGENTA };

   public LabelDnd() {
      super();
      // this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
      this.setBackground(Color.WHITE);
      this.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));

      JPanel basePanel = new JPanel();
      basePanel.setLayout(new GridLayout(1, 4, 4, 4));
      basePanel.setBackground(Color.CYAN);

      MouseAdapter listener = new MouseAdapter() {
         Point loc = null;
         Container parentContainer = null;
         Container glasspane = null;
         JLabel placeHolder = new JLabel("");
         private Point glassLocOnScn;

         @Override
         public void mousePressed(MouseEvent e) {
            JComponent selectedLabel = (JComponent) e.getSource();

            loc = e.getPoint();
            Point currLocOnScn = e.getLocationOnScreen();

            parentContainer = selectedLabel.getParent();

            JRootPane rootPane = SwingUtilities.getRootPane(selectedLabel);
            glasspane = (Container) rootPane.getGlassPane();
            glasspane.setVisible(true);
            glasspane.setLayout(null);
            glassLocOnScn = glasspane.getLocationOnScreen();

            Component[] comps = parentContainer.getComponents();

            // remove all labels from parent
            parentContainer.removeAll();

            // add labels back except for selected one
            for (Component comp : comps) {
               if (comp != selectedLabel) {
                  parentContainer.add(comp);
               } else {
                  // add placeholder in place of selected component
                  parentContainer.add(placeHolder);
               }
            }

            selectedLabel.setLocation(currLocOnScn.x - loc.x - glassLocOnScn.x,
                  currLocOnScn.y - loc.y - glassLocOnScn.y);
            glasspane.add(selectedLabel);
            glasspane.setVisible(true);

            parentContainer.revalidate();
            parentContainer.repaint();

         }

         @Override
         public void mouseDragged(MouseEvent e) {
            JComponent selectedLabel = (JComponent) e.getSource();

            glassLocOnScn = glasspane.getLocationOnScreen();
            Point currLocOnScn = e.getLocationOnScreen();
            selectedLabel.setLocation(currLocOnScn.x - loc.x - glassLocOnScn.x,
                  currLocOnScn.y - loc.y - glassLocOnScn.y);

            glasspane.repaint();
         }

         @Override
         public void mouseReleased(MouseEvent e) {
            JComponent selectedLabel = (JComponent) e.getSource();

            if (parentContainer == null || glasspane == null) {
               return;
            }

            // sort the labels based on their x position on screen
            PriorityQueue<JComponent> compQueue = new PriorityQueue<JComponent>(
                  4, new Comparator<JComponent>() {

                     @Override
                     public int compare(JComponent o1, JComponent o2) {
                        // sort of a kludge -- checking a client property that
                        // holds the x-position 
                        Integer i1 = (Integer) o1.getClientProperty(X_POS);
                        Integer i2 = (Integer) o2.getClientProperty(X_POS);
                        return i1.compareTo(i2);
                     }
                  });

            // sort of a kludge -- putting x position before removing component
            // into a client property to associate it with the JLabel
            selectedLabel.putClientProperty(X_POS, selectedLabel.getLocationOnScreen().x);
            glasspane.remove(selectedLabel);
            compQueue.add(selectedLabel);
            Component[] comps = parentContainer.getComponents();
            for (Component comp : comps) {
               JLabel label = (JLabel) comp;
               if (!label.getText().trim().isEmpty()) { // if placeholder!
                  label.putClientProperty(X_POS, label.getLocationOnScreen().x);
                  compQueue.add(label); // add to queue
               }
            }
            parentContainer.removeAll();

            // add back labels sorted by x-position on screen
            while (compQueue.size() > 0) {
               parentContainer.add(compQueue.remove());
            }

            parentContainer.revalidate();
            parentContainer.repaint();
            glasspane.repaint();

         }
      };

      this.labels = new JLabel[4];

      for (int i = 0; i < this.labels.length; i++) {
         this.labels[i] = new JLabel(String.valueOf(i), JLabel.CENTER);
         this.labels[i].setOpaque(true);
         this.labels[i].setPreferredSize(new Dimension(100, 100));
         this.labels[i].setBackground(this.colors[i]);
         this.labels[i].setForeground(Color.WHITE);
         this.labels[i].addMouseListener(listener);
         this.labels[i].addMouseMotionListener(listener);
         basePanel.add(this.labels[i]);
      }

      this.add(basePanel);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            JFrame frame = new JFrame("LabelDnd");
            frame.getContentPane().setLayout(new BorderLayout());

            LabelDnd panel = new LabelDnd();

            frame.getContentPane().add(panel, BorderLayout.CENTER);

            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
         }
      });
   }
}



回答2:


Because of z-index of your Swing component. You should use setComponentZOrder to change component's z-index value after you drag.

Please check this link to get more details



来源:https://stackoverflow.com/questions/13751954/dnd-why-is-dragged-label-displayed-below-other-components

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!