JTable обновляет данные из текстового файла

Я хочу создать программу чтения файлов, которая отображает данные в JTable. Данные в файле разделены символами ',' , ';' , или же '.' персонажи. Вот небольшая часть этого

текстовый файл

12345;Βασ.ίλειος;Τζης;Περικλής;Μαρία;28/06/1984;α1
12346;Βασίλ.ειος;Τζόγλου;Πέτρος;Μαρία;29/06/1984;α1
12347;Βα.σίλειος;Τζόπουλος;Παύ.λος;Μαρία;30/06/1984;α1
12348;Βασίλ.ειος;Τζάκης;Πανα.γιώτης;Μαρία;27/06/1984;α1

Я открываю эти записи с разделителем по умолчанию (';'), как показано на рисунке ниже.

читатель файлов

Когда я пытаюсь выбрать другой разделитель, программа должна снова прочитать файл, а затем разделить данные с новым разделителем. Я вижу, что данные не могут быть обновлены в конце концов. По настоянию я поместил весь необходимый код в один класс, чтобы его можно было запустить. Кроме того, я использую openCSV.

public class NewClass extends JFrame{
private CSVReader reader;
private DefaultTableModel defaultTableModel;
private final Handle handle;
private final List<String> studentColumnNames;
private FileInputStream fileInputStream;
private InputStreamReader fileReader;
private int numberOfColumns, numberOfRows;
private final JComboBox split;
private final JTable dataDemoTable;
private String[] nextLine;
private String[][] rowData;
CharsetDecoder UTF8_CHARSET;
Container container;
FlowLayout flowLayout;
List<String[]> myEntries;

public NewClass(){
    this.studentColumnNames = new ArrayList<>();
    this.studentColumnNames.add("A");
    this.studentColumnNames.add("B");
    this.studentColumnNames.add("C");
    this.studentColumnNames.add("D");
    this.studentColumnNames.add("E");
    this.studentColumnNames.add("F");
    this.studentColumnNames.add("G");

    this.split = new JComboBox();
    this.split.addItem(";");
    this.split.addItem(".");
    this.split.addItem("tab");

    read();
    populateData();
    this.dataDemoTable = new JTable(new DefaultTableModel(this.rowData, studentColumnNames.toArray())); 
    this.dataDemoTable.setFont(new Font("Calibri", Font.PLAIN,18));
    this.dataDemoTable.setPreferredScrollableViewportSize(new Dimension(490,290));
    this.dataDemoTable.setFillsViewportHeight(true);
    JScrollPane scrollPane = new JScrollPane(this.dataDemoTable);
    container = getContentPane();
    flowLayout = new FlowLayout();
    container.setLayout(flowLayout);
    container.add(scrollPane);
    container.add(this.split);
    close();

    this.handle = new Handle();
    this.split.addItemListener(handle);
}

private int getNumberOfColumnsFromFile(){
    //Estimating number of columns from file
    this.numberOfColumns = 0;
    try {
        this.nextLine = this.reader.readNext();
    } catch (IOException ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
    if(this.nextLine != null){
        this.numberOfColumns = this.nextLine.length;
    }
    return this.numberOfColumns;
}

private void close(){
    try {
        this.fileInputStream.close();
        this.fileReader.close();
        this.reader.close();
    }
    catch (IOException ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private void populateData(){
    try {
        myEntries = this.reader.readAll();
    } catch (IOException ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
    this.rowData = myEntries.toArray(new String[0][]);
}

private void read(){
    try {
        this.fileInputStream = new FileInputStream("D:\\Book2.txt"); //the txt file above
        UTF8_CHARSET = StandardCharsets.UTF_8.newDecoder();
        UTF8_CHARSET.onMalformedInput(CodingErrorAction.REPLACE);
        this.fileReader = new InputStreamReader(this.fileInputStream, UTF8_CHARSET);
        this.reader = new CSVReader(this.fileReader, this.split.getSelectedItem().toString().charAt(0));

        if(getNumberOfColumnsFromFile() > studentColumnNames.size()){
            int remainder = getNumberOfColumnsFromFile()-studentColumnNames.size();
            for(int i = 1; i <= remainder; i++){
                //add one more name to studentColumnNames
                studentColumnNames.add("" + (i) + "");
            }
        }
    } 
    catch (FileNotFoundException ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public void setVisibilityToView(){setVisible(true);}
public void setNumberOfColumns(int numberOfColumns){this.numberOfColumns = numberOfColumns;}
public void setSizeToView(int width,int height){setSize(width, height);}
public void setDefaultCloseOperationToView(){setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}

public class Handle implements ItemListener{

    @Override
    public void itemStateChanged(ItemEvent e) {
        read();
        populateData();
        close();
    }

}
}

Может ли кто-нибудь предложить решение этой проблемы? Спасибо.


person Vassilis De    schedule 17.08.2014    source источник
comment
"I tried tableModel.fireTableDataChanged() but there is not such method for my JTable." -- это метод AbstractTableModel, а не метод JTable -- пожалуйста, прочтите руководство по JTable и просмотрите API AbstractTableModel, чтобы узнать больше об этом. "I have to change it to DefaultTableModel instead. But if I do so, I cannot put in into scrollPane and display it." -- это не имеет смысла, так как модель не имеет ничего общего с помещением JTable в JScrollPane. Пожалуйста, улучшите этот вопрос.   -  person Hovercraft Full Of Eels    schedule 17.08.2014
comment
Должен признаться, я не очень хорошо разбираюсь в таблицах. Поэтому я стер этот абзац   -  person Vassilis De    schedule 17.08.2014
comment
Ваши ссылки на пользовательские классы сбивают с толку. А пытаться отладить незавершенную программу, в которой мы ничего не знаем о потоке событий/вызовов, очень сложно. Вы говорите, что мало знаете о таблицах. Почему бы вам не попробовать разработать MCVE (с жестко закодированными значениями), который не имеет абсолютно никакого отношения к этой конкретной программе, но представляет собой упрощенную работоспособную версию только этого конкретного варианта использования. Просто сделайте все это в одном классе, который мы можем копировать, вставлять, компилировать, запускать. Вы добьетесь гораздо большего успеха, получив ответ таким образом.   -  person Paul Samsotha    schedule 17.08.2014
comment
@peeskillet Надеюсь, последние правки помогут.   -  person Vassilis De    schedule 19.08.2014
comment
Итак, позвольте мне прояснить проблему. Вы хотите иметь возможность обновить таблицу с другим разбиением на основе вновь выбранного разделителя?   -  person Paul Samsotha    schedule 19.08.2014
comment
Да! Это правильно! Каждый раз, когда я меняю сплиттер, получаю те же результаты, что и для первого сплиттера.   -  person Vassilis De    schedule 19.08.2014
comment
Будет ли это всегда один и тот же формат файла? Причина, по которой я спрашиваю, заключается в том, как вы будете определять заголовки столбцов при каждом чтении файла?   -  person Paul Samsotha    schedule 19.08.2014
comment
Пока я не использую заголовки. Так что формат будет тот же. Я буду использовать поля со списком, чтобы пользователь мог решить, какой столбец является заголовком из его файла.   -  person Vassilis De    schedule 19.08.2014
comment
Короче говоря: ((DefaultTableModel)dataDemoTable.getModel()).fireTableDataChanged();   -  person Joop Eggen    schedule 19.08.2014


Ответы (1)


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

Если вы посмотрите на getModelFromCsvFile, он в значительной степени выполняет ту же функцию, что и ваш метод read(), за исключением того, что я возвращаю DefaultTableModel и вместо этого использую разделение. Вы можете использовать собственную реализацию метода. Вам просто нужно использовать разделитель, чтобы установить его в открытом CSV. Я не уверен, как установить разделитель с открытым CSV, но я уверен, что если вы знаете API, это что-то тривиальное

Если вы посмотрите на getDelimiterComboBox, я создаю поле со списком с помощью ActionListener. Когда значение в поле со списком изменяется, я вызываю getModelFromCsvFile, а затем устанавливаю новую модель для таблицы.

Это должно быть довольно легко следовать, но это основная идея, которой вы хотите следовать.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class ReadFileDemo {

    private String defaultFile = "D:\\Book.txt";
    private File currentFile = new File(defaultFile);
    private JTable table;

    public ReadFileDemo() {
        DefaultTableModel model = getModelFromCsvFile(currentFile, ";");
        table = new JTable(model);
        JFrame frame = new JFrame();
        frame.add(new JScrollPane(table));
        frame.add(getDelimiterComboBox(new String[] {";", ".", "\t"}), BorderLayout.NORTH);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    /**
     * Similar to your read() method
     */
    public DefaultTableModel getModelFromCsvFile(File file, String delimiter) {
        DefaultTableModel model = null;
        String line;
        boolean isFirstLine = true;
        try(BufferedReader reader = new BufferedReader(new FileReader(file))) {
            while ((line = reader.readLine()) != null) {
                String[] row = line.split(delimiter);
                if (isFirstLine) {
                    Object[] header = getTableColumnHeaders(row.length);
                    model = new DefaultTableModel(header, 0);
                    model.addRow(row);
                    isFirstLine = false;
                } else {
                    if (model != null) {
                        model.addRow(row);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return model;
    }

    public JComboBox getDelimiterComboBox(String[] delimiters) {
        final JComboBox cbox = new JComboBox(delimiters);
        cbox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String delimiter = cbox.getSelectedItem().toString();
                DefaultTableModel model = getModelFromCsvFile(currentFile,
                        delimiter);
                table.setModel(model);
            }
        });
        return cbox;
    }

    public Object[] getTableColumnHeaders(int size) {
        Object[] header = new Object[size];
        for (int i = 0; i < header.length; i++) {
            header[i] = i + 1;
        }
        return header; 
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new ReadFileDemo();
            }
        });
    }
}

ОБНОВЛЕНИЕ

Использование CSVReader в методе read().

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.List;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

import au.com.bytecode.opencsv.CSVReader;

public class ReadFileDemo {

    private String defaultFile = "D:\\Book.txt";
    private File currentFile = new File(defaultFile);
    private JTable table;
    private CSVReader reader;
    private CharsetDecoder UTF8_CHARSET;

    public ReadFileDemo() {
        DefaultTableModel model = getModelFromCsvFile(currentFile, ";");
        table = new JTable(model);
        JFrame frame = new JFrame();
        frame.add(new JScrollPane(table));
        frame.add(getDelimiterComboBox(new String[] { ";", ".", "\t" }),
                BorderLayout.NORTH);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    /**
     * Similar to your read() method
     */
    public DefaultTableModel getModelFromCsvFile(File file, String delimiter) {
        DefaultTableModel model = null;
        boolean isFirstRow = true;
        try {
            UTF8_CHARSET = StandardCharsets.UTF_8.newDecoder();
            UTF8_CHARSET.onMalformedInput(CodingErrorAction.REPLACE);
            reader = new CSVReader(new InputStreamReader(new FileInputStream(file),
                    UTF8_CHARSET), delimiter.charAt(0));
            List<String[]> dataList = reader.readAll();
            for (String[] row: dataList) {
                if (isFirstRow) {
                    model = new DefaultTableModel(getTableColumnHeaders(row.length), 0);
                    model.addRow(row);
                    isFirstRow = false;
                }
                else {
                    if (model != null) {
                        model.addRow(row);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return model;
    }

    public JComboBox getDelimiterComboBox(String[] delimiters) {
        final JComboBox cbox = new JComboBox(delimiters);
        cbox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String delimiter = cbox.getSelectedItem().toString();
                DefaultTableModel model = getModelFromCsvFile(currentFile,
                        delimiter);
                if (model != null) {
                    table.setModel(model);
                }
            }
        });
        return cbox;
    }

    public Object[] getTableColumnHeaders(int size) {
        Object[] header = new Object[size];
        for (int i = 0; i < header.length; i++) {
            header[i] = i + 1;
        }
        return header;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ReadFileDemo();
            }
        });
    }
}
person Paul Samsotha    schedule 19.08.2014
comment
Здесь мне нужно небольшое пояснение: вы сказали getModelFromCsvFile serves the same function as your create method, а внутри кода вы сказали Similar to your read() method. Какой правильный? - person Vassilis De; 19.08.2014
comment
извините, я имею в виду read(). Он просто читает файл и превращает его в DefaultTableModel - person Paul Samsotha; 19.08.2014
comment
Кроме того, после дальнейшего изучения вашего кода кажется, что вы просто забыли установить новую модель для таблицы, что, возможно, следует сделать в вашем методе populateData(). я не уверен на 100% - person Paul Samsotha; 19.08.2014
comment
Пришлось перенести инициализацию значений в конструктор, но по какой-то причине он не может найти мой текстовый файл... - person Vassilis De; 19.08.2014
comment
Я изменил имя файла. посмотри наверху. Просто измените его обратно - person Paul Samsotha; 19.08.2014
comment
Еще ничего, что? Файл не найден? Нет данных? Я отлично запускаю программу на своей стороне - person Paul Samsotha; 19.08.2014
comment
я получаю java.io.FileNotFoundException: D:\Book.txt - person Vassilis De; 19.08.2014
comment
ок ок я исправил. Теперь это работает! Большое спасибо! - person Vassilis De; 19.08.2014