подходящий LayoutManager для изменяемых размеров компонентов - PullRequest
7 голосов
/ 13 октября 2011

некоторое время назад я прочитал эту статью , в которой показан способ реализации компонентов с изменяемым размером мыши в Swing.

Автор использует нулевой LayoutManager для обеспечения абсолютного позиционирования компонентов.Я знаю, что нулевой макет никогда не должен использоваться, поэтому мой вопрос:

Есть ли уже реализованный LayoutManager, который позволяет абсолютное позиционирование компонента, или я должен реализовать его самостоятельно?

Ответы [ 4 ]

4 голосов
/ 13 октября 2011

В качестве альтернативы также рассмотрим

3 голосов
/ 14 октября 2011

Менеджер по макету действительно делает 3 вещи:

  1. Установить местоположение компонента. Поскольку вам нужна возможность перетаскивать компонент, вы не хотели бы, чтобы ваш менеджер компоновки делал это.

  2. Установить размер компонента. Поскольку вам нужна возможность изменить размер компонента, вы не захотите этого делать. Однако может потребоваться задать для компонента размер по умолчанию на основе предпочтительного размера компонентов. Таким образом, вам не нужно указывать размер при создании компонента.

  3. Определите предпочтительный размер родительской панели на основе добавленных к ней компонентов. Это позволит панелям прокрутки функционировать должным образом, так как полосы прокрутки могут быть добавлены / удалены по мере необходимости. Так что вам нужно определить, как должно работать перетаскивание. То есть разрешено ли перетаскивать компонент за пределы текущих границ панели. В этом случае предпочтительный размер панели должен автоматически увеличиться.

есть ли уже реализованный LayoutManager, позволяющий абсолютное позиционирование компонента

Я играл с менеджером по расположению, который близок к вашим потребностям. Он был разработан для использования с классом ComponentMover из ссылки Moving Windows, предоставленной trashgod.

Вот мой тестовый код для этого класса:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 */
public class DragLayout implements LayoutManager, java.io.Serializable
{
    public DragLayout()
    {
    }

    /**
     * Adds the specified component with the specified name to the layout.
     * @param name the name of the component
     * @param comp the component to be added
     */
    @Override
    public void addLayoutComponent(String name, Component comp) {}


    /**
     * Removes the specified component from the layout.
     *
     * @param comp the component to be removed
     */
    @Override
    public void removeLayoutComponent(Component component)
    {
    }

    /**
     *  Determine the minimum size on the Container
     *
     *  @param   target   the container in which to do the layout
     *  @return  the minimum dimensions needed to lay out the
     *           subcomponents of the specified container
     */
    @Override
    public Dimension minimumLayoutSize(Container parent)
    {
        synchronized (parent.getTreeLock())
        {
            return preferredLayoutSize(parent);
        }
    }

    /**
     *  Determine the preferred size on the Container
     *
     *  @param   parent   the container in which to do the layout
     *  @return  the preferred dimensions to lay out the
     *           subcomponents of the specified container
     */
    @Override
    public Dimension preferredLayoutSize(Container parent)
    {
        synchronized (parent.getTreeLock())
        {
            return getLayoutSize(parent);
        }
    }

    /*
     *  The calculation for minimum/preferred size it the same. The only
     *  difference is the need to use the minimum or preferred size of the
     *  component in the calculation.
     *
     *  @param   parent  the container in which to do the layout
     */
    private Dimension getLayoutSize(Container parent)
    {
        Insets parentInsets = parent.getInsets();
        int x = parentInsets.left;
        int y = parentInsets.top;
        int width = 0;
        int height = 0;

        //  Get extreme values of the components on the container

        for (Component component: parent.getComponents())
        {
            if (component.isVisible())
            {
                Point p = component.getLocation();
                Dimension d = component.getPreferredSize();
                x = Math.min(x, p.x);
                y = Math.min(y, p.y);
                width = Math.max(width, p.x + d.width);
                height = Math.max(height, p.y + d.height);
            }
        }

        // Width/Height is adjusted if any component is outside left/top edge

        if (x < parentInsets.left)
            width += parentInsets.left - x;

        if (y < parentInsets.top)
            height += parentInsets.top - y;

        //  Adjust for insets

        width += parentInsets.right;
        height += parentInsets.bottom;
        Dimension d = new Dimension(width, height);

        return d;
//      return new Dimension(width, height);
    }

    /**
     * Lays out the specified container using this layout.
     *
     * @param     target   the container in which to do the layout
     */
    @Override
    public void layoutContainer(Container parent)
    {
    synchronized (parent.getTreeLock())
    {
        Insets parentInsets = parent.getInsets();

        int x = parentInsets.left;
        int y = parentInsets.top;

        //  Get X/Y location outside the bounds of the panel

        for (Component component: parent.getComponents())
        {
            if (component.isVisible())
            {
                Point location = component.getLocation();
                x = Math.min(x, location.x);
                y = Math.min(y, location.y);
            }
        }

        x = (x < parentInsets.left) ? parentInsets.left - x : 0;
        y = (y < parentInsets.top) ? parentInsets.top - y : 0;

        //  Set bounds of each component

        for (Component component: parent.getComponents())
        {
            if (component.isVisible())
            {
                Point p = component.getLocation();
                Dimension d = component.getPreferredSize();

                component.setBounds(p.x + x, p.y + y, d.width, d.height);
            }
        }
    }}

    /**
     * Returns the string representation of this column layout's values.
     * @return   a string representation of this layout
     */
    public String toString()
    {
        return "["
            + getClass().getName()
            + "]";
    }

    public static void main( String[] args )
    {
        ComponentMover cm = new ComponentMover();
        cm.setEdgeInsets( new Insets(-100, -100, -100, -100) );
//      cm.setEdgeInsets( new Insets(10, 10, 10, 10) );
        cm.setAutoLayout(true);

        JPanel panel = new JPanel( new DragLayout() );
        panel.setBorder( new MatteBorder(10, 10, 10, 10, Color.YELLOW) );

        createLabel(cm, panel, "North", 150, 0);
        createLabel(cm, panel, "West", 0, 100);
        createLabel(cm, panel, "East", 300, 100);
        createLabel(cm, panel, "South", 150, 200);
        createLabel(cm, panel, "Center", 150, 100);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new JScrollPane(panel) );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    public static void createLabel(ComponentMover cm, JPanel panel, String text, int x, int y)
    {
        JLabel label = new JLabel( text );
        label.setOpaque(true);
        label.setBackground( Color.ORANGE );
        label.setLocation(x, y);
        panel.add( label );
        cm.registerComponent( label );
    }

}
  1. Для этого макета размер всегда считается предпочтительным размером. Вам нужно изменить это. Может быть, установить размер, чтобы быть предпочтительным размером, когда размер (0, 0). Вам также потребуется использовать размер компонента (а не его предпочтительный размер) при определении предпочтительного размера родительского контейнера.

  2. Класс ComponentMover можно настроить так, чтобы он мог перетаскивать компоненты за пределы родительского контейнера или держать компонент внутри границ. Если разрешить перемещение компонентов за пределы границ, предпочтительный размер автоматически корректируется с учетом нового расположения компонента.

  3. Если вы перетаскиваете компонент за пределы верхней или левой границ, то все компоненты смещаются (вправо или вниз), убедитесь, что ни один из компонентов не имеет отрицательного расположения.

1 голос
/ 13 октября 2011

Полагаю, это будет зависеть от особенностей поведения.

Основная причина, по которой не рекомендуется использовать нулевой менеджер компоновки, заключается в том, что интерфейсы, созданные с использованием таких интерфейсов, могут использоваться только в том размере, для которого они были разработаны.Если это хорошо для вас, используйте его.

Другой известный мне вариант - это AbsoluteLayout, с которым распространяется Netbeans.Вы можете получить больше информации здесь: http://www.java -tips.org / other-api-tips / netbeans / can-i-distribate-absolutelayout-with-my-applicationa.html .Я думаю, что это может быть именно то, что вы ищете, но, как вы можете видеть из этой ссылки, они рекомендуют использовать макет Null ... Я не думаю, что в любом случае это имеет большое значение.

Если вам нужно, чтобы пользователи могли также определять, как будут изменяться размеры компонентов, вы в конечном итоге создадите что-то вроде конструктора форм Netbeans Matisse, что, вероятно, излишне и не доставляет мне особого удовольствия:)

0 голосов
/ 13 октября 2011

Вопрос несколько расплывчатый, поэтому я могу полностью упустить момент.Я предполагаю, что вы ищете макет, который позволит вам использовать абсолютное позиционирование, но все же позволит вам изменить размер компонента и использовать все доступное пространство.

Если вы кодируете это вручную, у меня был успех с MIGLayout (http://www.miglayout.com/) и TableLayout (который менее абсолютен, но очень прост в использовании - http://java.sun.com/products/jfc/tsc/articles/tablelayout/)

Если выЕсли вы используете какой-либо конструктор форм, использование GroupLayout может быть хорошим выбором, но вы не хотите вручную его кодировать. См. этот вопрос: GroupLayout: стоит ли учиться?

...