Получить компоненты в порядке отображения

Есть ли способ получить список компонентов в JPanel в соответствии с порядком, в котором они отображаются в JPanel (сверху слева направо), а не в том порядке, в котором они были добавлены в JPanel?

Это, кажется, получает компоненты в том порядке, в котором они были добавлены на панель.

Component[] comps = myJPanel.getComponents();

person Get Off My Lawn    schedule 02.12.2012    source источник
comment
Возможно, вы могли бы использовать getComponentAt(x, y) и перебирать точки компонента, добавляя каждый компонент (который еще не был найден) в список. Просто теория.   -  person FThompson    schedule 03.12.2012
comment
Есть ли способ получить список компонентов в JPanel в соответствии с порядком их отображения в JPanel (слева вверху справа внизу) Конечно. Добавьте все компоненты в структуру списка, затем отсортируйте их в соответствии с Компаратором, который учитывает позицию. OTOH Мне довольно любопытно, чего вы на самом деле пытаетесь достичь с помощью такой ерунды.   -  person Andrew Thompson    schedule 03.12.2012


Ответы (2)


Взгляните на Container#getFocusTraversalPolicy, который возвращает FocusTraversalPolicy с методы определения перемещения фокуса через контейнер.

Это (должно) предоставить вам естественный порядок компонентов (с точки зрения менеджера компоновки и менеджера фокуса)

Я бы начал с FocusTraversalPolicy#getFirstComponent(Container) и FocusTraversalPolicy#getComponentAfter(Container, Component)

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

ОБНОВЛЕНО — Пример обхода фокуса

public class ComponentOrder {

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

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

                BodyPane body = new BodyPane();

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

                Container focusRoot = body.getFocusCycleRootAncestor();
                FocusTraversalPolicy ftp = focusRoot.getFocusTraversalPolicy();
                Component comp = ftp.getFirstComponent(body);
                Component first = comp;
                while (comp != null) {
                    System.out.println(" - " + comp);
                    comp = ftp.getComponentAfter(focusRoot, comp);
                    if (comp.equals(first)) {
                        break;
                    }
                }
            }
        });
    }

    public class BodyPane extends JPanel {

        private JTextField fldFirstName;
        private JTextField fldMiddleName;
        private JTextField fldLastName;
        private JTextField fldDateOfBirth;
        private JTextField fldEMail;
        private JButton okButton;
        private JButton cancelButton;

        public BodyPane() {

            setLayout(new BorderLayout());
            add(createFieldsPane());
            add(createButtonsPane(), BorderLayout.SOUTH);

        }

        public JPanel createButtonsPane() {

            JPanel panel = new JPanel(new FlowLayout());
            panel.add((okButton = createButton("Ok")));
            panel.add((cancelButton = createButton("Cancel")));

            return panel;

        }

        protected JButton createButton(String text) {

            return new JButton(text);

        }

        public JPanel createFieldsPane() {

            JPanel panel = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;

            panel.add(createLabel("First Name:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("Middle Name:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("Last Name:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("Date of Birth:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("EMail:"), gbc);

            gbc.gridy = 0;
            gbc.gridx++;
            gbc.weightx = 1;
            panel.add((fldFirstName = createField()), gbc);
            gbc.gridy++;
            panel.add((fldLastName = createField()), gbc);
            gbc.gridy++;
            panel.add((fldMiddleName = createField()), gbc);
            gbc.gridy++;
            panel.add((fldDateOfBirth = createField()), gbc);
            gbc.gridy++;
            panel.add((fldEMail = createField()), gbc);

            JPanel filler = new JPanel();
            filler.setOpaque(false);

            gbc.gridy++;
            gbc.weightx = 1;
            gbc.weighty = 1;
            panel.add(filler, gbc);

            return panel;

        }

        protected JLabel createLabel(String text) {

            return new JLabel(text);

        }

        protected JTextField createField() {

            JTextField field = new JTextField(12);
            return field;

        }
    }
}

Пример компаратора

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

nb Я украл компаратор из javax.swing.LayoutComparator, который защищен пакетом (что было хорошо для SwingTeam), и изменил его, чтобы преобразовать координаты компонента обратно в родительское координатное пространство.

public class ComponentOrder {

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

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

                BodyPane body = new BodyPane();

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

                List<Component> components = new ArrayList<Component>(25);
                getContents(body, components);
                LayoutComparator lc = new LayoutComparator(body);
                lc.setComponentOrientation(body.getComponentOrientation());
                Collections.sort(components, lc);
                for (Component comp : components) {
                    System.out.println(comp);
                }
            }
        });
    }

    protected void getContents(Container container, List<Component> components) {
        for (Component comp : container.getComponents()) {
            components.add(comp);
            if (comp instanceof Container) {
                getContents((Container) comp, components);
            }
        }
    }

    public class BodyPane extends JPanel {

        private JTextField fldFirstName;
        private JTextField fldMiddleName;
        private JTextField fldLastName;
        private JTextField fldDateOfBirth;
        private JTextField fldEMail;
        private JButton okButton;
        private JButton cancelButton;

        public BodyPane() {
            setLayout(new BorderLayout());
            add(createFieldsPane());
            add(createButtonsPane(), BorderLayout.SOUTH);
        }

        public JPanel createButtonsPane() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.add((okButton = createButton("Ok")));
            panel.add((cancelButton = createButton("Cancel")));
            return panel;
        }

        protected JButton createButton(String text) {
            return new JButton(text);
        }

        public JPanel createFieldsPane() {
            JPanel panel = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;

            panel.add(createLabel("First Name:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("Middle Name:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("Last Name:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("Date of Birth:"), gbc);
            gbc.gridy++;
            panel.add(createLabel("EMail:"), gbc);

            gbc.gridy = 0;
            gbc.gridx++;
            gbc.weightx = 1;
            panel.add((fldFirstName = createField("FirstName")), gbc);
            gbc.gridy++;
            panel.add((fldLastName = createField("LastName")), gbc);
            gbc.gridy++;
            panel.add((fldMiddleName = createField("MiddleName")), gbc);
            gbc.gridy++;
            panel.add((fldDateOfBirth = createField("DateOfBirth")), gbc);
            gbc.gridy++;
            panel.add((fldEMail = createField("EMail")), gbc);

            JPanel filler = new JPanel();
            filler.setOpaque(false);

            gbc.gridy++;
            gbc.weightx = 1;
            gbc.weighty = 1;
            panel.add(filler, gbc);

            return panel;
        }

        protected JLabel createLabel(String text) {
            JLabel label = new JLabel(text);
            label.setName(text);
            return label;
        }

        protected JTextField createField(String name) {
            JTextField field = new JTextField(12);
            field.setName("Field-" + name);
            return field;
        }
    }

    public class LayoutComparator implements Comparator<Component>, java.io.Serializable {

        private static final int ROW_TOLERANCE = 10;
        private boolean horizontal = true;
        private boolean leftToRight = true;

        private Component parent;

        public LayoutComparator(Component parent) {
            this.parent = parent;
        }

        void setComponentOrientation(ComponentOrientation orientation) {
            horizontal = orientation.isHorizontal();
            leftToRight = orientation.isLeftToRight();
        }

        public int compare(Component a, Component b) {
            if (a == b) {
                return 0;
            }

            // Row/Column algorithm only applies to siblings. If 'a' and 'b'
            // aren't siblings, then we need to find their most inferior
            // ancestors which share a parent. Compute the ancestory lists for
            // each Component and then search from the Window down until the
            // hierarchy branches.
            if (a.getParent() != b.getParent()) {
                LinkedList<Component> aAncestory = new LinkedList<Component>();

                for (; a != null; a = a.getParent()) {
                    aAncestory.add(a);
                    if (a instanceof Window) {
                        break;
                    }
                }
                if (a == null) {
                    // 'a' is not part of a Window hierarchy. Can't cope.
                    throw new ClassCastException();
                }

                LinkedList<Component> bAncestory = new LinkedList<Component>();

                for (; b != null; b = b.getParent()) {
                    bAncestory.add(b);
                    if (b instanceof Window) {
                        break;
                    }
                }
                if (b == null) {
                    // 'b' is not part of a Window hierarchy. Can't cope.
                    throw new ClassCastException();
                }

                for (ListIterator<Component> aIter = aAncestory.listIterator(aAncestory.size()),
                                bIter = bAncestory.listIterator(bAncestory.size());;) {
                    if (aIter.hasPrevious()) {
                        a = aIter.previous();
                    } else {
                        // a is an ancestor of b
                        return -1;
                    }

                    if (bIter.hasPrevious()) {
                        b = bIter.previous();
                    } else {
                        // b is an ancestor of a
                        return 1;
                    }

                    if (a != b) {
                        break;
                    }
                }
            }

            Point pa = SwingUtilities.convertPoint(a, a.getLocation(), parent);
            Point pb = SwingUtilities.convertPoint(b, b.getLocation(), parent);

            int ax = pa.x, ay = pa.y, bx = pb.x, by = pb.y;

            int zOrder = a.getParent().getComponentZOrder(a) - b.getParent().getComponentZOrder(b);
            if (horizontal) {
                if (leftToRight) {

                    // LT - Western Europe (optional for Japanese, Chinese, Korean)

                    if (Math.abs(ay - by) < ROW_TOLERANCE) {
                        return (ax < bx) ? -1 : ((ax > bx) ? 1 : zOrder);
                    } else {
                        return (ay < by) ? -1 : 1;
                    }
                } else { // !leftToRight

                    // RT - Middle East (Arabic, Hebrew)

                    if (Math.abs(ay - by) < ROW_TOLERANCE) {
                        return (ax > bx) ? -1 : ((ax < bx) ? 1 : zOrder);
                    } else {
                        return (ay < by) ? -1 : 1;
                    }
                }
            } else { // !horizontal
                if (leftToRight) {

                    // TL - Mongolian

                    if (Math.abs(ax - bx) < ROW_TOLERANCE) {
                        return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
                    } else {
                        return (ax < bx) ? -1 : 1;
                    }
                } else { // !leftToRight

                    // TR - Japanese, Chinese, Korean

                    if (Math.abs(ax - bx) < ROW_TOLERANCE) {
                        return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
                    } else {
                        return (ax > bx) ? -1 : 1;
                    }
                }
            }
        }
    }
}
person MadProgrammer    schedule 02.12.2012
comment
Я использую это: Component c1 = focus.getFirstComponent(layers), где слои - это JPanel, и я получаю исключение nullPointerException. Есть идеи, почему? - person Get Off My Lawn; 03.12.2012
comment
@RyanNaddy, у него есть составные компоненты? - person MadProgrammer; 03.12.2012

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

Поскольку точное кодирование будет зависеть от того, какие библиотеки вы решите использовать, позвольте мне эвристически описать последующий процесс:

Расстояние от начала координат для любой точки (x,y) равно (x^2 + y^2)**(0.5). Используя это, можно построить теневой массив, который отражает каждую пару с одним числом. Просто выполнив реляционную сортировку по возрастанию каждого из этих расстояний, можно получить довольно хорошее приближение порядка от верхнего левого к нижнему правому.

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

Чтобы справиться с этим, можно просто предварительно масштабировать значение x или y с помощью множителя, прежде чем возвести его в квадрат и объединить с другим возведенным в квадрат, как описано. Это даст пропорционально большее значение "y", которое выше, чем x, которое ближе к левому краю окна, или наоборот, если требуется.

person user2278409    schedule 13.04.2013