Потоки и jtable

У меня проблема с jtable.

У меня есть несколько потоков, и каждый из них должен добавить строку в jTable, но таблица остается пустой. Я работаю с netbeans, графика полностью отделена от логики. Может кто-то мне помочь, пожалуйста?


это код, который я использую для добавления строки

MainGui.java

public void addToTable(String from, String to, int request, int response, String timeElapsed) {
    Object [][] temp = new Object [data.length + 1][5];

    for (int i = 0; i < data.length; i++) {
        for (int j = 0; j < 5; j++) {
            temp[i][j] = data[i][j];
        }
    }

    temp[data.length][0] = from;
    temp[data.length][1] = to;
    temp[data.length][2] = request;
    temp[data.length][3] = response;
    temp[data.length][4] = timeElapsed;

    data = temp;
    table.setModel(new DefaultTableModel(data, columnName));
}

MyThread.java

public void run() {
    try {
        MainGui mg = new MainGui();
        mg.addtotable("null", "null", 0, 0, "null");
    } catch (Exception e) {
    }

person mav    schedule 15.11.2012    source источник
comment
У вас возникла проблема (таблица остается пустой), предоставьте нам фрагменты вашего кода, чтобы мы могли вам помочь   -  person Maxim Shoustin    schedule 16.11.2012
comment
@mav для лучшей помощи, скорее опубликуйте SSCCE с жестко закодированными значениями для потоков, короткие, исполняемые, компилируемые, в остальном все здесь могут быть только выстрелы в темноту   -  person mKorbel    schedule 16.11.2012


Ответы (6)


Первое правило Swing: Не изменяйте пользовательский интерфейс из любого потока, кроме потока диспетчеризации событий

Во-первых, убедитесь, что ваши вызовы обновлений синхронизированы, используя SwingUtilities#invokeLater или, если обновление критично для пути кода SwingUtilities#invokeAndWait

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

Если вы используете DefaultTableModel, это будет сделано за вас, если вы используете AbstractTableModel или у вас есть TableModel, вам нужно будет сделать это самостоятельно.

Самый простой способ — написать реализацию, расширяющую AbstractTableModel, и вызвать AbstractTableModel#fireTableRowsInserted(int, int) из вашего метода добавления, это сообщит JTable, что модель добавила строки, и приведет к соответствующему обновлению таблицы.

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

Ознакомьтесь с разделами Как использовать таблицы и Параллелизм в Swing для получения дополнительной информации.

ОБНОВЛЕНО

Судя по всему, я не совсем ясно выразился. Модель отвечает за запуск событий. Это означает, что в вашем методе добавления вы должны вызывать fireTableRowsInserted. Следует воздерживаться от вызова этих методов из внешнего источника.

person MadProgrammer    schedule 15.11.2012
comment
Я бы сказал, что табличная модель отвечает за запуск событий обновления. Единственная причина, по которой AbstractTableModel использует общедоступные методы пожарной безопасности, — это делегирование. - person Steve Kuo; 16.11.2012
comment
@SteveKuo Именно модель отвечает за отправку событий. Когда OP вызывает там метод добавления, они должны вызывать соответствующий fireTableXxx from with в этом методе. Извините, если я не ясно выразился - person MadProgrammer; 16.11.2012
comment
@Steve Kuo те же проблемы с DefaultTableModel, если вы измените значение модели вне EDT. - person mKorbel; 16.11.2012
comment
Если вы посмотрите на исходный код DefaultTableModel, он внутренне запускает событие изменения при вызове addRow, insertRow и т. д. Я хочу сказать, что хорошо написанная табличная модель должна автоматически запускать события изменения при изменении ее состояния. Клиенту, изменяющему модель таблицы, не нужно вручную запускать события изменения. - person Steve Kuo; 16.11.2012
comment
@SteveKuo, и мы с тобой согласны. Другая проблема, которую следует учитывать, заключается в том, что Swing небезопасен для потоков, поэтому, даже если ваша модель делает то, что должна делать, если вызывающая сторона не соблюдает контракт EDT, у вас все равно будут проблемы;) - person MadProgrammer; 16.11.2012

Swing не является потокобезопасным. Если вам нужно изменить компоненты Swing из потоков, отличных от потока отправки событий AWT, используйте

SwingUtilities.invokeLater(new Runnable(){public void run() {
 // your code
}});
person Maxim Shoustin    schedule 15.11.2012

Не могли бы вы уточнить, как вы добавляете строки? Надеюсь, используя модель, верно? После добавления новой строки вы должны вызвать метод модели fireTableDataChanged/не лучший вариант/ или fireTableRowsInserted/лучше/ И не забудьте сделать это с помощью SwingUtilities.invokeLater, чтобы избежать проблем Swing

person rimas    schedule 15.11.2012
comment
да с table.setModel (новая DefaultTableModel (данные, имя столбца)); - person mav; 16.11.2012
comment
Правильнее будет создать собственную модель таблицы, которая расширяет DefaultTableModel, а затем установить ее в свою таблицу. См. пример ниже - person rimas; 16.11.2012

Также при попытке обновить модель JTable важно удалить все tableModelListener перед обновлением модели. Я видел это наблюдение с model.addColumn() и table.moveColumn(). Убедитесь, что вы добавили tableModelListener после любых изменений, внесенных в модель.

person suppie    schedule 27.01.2014

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

person Addict    schedule 15.11.2012
comment
У меня нет прав, чтобы начать комментировать :) - person Addict; 16.11.2012

person    schedule
comment
and each of them have to add a row to the jTable, пожалуйста, где методы для addRow, есть только getXxx методы, пожалуйста, удалите этот ответ - person mKorbel; 16.11.2012
comment
Пожалуйста, прокрутите код немного вниз и найдите метод addRow(int id). В небольшом примере я разместил свою таблицу, в которой есть только один столбец, и я использую очень простое хранилище (список). Вызывая метод addRow, вы можете вставить новую строку в модель и обновить таблицу потокобезопасным способом. - person rimas; 16.11.2012