I'm new to Java Swing and I'm working with JTable.
Actually, I have difficulty in sorting of this component.
I want to enable and disable this function programatically.
I use JTable.setAutoCreateSorter(true) to initialize it, I change to false, nothing happen.
Also, I had use JTable.setRowSorter(null), it works, but I do not know how to enable it again.
Sorry for my poor English!
You can use setSortable(int index, boolean sortable) method of DefaultRowSorter.
for (int i=0 ; i<table.getColumnCount() ; i++) {
sorter.setSortable(i, false);
}
This worked for me. See also JTable sorting programatically only
Inspecting at JTable.setAutoCreateRowSorter(boolean autoCreateRowSorter) source code:
public void setAutoCreateRowSorter(boolean autoCreateRowSorter) {
boolean oldValue = this.autoCreateRowSorter;
this.autoCreateRowSorter = autoCreateRowSorter;
if (autoCreateRowSorter) {
setRowSorter(new TableRowSorter<TableModel>(getModel()));
}
firePropertyChange("autoCreateRowSorter", oldValue,
autoCreateRowSorter);
}
So, you have two options:
Keep a reference to the row sorter to restore it later, as #nachokk suggested.
Set a new TableRowSorter instance:
table.setRowSorter(new TableRowSorter(table.getModel()));
Edit
But now the table's rows are not selectable
That's weird, I didn't have any problem with row selection. Here is the code I've used to test my answer:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
public class Demo {
private void createAndShowGUI() {
DefaultTableModel model = new DefaultTableModel(new Object[]{"Column # 1", "Column # 2"}, 0){
#Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex) {
case 0: return String.class;
case 1: return Integer.class;
default: return super.getColumnClass(columnIndex);
}
}
};
for (int i = 0; i < 20; i++) {
model.addRow(new Object[]{"Property # " + i, Integer.valueOf(i)});
}
final JTable table = new JTable(model);
table.setAutoCreateRowSorter(true);
JToggleButton toggleButton = new JToggleButton("Disable", true);
toggleButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JToggleButton toggleButton = (JToggleButton)e.getSource();
String text = toggleButton.isSelected() ? "Disable" : "Enable";
TableRowSorter sorter = toggleButton.isSelected() ? new TableRowSorter(table.getModel()) : null;
toggleButton.setText(text);
table.setRowSorter(sorter);
}
});
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new JScrollPane(table), BorderLayout.CENTER);
frame.add(toggleButton, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
Related
I have a table in which a column needs to be a 'checkbox-column". And I wrote the code like this.
import javax.swing.DefaultCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class Test0 {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test0 test = new Test0();
test.launch();
}
});
}
private void launch() {
JFrame frame = new JFrame();
Object[][] data = {{Boolean.TRUE}};
String[] columnName = {"Checkbox here!"};
#SuppressWarnings("serial")
JTable table = new JTable(new DefaultTableModel(data,columnName) {
#Override
public Class<?> getColumnClass(int columnIndex){
return Boolean.class;
}
});
JCheckBox checkBox = new JCheckBox("HI");
table.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(checkBox));
JScrollPane tableScrollPane = new JScrollPane(table);
frame.add(tableScrollPane);
frame.pack();
frame.setVisible(true);
}
}
When I run this, the checkbox with a "HI" label was not there as I want to be.
Instead, a normal checkbox appeared and when I clicked that, my checkbox appeared and disappeared quickly.
I don't understand what caused that. Please help me. Thank you.
In my application everything is distributed.
On a action, application retrieves data from DB and saves in ArrayList<T>.
I create an object of RelativeTableModel where I pass the ArrayList<T>.
public void RelationsClicked() {
ArrayList<Relation> data = myParent.dbOperation.getRelations();
RelativeTableModel tModel = new RelativeTableModel(data); // subclass of AbstractTableModel
myParent.SetBrowsePanelData(tModel);
myParent.SetMainPanel(CashAccountingView.BROWSEPANEL);
}
I have a BrowseListPanel class that has a JTable in JScrollPane. Its instance is already created in the main application.
I pass the model to BrowseListPanel and finally show the panel.
Code:
public void SetBrowsePanelData(AbstractTableModel tModel) {
browsePanel.setTModel(tModel);
}
// BrowseListPanel's Code
public void setTModel(AbstractTableModel tModel) {
this.tModel = tModel; // tModel = AbstractTableModel
}
// Show the Panel
public void SetMainPanel(String panel) {
activePanel = panel;
SetFontSize();
cards.show(mainPanel, panel);
mainPanel.revalidate();
mainPanel.repaint();
}
But I don't see the Table. I believe as the object of BrowseListPanel (containing the JTable) is already created & later the TableModel is added. So some sort of event should be fired in setTModel().
Am I right? If so, what event should be thrown and what should be its implementation.
Invoking setModel() on the table should be sufficient, but you might call fireTableStructureChanged() on the model explicitly as a way to help sort things out.
Also, verify that you are working on the event dispatch thread.
Addendum: Here's an sscce that shows the basic approach.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
/** #see http://stackoverflow.com/questions/8257148 */
public class SwapTableModel extends JPanel {
public SwapTableModel() {
final JTable table = new JTable(Model.Alpha.model);
table.setPreferredScrollableViewportSize(new Dimension(128, 32));
this.add(new JScrollPane(table));
final JComboBox combo = new JComboBox();
for (Model model : Model.values()) {
combo.addItem(model);
}
this.add(combo);
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Model model = (Model) combo.getSelectedItem();
table.setModel(model.model);
}
});
}
private enum Model {
Alpha(), Beta();
private DefaultTableModel model;
private Model() {
Object[] data = {this.toString()};
this.model = new DefaultTableModel(data, 1);
model.addRow(data);
}
}
private void display() {
JFrame f = new JFrame("SwapTableModel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SwapTableModel().display();
}
});
}
}
I have in my application two ComboBoxes for rows and columns for each JTable. Shown below:
I want to add and remove rows and columns in each table dynamically. I know I would do something like table.add() but what about remove? For example if user selects 3 from Row combobox, it should add another row to it but what if user selects 2 back? It should remove that row inserted. So how do I do that?
I know it can be a stupid question but I am a newbie to Swing so people can't really expect much from me :(
It seems that you want to control the dimension of the table using combo boxes. JTable renderers its underlying data model. Read more about tables in How to Use Tables. Adding and removing rows is actually manipulation of the data model. For example DefaultTableModel has many methods useful for your task: addRow(), removeRow(), getRowCount() etc.
It all depends on the data and task required. Check out this simple example that uses a custom table model that wraps Apache's RealMatrix. You can choose whatever data structure you need. DefaultTableModel is also good an may be sufficient. The example has two combo boxes that adjust table size.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.RealMatrix;
public class TestTableDims extends JPanel{
private MyTableModel model;
private JTable table;
private JComboBox rowsCombo;
private JComboBox columnsCombo;
public TestTableDims() {
setLayout(new BorderLayout(5, 5));
model = new MyTableModel(2, 2);
JPanel buttonsPanel = new JPanel();
Integer[] test = {1, 2, 3, 4, 5};
rowsCombo = new JComboBox(test);
rowsCombo.setSelectedItem(2);
rowsCombo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.setRows(((Integer)rowsCombo.getSelectedItem()));
}
});
buttonsPanel.add(new JLabel("rows"));
buttonsPanel.add(rowsCombo);
columnsCombo = new JComboBox(test);
columnsCombo.setSelectedItem(2);
columnsCombo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.setColumns(((Integer)columnsCombo.getSelectedItem()));
}
});
buttonsPanel.add(new JLabel("columns"));
buttonsPanel.add(columnsCombo);
add(buttonsPanel, BorderLayout.NORTH);
JTable table = new JTable();
table.setModel(model);
add(new JScrollPane(table));
}
class MyTableModel extends AbstractTableModel {
private RealMatrix matrix;
public MyTableModel(int rows, int columns) {
matrix = new Array2DRowRealMatrix(rows, columns);
}
public void setRows(int rows) {
matrix = new Array2DRowRealMatrix(rows, matrix.getColumnDimension());
fireTableStructureChanged();
}
public void setColumns(int columns) {
matrix = new Array2DRowRealMatrix(matrix.getRowDimension(), columns);
fireTableStructureChanged();
}
#Override
public int getColumnCount() {
return matrix.getColumnDimension();
}
#Override
public int getRowCount() {
return matrix.getRowDimension();
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return Double.class;
}
#Override
public void setValueAt(Object value, int row, int column) {
matrix.setEntry(row, column, (double)value);
}
#Override
public Object getValueAt(int row, int column) {
return matrix.getEntry(row, column);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
TestTableDims panel = new TestTableDims();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
});
}
}
I have a Jtable in which I want to add a JCheckbox in one column. However, when I create a JCheckbox object, javax.swing.JCheckBox is being displayed in the column.Please refer to the image. Can you tell me how to amend that please? I have searched everywhere but cannot seem to find any solution for it. Thank you.
don't add components to your TableModel, that's not the responsibility of the TableModel
You will need to specify the class type of your column. Assuming you're using a DefaultTableModel, you can simply fill the column with a bunch of booleans and this should work - After testing, you will need to override the getColumnClass method of the DefaultTableModel (or what ever TableModel implementation) and make sure that for the "check box" column, it returns Boolean.class
See How to use tables for more details
For example...
import java.awt.EventQueue;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class TestCardLayout {
public static void main(String[] args) {
new TestCardLayout();
}
public TestCardLayout() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
Random rnd = new Random();
DefaultTableModel model = new DefaultTableModel(new Object[]{"Check boxes"}, 0) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return Boolean.class;
}
};
for (int index = 0; index < 10; index++) {
model.addRow(new Object[]{rnd.nextBoolean()});
}
JTable table = new JTable(model);
final JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I'm working with JTables to display information that users can filter, and if the user saves after filtering I want to save the filtered table to a textfile for persistence (meaning anything that got filtered out will not be saved to the textfile).
For filtering I just followed the filtering part of this tutorial: http://download.oracle.com/javase/tutorial/uiswing/components/table.html#sorting and it works fine, but I'm not sure of any way that I can get a model of the current display as opposed to the underlying model that contains everything that hasn't been filtered out.
Is there any way to do this with this with the way that I'm filtering?
Thanks!
Ask the table its number of rows (using getRowCount()), which will return the number of filtered (visible) rows. Iterate from 0 to the rowCount, convert each row index to the model index using convertRowIndexToModel(), and ask your model the data at each model index to build the list of filtered (visible) data.
This code shows how to do this. Please note that B row is not printed to the input after the button is pressed.
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class JTableFilterDemo {
public static void main(String[] args) {
Object[][] data = { { "A", 5 }, { "B", 2 }, { "C", 4 }, { "D", 8 } };
String columnNames[] = { "Item", "Value" };
TableModel model = new DefaultTableModel(data, columnNames) {
public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
JTable table = new JTable(model);
RowFilter<Object, Object> filter = new RowFilter<Object, Object>() {
public boolean include(Entry entry) {
Integer population = (Integer) entry.getValue(1);
return population.intValue() > 3;
}
};
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
model);
sorter.setRowFilter(filter);
table.setRowSorter(sorter);
JScrollPane scrollPane = new JScrollPane(table);
JFrame frame = new JFrame("Filtering Table");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnNewButton = new JButton("Print values");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for(int row = 0;row < table.getRowCount();row++) {
System.out.println(table.getModel().getValueAt(table.convertRowIndexToModel(row), 0));
}
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
frame.getContentPane().add(scrollPane);
frame.setSize(300, 200);
frame.setVisible(true);
}
}