I have a JFrame
which holds a JXTable
(from SwingX dependency) and a JButton
.
Once I click the JButton the table should get updated each time. In my case it gets updated only at the first time. Other events also get triggered on the button click (which happens each time I click the button). Only the table is not refreshed with the new rows added.
I am using DeafultTableModel
and have tried (explicit trigger) all suggested methods like repaint
, fireTableDataChanged
etc.
Can someone please help?
EDIT-1 (code snippet added): -
// the actions will take place when VALIDATE button is clicked
validateButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
if (evCheckbox1.isSelected() || !list.isSelectionEmpty()) {
try {
// store the validation errors for future use
List<List<String>> validationErrors = validateSheet(Driver.this.fileLocation, list
.getSelectedValuesList(), regulatorTypeCB.getSelectedItem().toString(), sheetTypeCB
.getSelectedItem().toString());
// creates the validation error overview to be added to roTable
Map<String, Integer> tmpMap = getValidationErrorsOverview(validationErrors);
System.out.println(tmpMap);
// create the report overview table
String[] columnNames = {"SHEET_NAME", "VALIDATION_NAME", "#"};
DefaultTableModel tmodel = new DefaultTableModel(0, 0);
tmodel.setColumnIdentifiers(columnNames);
JXTable roTable = new JXTable();
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
roTable.addHighlighter(HighlighterFactory.createSimpleStriping());
List<String> tlist = new ArrayList<String>();
JScrollPane scrPane = new JScrollPane(roTable);
scrPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
scrPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
overviewPanel.add(scrPane);
// create a list from the validation error overview map to insert as a row in table
for (Map.Entry<String, Integer> entry : tmpMap.entrySet()) {
tlist.add(entry.getKey().split(":")[0]);
tlist.add(entry.getKey().split(":")[1]);
tlist.add(String.valueOf(entry.getValue()));
}
// add rows in table
for (int i = 0; i < tmpMap.size(); i++) {
tmodel.addRow(new Object[] {tlist.get((i * 3) + 0), tlist.get((i * 3) + 1),
tlist.get((i * 3) + 2)});
}
FileUtils.writeStringToFile(logFile, "\n" + new Date().toString() + "\n", true);
roTable.setModel(tmodel);
roTable.repaint();
// frame refresh
Driver.this.frame.revalidate();
Driver.this.frame.repaint();
// open the log file in notepad.exe
ProcessBuilder pb = new ProcessBuilder("Notepad.exe", "verifier.log");
pb.start();
} catch (BiffException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
There are some conceptual mistakes in the lines below:
String[] columnNames = {"SHEET_NAME", "VALIDATION_NAME", "#"};
DefaultTableModel tmodel = new DefaultTableModel(0, 0);
tmodel.setColumnIdentifiers(columnNames);
JXTable roTable = new JXTable();
...
JScrollPane scrPane = new JScrollPane(roTable);
...
overviewPanel.add(scrPane);
1) Don't create a new JXTable
when you press the button but work with the table model instead either by clearing the current table model and adding rows to it or directly by setting a new one. For example:
String[] columnNames = {"SHEET_NAME", "VALIDATION_NAME", "#"};
DefaultTableModel tmodel = new DefaultTableModel(0, 0);
tmodel.setColumnIdentifiers(columnNames);
yourTable.setModel(tmodel);
2) These lines suggests that overviewPanel
has already been displayed by the time you are trying to add the new table by clicking the button, thus invalidating the components hierarchy and in consequence you have to revalidate and repaint the panel like this:
overviewPanel.add(scrPane);
overviewPanel.revalidate();
overviewPanel.repaint();
However while we can add components dynamically in Swing we tipically place all our components before the top-level container (window) is made visible. Thus the approach described in point 1 is highly preferable over this one and I'm adding this point just for completeness.
3) Be aware that time consuming tasks such as database calls or IO operations may block the Event Dispatch Thread (EDT) causing the GUI become unresponsive. The EDT is a single and special thread where Swing components creation and update take place. To avoid block this thread consider use a SwingWorker to perform heavy tasks in a background thread and update Swing components in the EDT. See more in Concurrency in Swing lesson.
Update
Please consider the following example illustrating point 1:
- The table is created and placed once before making the top-level container (window) visible.
- Both actions work with the table model: one of them sets a new table model and the other one clear and re-fill the current table model.
Here is the code. Hope it helps!
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import org.jdesktop.swingx.JXTable;
public class Demo {
private void createAndShowGUI() {
final JXTable table = new JXTable(5, 6);
table.setPreferredScrollableViewportSize(new Dimension(500, 200));
Action resetModelAction = new AbstractAction("Set a new model") {
@Override
public void actionPerformed(ActionEvent e) {
Random random = new Random(System.currentTimeMillis());
DefaultTableModel model = new DefaultTableModel(0, 6);
for (int i = 0; i < model.getColumnCount(); i++) {
model.addRow(new Object[]{
random.nextInt(),
random.nextInt(),
random.nextInt(),
random.nextInt(),
random.nextInt(),
random.nextInt()
});
}
table.setModel(model);
}
};
Action clearAndFillModelAction = new AbstractAction("Clear and fill model") {
@Override
public void actionPerformed(ActionEvent e) {
Random random = new Random(System.currentTimeMillis());
DefaultTableModel model = (DefaultTableModel)table.getModel();
model.setRowCount(0); // clear the model
for (int i = 0; i < model.getColumnCount(); i++) {
model.addRow(new Object[]{
random.nextInt(),
random.nextInt(),
random.nextInt(),
random.nextInt(),
random.nextInt(),
random.nextInt()
});
}
}
};
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(new JButton(resetModelAction));
buttonsPanel.add(new JButton(clearAndFillModelAction));
JPanel content = new JPanel(new BorderLayout(8,8));
content.setBorder(BorderFactory.createEmptyBorder(8,8,8,8));
content.add(new JScrollPane(table));
content.add(buttonsPanel, BorderLayout.PAGE_END);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
来源:https://stackoverflow.com/questions/26629763/jxtable-not-refreshed-upon-button-click