1

I'm writing a small program that creates a gui to display the contents of a csv file. I've tried following the outline from the Oracle website (http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#data), but my problem is that the 'getColumnCount' method that is used to build the table can't access the 'headers' variable. Or more likely, it can, but the changes I thought I made to it in the main method did not connect to it. If anyone can shed some light on what's wrong and how to fix it, it'd be much appreciated.

public class MyTableModel implements TableModel {

    private String[] headers;        //This line.
    private Object[][] tableData;

    public static void main(String[] args) {
        String fileName = "products.csv";

        String[] csvList = readCSV(fileName);

        String[] headers = Arrays.copyOfRange(csvList, 0, 10); //Or maybe this line isn't changing the one above.
    }

    private static String[] readCSV(String file) {
        //Some code to fill the list.
        return fileString;
    }

    @Override
    public int getColumnCount() {
        return headers.length;        //<<This line of code
    }
}

@Hovercraft Full Of Eels

Oh, I should have mentioned. I'm implementing this class like this, which is to say, I'm calling it from elsewhere.

private static void createGUI() {
    csvTabler table = new csvTabler();
    table.setTitle("CSV Table");
    table.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    table.createJTable();
    table.pack();
    table.setVisible(true);
}

private void createJTable() {
    jTable = new JTable(new MyTableModel());
}

I'm sure this affects your solution but I'm not sure how to adjust..

André Foote
  • 366
  • 3
  • 15

1 Answers1

4
String[] headers = Arrays.copyOfRange(csvList, 0, 10); //Or maybe this line isn't changing the one above.

Yep, that's it in a nutshell .... you're trying to change an instance field from a static method and are also shadowing the variable to boot, and that just won't work. Understand that the headers variable declared within the main method is local to this method -- visible only within the method -- and so changes to it will have absolutely no effect on the headers instance field in the class. Instead create a constructor and pass the header data in when you need to pass it into the class.

A bad idea is to make headers static -- just don't do this as this throws out the OOPs baby with the bathwater, essentially fixing your problem with a kludge rather than making a much cleaner more fundamental improvement to your program.

For example:

public class MyTableModel implements TableModel {

    private String[] headers;        //This line.
    private Object[][] tableData;


    public MyTableModel(String[] headers, Object[][] tableData) {
        this.headers = headers;
        this.tableData = tableData;
    }

    @Override
    public int getColumnCount() {
        return headers.length;        //<<This line of code
    }

    public static void main(String[] args) {
        String fileName = "products.csv";

        String[] csvList = readCSV(fileName);

        String[] headers = Arrays.copyOfRange(csvList, 0, 10); 
        Object[][] tableData = ..MyTableModel.. // code to create this

        // now create a table model with your data and use it.
        MyTableModel myTableModel = new MyTableModel(headers, tableData);
    }

    private static String[] readCSV(String file) {
        String fileString = "";
        //Some code to fill the list.
        return fileString;
    }

}

Other issues: You should almost never implement TableModel but rather extend either DefaultTableModel or AbstractTableModel. Otherwise your model will miss most of the necessary machinery to make it work.

Regarding:

What if I made the instance field static as well? But assuming that no such easy option exists. Do I do away with my main() method? I suspected that a constructor would be better, but the main method was helpful for testing at first, and I was getting a lot of errors with the constructor I tried to build.

Again, avoid statics as this increases connectedness of your code, its "coupling" without benefit which greatly increases your risk of hard to find bugs as your program grows.

Regarding, "do I do away with my main method" -- but of course your program will need a main method somewhere, so you already know the answer to this. The main method should be small and should serve only to set the pieces of the application in motion, and nothing more.

regarding "I suspected that a constructor would be better, but the main method was helpful for testing at first, and I was getting a lot of errors with the constructor I tried to build." -- a constructor is necessary, the main method and the constructor are no mutually exclusive, and as for errors -- fix them, one at a time.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Firstly, thanks for your response! What if I made the instance field static as well? But assuming that no such easy option exists. Do I do away with my main() method? I suspected that a constructor would be better, but the main method was helpful for testing at first, and I was getting a lot of errors with the constructor I tried to build. – André Foote Nov 01 '16 at 03:35
  • @AndréFoote: a **very** bad idea. Stick with decent OOPs structure, and don't bend this structure to fix a fundamental problem with your code. Instead fix the fundamental problem itself. Please see edits to answer (soon). – Hovercraft Full Of Eels Nov 01 '16 at 03:37
  • @AndréFoote: see more edits to the answer. And please please please, never post code like that in a comment. As you can see, it cannot be formatted and is impossible to read. If you have significant questions about code, then edit your original question -- without destroying the original question, and show code there. – Hovercraft Full Of Eels Nov 01 '16 at 03:44
  • Yeah, sorry, first time I tried that and I've learned my lesson. Posted in the original question. – André Foote Nov 01 '16 at 03:46
  • yeah, fair enough. Pure Youtube is a a bit of a hacky way to go about this. You've given me a lot to go on though, much appreciated. – André Foote Nov 01 '16 at 03:49
  • @AndréFoote: you never appear to be adding your JTable to a JScrollPane nor the JScrollPane to your GUI -- does anything display? Also (and again) your implementing TableModel is something you shouldn't be doing as I doubt your model is "wired" to correctly notify the JTable of changes to its state. Again extend DefaultTableModel and use the methods it has to make your coding so much easier. – Hovercraft Full Of Eels Nov 01 '16 at 03:49
  • 1
    @AndréFoote: go to the main Java tutorials: [The Really Big Index](http://docs.oracle.com/javase/tutorial/reallybigindex.html), the main tutorial where you should start as well as the Swing tutorials: [Using Swing Components](http://docs.oracle.com/javase/tutorial/uiswing/components/index.html), how to create Swing GUI's. Also invest in a decent intro to Java book and go through it. You won't regret going through these. – Hovercraft Full Of Eels Nov 01 '16 at 03:51
  • Don't mean to pester you but I'd just like to say thanks again. It took some time, but looking at the second link helped sort things out for me. – André Foote Nov 01 '16 at 15:49