Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
379 views
in Technique[技术] by (71.8m points)

java - How to prevent JLabel positions from resetting?

I have a JPanel that contains 11 JLabels, each of them registered with a MouseMotionListener like so (generated by Netbeans):

label1.addMouseMotionListener(new MouseMotionAdapter()
{
    public void mouseDragged(MouseMotionEvent evt){
        label1MouseDragged(evt);
}

and the individual labelXMouseDragged methods contain (for example):

label1.setLocation(label1.getParent().getMousePosition());

This Panel lives inside another Panel alongside various other controls. I find that I can drag my labels just fine inside the panel (I had my methods correctly checking for bounds, but I have left them like the above for simplicity). However, if the mouse is clicked anywhere that is not a control, either within the inner panel or within the parent panel, the locations of the labels reset. What is causing this to happen? I have no mouseListeners of any kind registered anywhere else, and if I make this panel by itself, I seem to have no issues with clicks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You could achieve this by using a null layout, but I have a pathalogical dislike for null layouts, too many things go wrong with them.

The Swing API is based around the use of layout managers when laying out components.

Instead, you could create a layout manager whose sole responsibility would be to honour the position of the components it is managing

AbsoluteLayout

The basic benefit of this is you don't need to worry about sizing the components and that it will respond to changes to the parent container as well as changes to the containers around it without you needing to add additional listeners.

You could even devise a bounds check within the layoutContainer to ensure that the components stay within bounds

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class AbsoluteLayoutExample {

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

    public AbsoluteLayoutExample() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {

            setLayout(new AbsoluateLayoutManager());

            JLabel test = new JLabel("Test");
            add(test);

            MouseAdapter ma = new MouseAdapter() {

                private Point offset;
                private Component dragComp;

                @Override
                public void mousePressed(MouseEvent e) {
                    Point point = e.getPoint();
                    for (Component comp : getComponents()) {
                        if (comp.getBounds().contains(point)) {
                            offset = new Point(point.x - comp.getX(), point.y - comp.getY());
                            dragComp = comp;
                        }
                    }
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    offset = null;
                    dragComp = null;
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    if (dragComp != null) {
                        Point p = e.getPoint();
                        Point dragP = new Point(p.x - offset.x, p.y - offset.y);
                        dragComp.setLocation(dragP);
                    }
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class AbsoluateLayoutManager implements LayoutManager2 {

        @Override
        public void addLayoutComponent(Component comp, Object constraints) {
        }

        @Override
        public Dimension maximumLayoutSize(Container target) {
            return preferredLayoutSize(target);
        }

        @Override
        public float getLayoutAlignmentX(Container target) {
            return 0.5f;
        }

        @Override
        public float getLayoutAlignmentY(Container target) {
            return 0.5f;
        }

        @Override
        public void invalidateLayout(Container target) {
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            int maxX = 0;
            int maxY = 0;
            for (Component comp : parent.getComponents()) {
                Dimension size = comp.getPreferredSize();
                maxX = Math.max(comp.getX() + size.width, maxX);
                maxY = Math.max(comp.getY() + size.height, maxY);
            }

            return new Dimension(maxX, maxY);
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return preferredLayoutSize(parent);
        }

        @Override
        public void layoutContainer(Container parent) {
            for (Component comp : parent.getComponents()) {
                Dimension size = comp.getPreferredSize();
                comp.setSize(size);
            }
        }

    }

}

You might also consider something like this example which is a "percentage" based constraint to lay out components, so thay are always at a given perctange point within the container


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...