Frage

I am working on a the GUI of a piece of code that I have been patching together. I am stuck at this part of the program where I would like a datafile the user chooses to be displayed in a JTable in a preview manner (i.e. the user should not be able to edit the data on the table).

With a button click from Experiment Parameters tab (see screenshot below), I create and run a "PreviewAction" which creates a new tab, and fills it up with the necessary components. Below is the code for DataPreviewAction. EDIT: I also posted a self-contained, minimal version of this that mimics the conditions in the real project, and exhibits the same behaviour.

import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class MyFrame extends JFrame {

private JPanel panel1;
private JTabbedPane tabs;
private JButton runButton;

public MyFrame() {
    tabs = new JTabbedPane();
    panel1 = new JPanel();
    runButton = new JButton("go!");
    runButton.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            runButtonActionPerformed(evt);
        }
    });
    panel1.add(runButton);
    tabs.addTab("first tab", panel1);
    this.add(tabs);
    pack();
}

public static void main(String args[]) {
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager
                .getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(MyFrame.class.getName()).log(
                java.util.logging.Level.SEVERE, null, ex);
    }

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {

        public void run() {
            MyFrame frame = new MyFrame();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
    /*
     * Normally there is more stuff happening here but this much will do for
     * the sake of example
     */
    List<String[]> data = new LinkedList<String[]>();
    for (int i = 1; i < 1000; i++)
        data.add(new String[] { "entry1", "value1", "value2", "value3" });

    SwingUtilities.invokeLater(new DataPreviewAction(data, tabs));
}

public class DataPreviewAction implements Runnable {

    private JTabbedPane contentHolder;
    private List<String[]> data;

    public DataPreviewAction(List<String[]> data, JTabbedPane comp) {
        this.contentHolder = comp;
        this.data = data;
    }

    @Override
    public void run() {
        DefaultTableModel previewModel = new DefaultTableModel() {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };

        for (String[] datarow : data) {
            previewModel.addRow(Arrays.copyOf(datarow, datarow.length,
                    Object[].class));
        }

        JTable table = new JTable(previewModel);

        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton("A button"));
        buttonPanel.add(new JLabel(
                "Some description for the awesome table below "));
        buttonPanel.add(new JButton("another button"));

        JScrollPane tablePanel = new JScrollPane(table);
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(buttonPanel, BorderLayout.NORTH);
        container.add(tablePanel, BorderLayout.CENTER);
        contentHolder.addTab("Preview", container);
        contentHolder.validate();
        contentHolder.repaint();
    }
}
}

There are at least two problems here:

  1. The JTable (or the JScrollPane) does not render at all
  2. The JScrollPane is not as wide as the frame itself, I have no idea why

I am not all that good in Swing so I might be missing something fundamental. I have checked that the datafile is read properly, and the data model contains the right amount of rows (1000+). SO the table should not be empty.

Suggestions?

screenshot of the problem

War es hilfreich?

Lösung 2

Following the footsteps of mKorbel I ended up doing some debugging. I am providing it here in case others run into the same problem.

It felt quite odd that the table looked OK when the underlying DataModel was supplied a data matrix upon initialisation

private DefaultTableModel model = new DefaultTableModel(data, columnNames)

but it would not show up properly when created with the empty constructor

private DefaultTableModel model = new DefaultTableModel()

and adding rows later with model.addRow(Object[] row);

I started look through the source code, and it turns out with the empty constructor the number of rows and columns for the model (private fields) is initiated to 0 and not updated properly afterwards. I noticed this while debugging since my tables had the dimension of 1370 x 0, which of course does not display properly.

Since I do not want to hardcode the number of rows/cols in advance the best course of action was to convert my "rows" to a matrix and provide the data to the model via constructor (much like mKorbel did). Here comes the fun part, if you want to supply the data then you need to supply the column names as well. THe fact that you have to have column names is counter-intuitive (IMHO), what happens if you dont have/need headers? The data is already in a table form, so I dont understand why column names is so important.

At any rate the following code renders the table at least:

String[] colNames = new String[data[1].length];
for(int i=0; i<colNames.length; i++)
    colNames[i] = "C" + i;

DefaultTableModel model = new DefaultTableModel(data,colNames){
    @Override
    public boolean isCellEditable(int row, int column){
        return false;
    }};

I am accepting this because it points to the origin of the problem, but I would not be able to pinpoint the problem without mKorbel's answer, so give the upvote to his/her answer :)

Andere Tipps

JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton("A button"));
buttonPanel.add(new JLabel("Some description for the awesome table below "));
buttonPanel.add(new JButton("another button"));

JScrollPane tablePanel = new JScrollPane(table);
JPanel container = new JPanel();
container.add(buttonPanel,BorderLayout.NORTH);
container.add(tablePanel,BorderLayout.SOUTH);
contentHolder.addTab("Preview", container);
    //contentHolder.validate(); <- NO good
    //contentHolder.repaint();  <- --"---
}
  • JPanel uses FlowLayout (implemented in API, acceptiong only PreferredSize, by default isn't resizable), correct output as is demonstrated in attn image, you have to change default LayoutManager for JPanel to BorderLayout, then code lines

.

container.add(buttonPanel,BorderLayout.NORTH);
container.add(tablePanel,BorderLayout.SOUTH);
  • will expands JComponents and can be works as you expecting, but I think tablePanel should be placed in CENTER area

EDIT:

enter image description here

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class MyFrame extends JFrame {

    private JPanel panel1;
    private JTabbedPane tabs;
    private JButton runButton;
    private JFrame frame = new JFrame();
    private String[] columnNames = {"Nama", "Nim", "IP", "Hapus Baris ke"};
    private Object[][] data = {
        {"igor", "B01_125-358", "1.124.01.125", true},
        {"lenka", "B21_002-242", "21.124.01.002", true},
        {"peter", "B99_001-358", "99.124.01.001", false},
        {"zuza", "B12_100-242", "12.124.01.100", true},
        {"jozo", "BUS_011-358", "99.124.01.011", false},
        {"nora", "B09_154-358", "9.124.01.154", false},
        {"xantipa", "B01_001-358", "1.124.01.001", false},};
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
        private static final long serialVersionUID = 1L;

        @Override
        public boolean isCellEditable(int row, int column) {
            switch (column) {
                case 3:
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public Class getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };

    public MyFrame() {
        tabs = new JTabbedPane();
        panel1 = new JPanel();
        runButton = new JButton("go!");
        runButton.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                //
            }
        });
        panel1.add(runButton);
        tabs.addTab("first tab", panel1);
        JTable table = new JTable(model);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton("A button"));
        buttonPanel.add(new JLabel("Some description for the awesome table below "));
        buttonPanel.add(new JButton("another button"));
        JScrollPane tablePanel = new JScrollPane(table);
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(buttonPanel, BorderLayout.NORTH);
        container.add(tablePanel, BorderLayout.CENTER);
        tabs.addTab("Preview", container);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(tabs);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyFrame frame = new MyFrame();

            }
        });
    }
}

EDIT 2nd. e.g.

enter image description here

from code (included your idea about to fill data to model)

import java.awt.BorderLayout;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class MyFrame extends JFrame {

    private JPanel panel1;
    private JTabbedPane tabs;
    private JButton runButton;
    private JFrame frame = new JFrame();
    private String[] columnNames = {"Nama", "Nim", "IP", "Hapus Baris ke"};
    private Object[][] data = {
        {"igor", "B01_125-358", "1.124.01.125", "true"},
        {"lenka", "B21_002-242", "21.124.01.002", "true"},
        {"peter", "B99_001-358", "99.124.01.001", "false"},
        {"zuza", "B12_100-242", "12.124.01.100", "true"},
        {"jozo", "BUS_011-358", "99.124.01.011", "false"},
        {"nora", "B09_154-358", "9.124.01.154", "false"},
        {"xantipa", "B01_001-358", "1.124.01.001", "false"},};
    private DefaultTableModel model = new DefaultTableModel(data, columnNames) {
        private static final long serialVersionUID = 1L;

        @Override
        public boolean isCellEditable(int row, int column) {
            switch (column) {
                case 3:
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public Class getColumnClass(int column) {
            return getValueAt(0, column).getClass();
        }
    };

    public MyFrame() {
        tabs = new JTabbedPane();
        panel1 = new JPanel();
        runButton = new JButton("go!");
        runButton.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                List<String[]> data = new LinkedList<String[]>();
                for (int i = 1; i < 10; i++) {
                    data.add(new String[]{"entry1", "value1", "value2", "value3"});
                }
                for (String[] datarow : data) {
                    model.addRow(Arrays.copyOf(datarow, datarow.length, Object[].class));
                }
            }
        });
        panel1.add(runButton);
        tabs.addTab("first tab", panel1);
        JTable table = new JTable(model);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton("A button"));
        buttonPanel.add(new JLabel("Some description for the awesome table below "));
        buttonPanel.add(new JButton("another button"));
        JScrollPane tablePanel = new JScrollPane(table);
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(buttonPanel, BorderLayout.NORTH);
        container.add(tablePanel, BorderLayout.CENTER);
        tabs.addTab("Preview", container);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(tabs);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyFrame frame = new MyFrame();

            }
        });
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top