Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> JTable, AbstractTableModel и множество потоков, Не успевает обновляться интерфейс 
V
    Опции темы
User1302
Дата 18.11.2010, 01:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.11.2010

Репутация: нет
Всего: нет



Здравствуйте, уважаемые форумчане! smile 

Я новичок в Java.
У меня возникла проблеммка с обновлением данных в JTable, кот. имеет моделью AbstractTableModel с List<> в качестве источника записей.
Раньше не программировал интерфейс и возникшая ситуация ставит под сомнение правильность всей моей модели приложения.

Попробую объяснить:

1. Есть обьекты, названные мною "Section", имеют свои поля (Код, Дата, Комментарий и проч.)
Эти обьекты я хочу видеть в таблице JTable в отдельной строчке для каждого обьекта, где в столбцах - значения полей обьекта Section.
Обьекты Section хранятся в массиве типа List<Section>. Массив List<Section> может пополняться новыми обьектами Section, также обьекты могут быть удалены из массива.
2. Таблица JTable использует AbstractTableModel, кот. берет данные из массива обьектов List<Section>. Вот примерный код, как это происходит:

Код

List<Section> sectionList = SomeClass.getSectionList();

public int getRowCount() {
        return sectionList.size();
}

public Object getValueAt(int rowIndex, int columnIndex) {
        Section section;
        section = sectionList.get(rowIndex);
        switch (columnIndex) {
            case 0:
                return section.getId(); //Для поля КОД
            case 1:
                return section.getDate(); //Для поля ДАТА
//не привожу здесь все методы, дабы не загромождать код
            case 6:
                return section.getComment(); //Для поля Комментарий
            default:
                return null;
        }
    }


3. События.
Действия, кот. я хочу выполнять над обьектом Section: a) изменять его поля;
Действия, кот. я хочу выполнять над массивом List<Section>: a) добавлять обьекты Section в массив; b) удалять обьекты Section из массива;

Требуется, чтоб об этом узнавала таблица (модель) и при каждом изменении обьекта/списка обьектов обновлялись данные таблицы.
Для простоты и по неопытности сейчас я это сделал так:
Модель является подписчиком событий изменения обьекта Section - метод sectionUpdated(Section section){} и подписчиком событий изменения массива List<Section> - методы sectionAdded(Section section) и sectionWillBecomeRemoved(Section section).
Соответственно в указанных методах вызываются методы модели AbstractTableModel - fireTableRowsUpdated(r, r);fireTableRowsInserted(r, r);fireTableRowsDeleted(r, r);

А теперь собственно проблема: все работает, пока обновления происходят в одном потоке.
Поскольку действия, производимые над обьектом Section занимают некот. время и над разными экземплярами Section могут одновременно выполняться действия, каждое действие выполняется в отдельном потоке. Когда действие завершается, обьект меняет свое состояние и об этом узнают все подписчики обьекта Section ч-з метод sectionUpdated(this), в их числе оказывается и моя модель таблицы.
В отдельном потоке также могут производиться действия по добавлению и удалению в List<Section> обьектов.

И вот когда происходит удаление подряд сразу нескольких обьектов Section - уведомляется об этом модель таблицы, выполняется fireTableRowsDeleted(r, r); и вылетает исключение:
Exception in thread "AWT-EventQueue-0" 
java.lang.ArrayIndexOutOfBoundsException: 1
Причем не всегда и при малом количестве обьектов (до десяти) все в порядке. Больше - обязательно исключение. Хотя пару раз не вылетало и при сотне обьектов.
Блокировки synchronized не помогают.

Думаю, проблема вот. в чем - из модели удаляются обьекты(строки) в том потоке, кот. это вызвал, а вот слушатели модели, в том числе JTable обновляются в другом потоке (EventDispatchThread???) и пока это происходит другой поток изменяет модель и уменьшает количество обьектов в массиве List<Section> и получается выход за пределы массива.
Если я неправ, прошу меня поправить!

В общем, прошу помощи в виде более-менее конкретных решений, типа "посмотри в сторону EventQueue.InvokeLater", или "SwingWorker", "EventDispatchThread".
Перечисленные вещи крутятся в голове, но вплотную работать с ними не приходилось пока.
Самое простое решение, кот. пришло в голову - запускать в самой модели отдельный поток на изменение модели, а удаляемые обьекты ставить в очередь.
Но сейчас мне кажется это глупым.

Буду очень признателен за все возможные варианты решений, в том числе радикальных, требующих пускай даже изменения всей модели приложения, ведь истина дороже! smile 
Повторяю, написать готовое решение я не прошу, достаточно совета, но за код тоже буду благодарен!
На всякий случай прикрепляю рабочий вариант приложения, кот. сваял - очень сильно упрощенный вариант для удобства, но ошибка в нем присутствует.
компилируется просто: javac Main.java, запускаетя тоже: java Main

Всех заранее благодарю!

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  Main.java.tar.gz 1,88 Kb
PM MAIL   Вверх
COVD
Дата 18.11.2010, 05:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



Цитата

Думаю, проблема вот. в чем ...

Да. Любые изменения модели следует выполнять в потоке EventDispatchThread. Тогда изменение и перерисовка изменения будут выполняться в одном потоке, т.е. последовательно, а не одновременно. 
PM MAIL   Вверх
User1302
Дата 18.11.2010, 10:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.11.2010

Репутация: нет
Всего: нет



Цитата

Да. Любые изменения модели следует выполнять в потоке EventDispatchThread. Тогда изменение и перерисовка изменения будут выполняться в одном потоке, т.е. последовательно, а не одновременно. 


Попробовал сделать вот так:
Код

public synchronized void sectionRemoved(final Section section) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                int r = sectionList.indexOf(section);
                fireTableRowsDeleted(r, r);
                sectionList.remove(section);
            }
        });
    }


В итоге вроде все хорошо работает. Правильно так делать?
PM MAIL   Вверх
Skipy
Дата 18.11.2010, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 4
Всего: 16



А sectionList у Вас - это модель таблицы? Не получится, что после получения события таблица обратится к модели для перерисовки, а Вы еще не удалили строку? Я бы поставил sectionList.remove(section) перед уведомлением.

Это сообщение отредактировал(а) Skipy - 18.11.2010, 11:31


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
User1302
Дата 18.11.2010, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 23
Регистрация: 17.11.2010

Репутация: нет
Всего: нет



Цитата

А sectionList у Вас - это модель таблицы? Не получится, что после получения события таблица обратится к модели для перерисовки, а Вы еще не удалили строку? Я бы поставил sectionList.remove(section) перед уведомлением.


Думаю, вы правы - исправил, хотя работает и так, и так.
sectionList - это список в модели, откуда строчки дергаются.
...
Разобрался немного с моделью событий Swing.

Запускать изменения интерфейса через "SwingUtilities.invokeLater()" мне кажется правильным решением.
Если это не единственное решение, прошу показать еще варианты, если они есть.
А в общем, думаю, тему можно считать закрытой.

Спасибо COVD, Skipy, плюсики ставить еще не получается

PM MAIL   Вверх
jk1
Дата 18.11.2010, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 21
Всего: 75



Цитата

Спасибо COVD, Skipy, плюсики ставить еще не получается

Модератор:  Поставил


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.0493 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.