0

I've seen a number of posters argue that Swing components should not be extended, and that functionality should instead be added via composition. So say I want to reusably create a JPanel with absolute positioning (no layout manager) in which I can reposition components with the mouse:

public class MoveableComponentPanel 
{
    private final JPanel m_panel;

    public MoveableComponentPanel()
    {
        m_panel = new JPanel(null);
    }

    public void add(Component c)
    {
        m_panel.add(c);
        c.addMouseListener(m_mover);
        c.setSize(c.getPreferredSize());
    }   

    private final MouseListener m_mover = new MouseListener()
    {
        private int m_startX, m_startY;

        @Override
        public void mousePressed(MouseEvent e)
        {
            if (e.getButton() == MouseEvent.BUTTON1)
            {
                m_startX = e.getX();
                m_startY = e.getY();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            if (e.getButton() == MouseEvent.BUTTON1)
            {
                Component c = e.getComponent();
                Point p = c.getLocation();
                p.x += e.getX() - m_startX;
                p.y += e.getY() - m_startY;         
                c.setLocation(p);
                c.repaint();
            }
        }   

        @Override
        public void mouseClicked(MouseEvent e) {}

        @Override
        public void mouseEntered(MouseEvent e) {}

        @Override
        public void mouseExited(MouseEvent e) {}
    };
}

Looks nice, but there's no way to add the panel to a container. Further headaches if I want to allow a calling class to interact with the panel, e.g. change size, background color, register event listeners, etc. Either I add a getPanel() accessor, which breaks encapsulation, or write pass-through methods for the JPanel methods/properties I want to expose (potentially many). Is there some other strategy I'm missing here? What is the accepted best practice?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Stephen Carlson
  • 276
  • 1
  • 9
  • 1
    I see nothing wrong with extending `JPanel` here... – OneCricketeer Dec 15 '16 at 07:11
  • 1
    *"I've seen a number of posters argue that Swing components should not be extended.."* As a person that often gives that advice, I'll point out that it is a 'general rule' rather than one that is chiselled into stone. There ***are*** valid cases where extending a component makes sense (e.g. custom painting). *"..absolute positioning (no layout manager) in which I can reposition components with the mouse"* ..why? I hope this is not an attempt at trying to make a 'GUI designer', since the resulting GUIs will have all the problems usually inflicted upon GUIs made without layouts. .. – Andrew Thompson Dec 15 '16 at 07:13
  • 1
    .. But if it actually turns out to be a good case for a D'n'D panel, I'd strongly suggest implementing a `DragAndDropLayout` because that will at least bring you to consider some of the things that could go wrong with it. – Andrew Thompson Dec 15 '16 at 07:15
  • It's a UML class diagram viewer based on Reflection. – Stephen Carlson Dec 15 '16 at 07:18
  • And thank you, I'll look into DragAndDropLayout – Stephen Carlson Dec 15 '16 at 07:18
  • 2
    Extending `JPanel` gives you a UI delegate and lets you manage the [preferred size](http://stackoverflow.com/q/7229226/230513). See also `JHotDraw`, cited [here](http://stackoverflow.com/a/13997870/230513). – trashgod Dec 15 '16 at 10:43

1 Answers1

1

in which I can reposition components with the mouse:

Then you just add the MouseListener/MouseMotionListener to the components that you want to drag. There is no need to extend any component to add that functionality.

Check out the Component Mover class for examples of ways to do basic dragging of a component as well as a more complex dragging solution.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Wow, you're right. I hadn't thought about it that way. There really is no need for this functionality to be bound to any particular container type, and it's a lot more flexible if it isn't. ComponentMover demonstrates that beautifully. Thanks! – Stephen Carlson Dec 16 '16 at 05:40