Странная ошибка Swing при вызове RemoveAll () для подкласса JPanel - PullRequest
1 голос
/ 21 февраля 2011

Я работаю над генератором головоломок Судоку и сталкиваюсь с некоторыми прерывистыми исключениями свинга после / во время вызова метода RemoveAll () в JPanel. Когда я работаю в режиме отладки Eclipse, исключения не появляются. Вот код для рассматриваемого класса:

import java.awt.FlowLayout;
import java.awt.GridLayout;

import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * Represents a cell in the GUI Grid display
 * @author alex
 *
 */
public class CellGUI extends JPanel {



    public CellGUI()
    {
        super();

        this.setLayout(new GridLayout(3,3));

        for(int i = 1;i <=9;i++)
        {
            add(new JLabel("" + i));
        }

        setVisible(true);
    }

    public void clear()
    {
        this.removeAll();
        this.validate();
        this.setLayout(new GridLayout(3,3));

        for(int i = 1;i <= 9; i++)
        {
            add(new JLabel("" + i));
        }       

    }

    public void setValue(int newVal)
    {
        if (newVal == 0)
        {
            clear();
        }
        else
        {

            this.removeAll(); // this line appears to be the problem 

            //this.updateUI();
            //this.setLayout(new FlowLayout());

            //add(new   JLabel("" + newVal));
        }
    }
}

Обычно это выплевывает исключение:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException
    at javax.swing.LayoutComparator.compare(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(Unknown Source)
    at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(Unknown Source)
    at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(Unknown Source)
    at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(Unknown Source)
    at java.awt.FocusTraversalPolicy.getInitialComponent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.SequencedEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

Я полагаю, что в своей наивности я собираюсь поступить неправильно. Есть идеи?

Редактировать: По запросу выкладываю дополнительный код.

Этот класс вызывает метод setValue CellGUI:

public class GridGUI extends JPanel {

    ArrayList<CellGUI> cells = new ArrayList<CellGUI>();

    public GridGUI()
    {

        this.setLayout(new GridLayout(9,9));


        for(int i = 0; i < 81;i++)
        {
            CellGUI cell = new CellGUI();
            cells.add(cell);
            add(cell);
        }

    }


    public void updateGrid(Grid g)
    {
        for(int i = 0;i<81;i++)
        {
            cells.get(i).setValue(g.getValue(i));
        }
    }
}

Класс GridGUI создается и управляется классом, расширяющим JFrame:

public class GUI extends JFrame {   
...
public GUI() 
    {
        this.setLayout(new BorderLayout());
        add(gridGUI,BorderLayout.CENTER);

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());
        panel.add(isValidLabel);
        panel.add(isSolvableLabel);
        panel.setVisible(true);

        add(panel, BorderLayout.SOUTH);

        this.setSize(600, 600);

        setVisible(true);       

    }
    public void loadGrid(String path)
    {
        grid = new Grid(path);
        grid.print();

        gridGUI.updateGrid(grid);

        updateLabels();
    }
...
}

Который называется моим основным классом:

public static void main(String[] args) 
{       
    GUI gui = new GUI();
    gui.loadGrid(args[0]);
}

Ответы [ 5 ]

6 голосов
/ 21 февраля 2011

«Периодические / случайные ошибки» в приложениях Swing. часто вызываются обновлением пользовательского интерфейса вне EDT. См. Параллельность в Swing для получения более подробной информации.

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

5 голосов
/ 21 февраля 2011

Итак, анализ трассировки стека показывает, что ошибка возникает, когда FocusManager пытается получить первый компонент.Для этого ваш FocusTraversalPolicy пытается упорядочить компоненты в «порядке расположения», что означает примерно в столбцах и строках.Для GridLayout это должно быть совершенно тривиально.Давайте посмотрим на код LayoutComparator.В некоторых местах он создает исключение ClassCastException:

        if (a == null) {
            // 'a' is not part of a Window hierarchy. Can't cope.
            throw new ClassCastException();
        }

a является либо содержащим здесь окном, либо null, если такого окна не существует.

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

Чтобы избежать этого, переносит все изменения в GUI (включаясоздание компонентов, как ваш вызов конструктора выше) при вызове EventQueue.invokeLater(...).(Иногда invokeAndWait более полезен, и вы также можете вместо этого использовать методы с тем же именем в SwingUtilities.) В вашем случае изменение довольно простое:

public static void main(String[] args) 
{
    EventQueue.invokeLater(new Runnable() { public void run() {
        GUI gui = new GUI();
        gui.loadGrid(args[0]);
    }});
}
4 голосов
/ 21 февраля 2011

Периодические ошибки, подобные этой, заставляют меня беспокоиться о вызове кода Swing из EDT, потока диспетчеризации событий, который является основным потоком Swing и отвечает за графику Swing и взаимодействие с пользователем. Где и как вы вызываете метод CellGUI # setValue (...)? Может ли это быть вне EDT?

1 голос
/ 21 февраля 2011

Не вижу смысла удалять все ярлыки?

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

0 голосов
/ 07 марта 2014

Иногда, когда вы намерены создать только один поток, вы получаете больше и запускаете обновление из-за проблемы с неправильным потоком.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...