Delete row from JTable with custom table model - java

I've a subclass of JTable that uses a custom table model (an implementation of AbstractTableModel) to manage data.
The problem occurs when I try to delete a row with the method deleteRow. The row in my table is replaced by a blank string but the row is not deleted.
Here is the code:
public class LiveSearchTableModel extends AbstractTableModel
{
private List<String> columnNames = new ArrayList<String>();
private Map<Point, Object> displayData = new HashMap<Point, Object>();
private Map<Point, Object> originalData = new HashMap<Point, Object>();
public LiveSearchTableModel(List<String> columnNames,
Map<Point, Object> tableData)
{
this.columnNames = columnNames;
this.displayData = tableData;
this.originalData.putAll(tableData);
}
#Override
public int getColumnCount() {
return columnNames.size();
}
#Override
public int getRowCount() {
return displayData.size() / columnNames.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return displayData.get(new Point(rowIndex, columnIndex));
}
public void deleteRow (int row)
{
for (int cont = 0; cont < columnNames.size();cont++)
{
displayData.remove(new Point (row,cont));
}
this.fireTableRowsDeleted(row, row);
}
#Override
public void setValueAt(Object value, int rowIndex, int columnIndex)
{
this.displayData.put(new Point(rowIndex, columnIndex), value);
this.fireTableDataChanged();
}
}

The sscce below illustrates one potential problem: The keys of a Map are not ordered, while the rows of a table are. In the approach shown, an array of keys must by updated with each change to the data. See also this related example. If required, you could extend Point to implement Comparable, as shown here for Value.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
/**
* #see https://stackoverflow.com/q/12330167/230513
*/
public class TableModelTest extends JPanel {
public TableModelTest() {
super(new BorderLayout());
final MyModel model = new MyModel();
JTable table = new JTable(model);
this.add(new JScrollPane(table));
this.add(new JButton(new AbstractAction("Delete") {
#Override
public void actionPerformed(ActionEvent e) {
model.remove(0);
}
}), BorderLayout.SOUTH);
}
public class MyModel extends AbstractTableModel {
private List<String> names = new ArrayList<String>();
private Map<Point, Object> data = new HashMap<Point, Object>();
private Point[] keys;
public MyModel() {
this.names = Arrays.asList("Point", "Name");
data.put(new Point(1, 1), "One");
data.put(new Point(2, 2), "Two");
data.put(new Point(3, 3), "Three");
this.keys = data.keySet().toArray(new Point[data.size()]);
}
public void remove(int row) {
data.remove(keys[row]);
keys = data.keySet().toArray(new Point[data.size()]);
this.fireTableRowsDeleted(row, row);
}
#Override
public int getColumnCount() {
return names.size();
}
#Override
public String getColumnName(int col) {
return names.get(col);
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
if (col == 0) {
return keys[row];
} else {
return data.get(keys[row]);
}
}
}
private void display() {
JFrame f = new JFrame("TableModelTest");
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 TableModelTest().display();
}
});
}
}

Related

Java JTable mistake in copying rows

Good day!
There is a problem in downloaded program. You can copy a row by clicking on it by right mouse button, but after that when you change data in one cell data will be changed in every cell in column. Please, help me to understand, what I've missed.
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public class Main extends JFrame{
JMenuItem obrc;
JTable table;
DataModel tm;
JScrollPane scrollTable;
Main() {
super("Example JTable");
Container c = getContentPane();
ArrayList<String> columnNames = new ArrayList<String>();
columnNames.add("Type"); columnNames.add("Sort"); columnNames.add("Thickness"); columnNames.add("Width");
tm = new DataModel(columnNames);
table = new JTable(tm);
c.add(new JScrollPane(table), BorderLayout.CENTER);
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
table.getColumnModel().getColumn(0).setPreferredWidth(40);
table.getColumnModel().getColumn(1).setPreferredWidth(40);
table.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent event) {
if (SwingUtilities.isRightMouseButton(event)) {
JPopupMenu obrcd = new JPopupMenu();
obrc = new JMenuItem("Copy");
obrc.addActionListener(new MenuListener());
obrcd.add(obrc);
obrcd.show(c, event.getX(), event.getY());
}
}
});
}
public class MenuListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
int[] nums = table.getSelectedRows();
if (nums.length != 0) {
if (e.getSource() == obrc) {
ArrayList<Object[]> list = tm.getRows(nums);
tm.addRows(list);
}
else JOptionPane.showMessageDialog(null,
"Select at least one row", "Warning", JOptionPane.ERROR_MESSAGE);
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}
});
}
class DataModel extends AbstractTableModel{
ArrayList<Object[]> data = new ArrayList<Object[]>();
ArrayList<String> columnNames = new ArrayList<String>();
public DataModel(ArrayList<String> cNames){
super();
columnNames = cNames;
Object[] dat = new Object[4];
dat[0] = "board";
dat[1] = "1";
dat[2] = "25";
dat[3] = "150";
data.add(dat);
}
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return true;
}
public Object getValueAt(int rowIndex, int columnIndex){
Object[] row = data.get(rowIndex);
return row[columnIndex];
};
public void setValueAt(Object newValue, int rowIndex, int columnIndex){
data.get(rowIndex)[columnIndex] = newValue;
fireTableDataChanged();
}
public int getRowCount()
{
return data.size();
};
public int getColumnCount()
{
return columnNames.size();
};
public String getColumnName(int column)
{
return columnNames.get(column);
}
public ArrayList<Object[]> getRows(int[] nums) {
ArrayList<Object[]> newdata = new ArrayList<Object[]>();
for (int i = 0; i < nums.length; i++) {
newdata.add(data.get(nums[i]));
}
return newdata;
}
public void addRows (ArrayList<Object[]> rows) {
for (int i = 0; i < rows.size(); i++) data.add(rows.get(i));
fireTableDataChanged();
}
}
}
Problem when you are adding new rows
public void addRows (ArrayList<Object[]> rows) {
for (int i = 0; i < rows.size(); i++) data.add(rows.get(i));
fireTableDataChanged();
}
Your copied row(s) will point to same object(s) with selected row(s). You need clone to new object:
public void addRows (ArrayList<Object[]> rows) {
for (int i = 0; i < rows.size(); i++) {
Object[] clone = rows.get(i).clone();
data.add(clone);
}
fireTableDataChanged();
}

JAVA JTable datamodel columns names bug

I have the following "sample" code almost, but the column names dissapiared after ~2 hours codeing and i cant find where.
Can somebody tell me why the datamodel doesnt add the column names to the JTable?
My code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
class MyTableModel extends JPanel {
private static final int CHECK_COL = 3;
private static Object[][] DATA = {
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false},
{"","","",false},{"","","",false},{"","","",false},{"","","",false}
};
public static String[] COLUMNS = {"Debtid","Nev","VHO", "Check"};
protected DataModel dataModel = new DataModel(DATA, COLUMNS);
private JTable table = new JTable(dataModel);
private DefaultListSelectionModel selectionModel;
public MyTableModel(){
super(new BorderLayout());
this.add(table);
this.add(new ControlPanel(), BorderLayout.SOUTH);
table.setPreferredScrollableViewportSize(new Dimension(250, 175));
selectionModel = (DefaultListSelectionModel) table.getSelectionModel();
}
private class DataModel extends DefaultTableModel {
public DataModel(Object[][] data, Object[] COLUMNS) {
super(data, COLUMNS);
}
#Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == CHECK_COL) {
return getValueAt(0, CHECK_COL).getClass();
}
return super.getColumnClass(columnIndex);
}
#Override
public boolean isCellEditable(int row, int column) {
return true;
}
}
private class ControlPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = -7342459414751761853L;
public ControlPanel() {
this.add(new JLabel("Selection:"));
this.add(new JButton(new SelectionAction("Clear", false)));
this.add(new JButton(new SelectionAction("Check", true)));
}
}
private class SelectionAction extends AbstractAction {
boolean value;
public SelectionAction(String name, boolean value) {
super(name);
this.value = value;
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < dataModel.getRowCount(); i++) {
if (selectionModel.isSelectedIndex(i)) {
dataModel.setValueAt(value, i, CHECK_COL);
}
}
}
}
public void setValueAt_Cell(String val, int row, int col) {
// TODO Auto-generated method stub
if(row==DATA.length){
DATA=cloneArray(DATA);
}
dataModel.setValueAt(val, row, col);
}
public static Object[][] cloneArray(Object[][] src) {
int length = src.length;
Object[][] target = new Object[length+1][src[0].length];
for (int i = 0; i < length; i++) {
System.arraycopy(src[i], 0, target[i], 0, src[i].length);
}
target[length] = new Object[]{"","","",false};
return target;
}
public String getValAtPos(int row,int col) {
//System.out.println(dataModel.getValueAt(row, col));
return dataModel.getValueAt(row, col).toString();
}
public int getRowCount(){
return DATA.length;
}
}
You need to wrap JTable with JScrollPane : this.add(new JScrollPane(table));.

Seperate Char & Int into different JTable columns [duplicate]

I have a JTable populated with a custom DataModel (pasted below) and when I call the populate() method, it appears to populate the table with duplicate data - each row is filled with the same value over and over again. However, on closer inspection (by simply println()ing the 'data' field), the data model isn't at fault - it holds correct data, in the format I expect. What gives?
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
#SuppressWarnings("serial") // we don't expect this app to ever use serialized classes. EVER.
public class CollectionDataModel extends AbstractTableModel {
private ArrayList<ArrayList<String>> data;
public CollectionDataModel() {
data = new ArrayList<ArrayList<String>>();
}
#Override
public int getColumnCount() {
if(data.isEmpty()) return 0;
return data.get(0).size();
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
if(rowIndex > getRowCount()) return null;
if(columnIndex > getColumnCount()) return null;
return data.get(rowIndex).get(columnIndex);
}
public void populate(Collection c) {
data.clear();
for(Item i : c.getItems()) {
ArrayList<String> row = new ArrayList<String>();
for(Property p : i.getProperties().values()) {
row.add(p.toString());
}
data.add(row);
}
fireTableDataChanged();
}
}
Here's a complete example that may prove helpful. As the sample Map is unmodifiable, I refer you to #mKorbel's example on how to override isCellEditable() and setValueAt().
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
/** #see https://stackoverflow.com/questions/9132987 */
public class EnvTableTest extends JPanel {
public EnvTableTest() {
this.setLayout(new GridLayout());
this.add(new JScrollPane(new JTable(new EnvDataModel())));
}
private static class EnvDataModel extends AbstractTableModel {
private Map<String, String> data = System.getenv();
private String[] keys;
public EnvDataModel() {
keys = data.keySet().toArray(new String[data.size()]);
}
#Override
public String getColumnName(int col) {
if (col == 0) {
return "Key";
} else {
return "Value";
}
}
#Override
public int getColumnCount() {
return 2;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int row, int col) {
if (col == 0) {
return keys[row];
} else {
return data.get(keys[row]);
}
}
}
private void display() {
JFrame f = new JFrame("EnvTableTest");
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 EnvTableTest().display();
}
});
}
}
You could try to make the changes of populate more atomic.
public void populate(Collection c) {
ArrayList<ArrayList<String>> data2 = new ArrayList<ArrayList<String>>();
for(Item i : c.getItems()) {
ArrayList<String> row = new ArrayList<String>();
for(Property p : i.getProperties().values()) {
row.add(p.toString());
}
data2.add(row);
}
data = data2;
fireTableDataChanged();
}
I am guessing that populate is called again before a prior populate call finished. And probably c is changed during its iteration.
1) your TableModel is un_completed, I miss there lots or required methods for JTable's life_cycle, starting with TableHeader etc.
2) since there are lots of AbstactTableModels based on HashMap, I'd suggest to return arrays type implemented in API directly
Vector<Vector<Object or String>> data;
String[][] or Object[][]
instead of
ArrayList<ArrayList<String>> data;
simple explanations is that XxxList returs column and Vector or String[] returns Row
3) I'd suggest to use DefaultTableModel directly then you'll never need to solve duplicates or missed column/row

How to implement checkbox list java

Probably a noob question, but im new to java. I have a need for a checkbox list which I found is not supported in swing, but I found this custom control here
http://www.devx.com/tips/Tip/5342
So I created a class file named CheckBoxList, and copied the code from the link into it:
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class CheckBoxList extends JList
{
protected static Border noFocusBorder =
new EmptyBorder(1, 1, 1, 1);
public CheckBoxList()
{
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
}
);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ?
getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ?
getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ?
UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
The problem is I don't know how to implement it in my GUI file. I tried a lot of code, but they never showed an example. Just
To use the class, simply instantiate it, then pass it an array of
JCheckBox objects (or subclasses of JCheckBox objects) by calling
setListData
So does that mean that I will not see the control in the Graphical Design view? My client wants to be able to edit it himself and add stuff so I want it to be easy and graphical if possible. If someone could show an example of instantiating it or give a good hint I would appreciate it. Thanks!
Can you just tell me how?
Use a one column JTable and an appropriate renderer and editor. Based on this example, the code below relies on the default renderer for a data value of type Boolean.Class. A more general example is cited here.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
/** #see https://stackoverflow.com/a/13919878/230513 */
public class CheckTable {
private static final CheckModel model = new CheckModel(5000);
private static final JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(150, 300);
}
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
JCheckBox jcb = (JCheckBox) super.prepareRenderer(renderer, row, column);
jcb.setHorizontalTextPosition(JCheckBox.LEADING);
jcb.setText(String.valueOf(row));
return jcb;
}
};
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("CheckTable");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0));
f.add(new JScrollPane(table));
f.add(new DisplayPanel(model));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class DisplayPanel extends JPanel {
private DefaultListModel dlm = new DefaultListModel();
private JList list = new JList(dlm);
public DisplayPanel(final CheckModel model) {
super(new GridLayout());
this.setBorder(BorderFactory.createTitledBorder("Checked"));
this.add(new JScrollPane(list));
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
dlm.removeAllElements();
for (Integer integer : model.checked) {
dlm.addElement(integer);
}
}
});
}
}
private static class CheckModel extends AbstractTableModel {
private final int rows;
private List<Boolean> rowList;
private Set<Integer> checked = new TreeSet<Integer>();
public CheckModel(int rows) {
this.rows = rows;
rowList = new ArrayList<Boolean>(rows);
for (int i = 0; i < rows; i++) {
rowList.add(Boolean.FALSE);
}
}
#Override
public int getRowCount() {
return rows;
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public String getColumnName(int col) {
return "Column " + col;
}
#Override
public Object getValueAt(int row, int col) {
return rowList.get(row);
}
#Override
public void setValueAt(Object aValue, int row, int col) {
boolean b = (Boolean) aValue;
rowList.set(row, b);
if (b) {
checked.add(row);
} else {
checked.remove(row);
}
fireTableRowsUpdated(row, row);
}
#Override
public Class<?> getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
return true;
}
}
}
The code is expecting a list of JCheckBox objects - so this works
CheckBoxList cbList = new CheckBoxList(); // the class you have
JCheckBox check1 = new JCheckBox("One");
JCheckBox check2 = new JCheckBox("two");
JCheckBox[] myList = { check1, check2}; list of checkbox object
cbList.setListData(myList); // set the list data for the object
Small Swing program using your class below
util;
import javax.swing.*;
public class HelloWorldSwing {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckBoxList cbList = new CheckBoxList();
JCheckBox check1 = new JCheckBox("One");
JCheckBox check2 = new JCheckBox("two");
JCheckBox[] myList = { check1, check2};
cbList.setListData(myList);
frame.getContentPane().add(cbList);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Set row height depend on JTextArea height

I have a problem and really don't know how to solve it.
I used some solutions from this forum but they don't work.
This is the piece of code:
package own_components.custom_components;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import own_components.localizable_components.LocalizableComponent;
import localization.GUILocalizationTags;
import localization.LocalizationManager;
public class OutputJTable extends JTable implements CustomComponent
{
private CustomTableModel dataModel = new CustomTableModel();
private List<String[]> data = new ArrayList<String[]>();
private final int COLUMNS_AMOUNT = 3;
private final int _1ST_COL_WIDTH = 25;
private final int _2ST_COL_WIDTH = 45;
private final int _3ND_COL_WIDTH = 505;
public OutputJTable()
{
setModel(dataModel);
setTableProperties();
dataModel.addTableModelListener(new TableModelListener(){
#Override
public void tableChanged(TableModelEvent paramTableModelEvent)
{
fitRowsHeight();
}
});
}
private void setTableProperties()
{
//some properties of table
}
public void setResultOutput(List<String[]> result)
{
data = new ArrayList<String[]>();
data.add(new String[] { "l", "code", "222222222222222222222222222 22ddddddddddddddddddddddddddd22222222222222222222222222222222" });
data.add(new String[] { "l", "code", "sssssssssssssssssssssssssssssss sssssssssssssssssssssssssssssssssssssssssssssssssss222222222" });
dataModel.fireTableDataChanged();
}
private void fitRowsHeight()
{
for (int row = 0; row < getRowCount(); row++)
{
int rowHeight = getRowHeight();
Component comp = prepareRenderer(getCellRenderer(row, 2), row, 2);
rowHeight = Math.max(rowHeight, comp.getSize().height);
setRowHeight(row, rowHeight);
}
}
public int getSelectedRow()
{
return selectedRow;
}
private class CustomTableModel extends AbstractTableModel implements LocalizableComponent
{
private static final long serialVersionUID = -992340559233338699L;
private String[] columnsNames = { "a", "b", "c" };
#Override
public String getColumnName(int paramInt)
{
return columnsNames[paramInt];
}
#Override
public boolean isCellEditable(int paramInt1, int paramInt2)
{
return false;
}
#Override
public int getColumnCount()
{
return COLUMNS_AMOUNT;
}
#Override
public int getRowCount()
{
return data.size();
}
#Override
public String getValueAt(int arg0, int arg1)
{
return data.get(arg0)[arg1];
}
#Override
public void useTranslatedText(String tag)
{
columnsNames[1] = tag;
getColumnModel().getColumn(2).setHeaderValue(tag);
repaint();
}
#Override
public void registerToLocalization(LocalizationManager lm, String key)
{
lm.registerToTranslationList(this, GUILocalizationTags.OUT_TAB_DESCRIPTION);
}
}
private class CustomTableRenderer extends DefaultTableCellRenderer
{
JTextArea cellTemp = new JTextArea();
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
cellTemp = new JTextArea(data.get(row)[column]);
cellTemp.setLineWrap(true);
return cellTemp;
}
}
}
This is little bit long but rather simple: my table uses custom cell renderer which contains JTextArea. I use JTA because I need Strings wrapping. After put such JTextAreas I expect to set row heights to highest JTA in a row.
And here is the problem. In code above I expect to receive JTA.height but I still receive "0". The same situation with JTA.getRows().
I really don't understand why. Can anybody explain me what is wrong with this code?
This is working JTable with wrapped strings.
(I used solutions introduced by mKorbel in this thread How to make a JTable column to contain not JTextFields, but JTextAreas)
package own_components.custom_components;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.View;
public class OutputJTable extends JTable
{
private static final long serialVersionUID = 1L;
private List<String[]> data = new ArrayList<String[]>();
private CustomTableModel dataModel = new CustomTableModel();
private final int COLUMNS_AMOUNT = 3;
private final int _1ST_COL_WIDTH = 25;
private final int _2ST_COL_WIDTH = 45;
private final int _3ND_COL_WIDTH = 505;
private int selectedRow = -1;
public OutputJTable()
{
setModel(dataModel);
setDefaultRenderer(Object.class, new CustomTableRenderer());
setTableProperties();
}
/**
* Sets basic table properties.
*/
private void setTableProperties()
{
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
getColumnModel().getColumn(0).setMaxWidth(_1ST_COL_WIDTH);
getColumnModel().getColumn(0).setMinWidth(_1ST_COL_WIDTH);
getColumnModel().getColumn(1).setMaxWidth(_2ST_COL_WIDTH);
getColumnModel().getColumn(1).setMinWidth(_2ST_COL_WIDTH);
getColumnModel().getColumn(2).setMaxWidth(_3ND_COL_WIDTH);
getColumnModel().getColumn(2).setMinWidth(_3ND_COL_WIDTH);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setIntercellSpacing(new Dimension(0, 0));
setShowGrid(false);
}
/**
* Receives data used to modified data showned in table.
* This should be only access point to add data used by data model (which is used by jtable).
*
* #param result
*/
public void setResultOutput(List<String[]> result)
{
data = new ArrayList<String[]>();
data = result;
dataModel.fireTableDataChanged();
}
#Override
public void doLayout()
{
super.doLayout();
for (int row = 0; row < getRowCount(); row++)
{
JTextArea a = (JTextArea) prepareRenderer(getDefaultRenderer(Object.class), row, 2);
int rowHeight = (int) a.getUI().getRootView(a).getView(0).getPreferredSpan(View.Y_AXIS) + getIntercellSpacing().height;
setRowHeight(row, rowHeight);
}
}
/**
* Returns which row is selected. Main purpose of this method is provide data to PrintManager what should be printed.
*/
public int getSelectedRow()
{
return selectedRow;
}
#Override
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
{
if (rowIndex != selectedRow)
{
selectedRow = rowIndex;
}
else
{
selectedRow = -1;
}
super.changeSelection(rowIndex, columnIndex, true, false);
}
/**
* This is model used to fill this table with data.
*/
private class CustomTableModel extends DefaultTableModel implements LocalizableComponent
{
private static final long serialVersionUID = -992340559233338699L;
private String[] columnsNames = { "a", "b", "c" };
#Override
public String getColumnName(int paramInt)
{
return columnsNames[paramInt];
}
#Override
public boolean isCellEditable(int paramInt1, int paramInt2)
{
return false;
}
#Override
public int getColumnCount()
{
return COLUMNS_AMOUNT;
}
#Override
public int getRowCount()
{
return data.size();
}
#Override
public String getValueAt(int arg0, int arg1)
{
return data.get(arg0)[arg1];
}
}
/**
* This class is used to render single cell.
*/
private class CustomTableRenderer extends JTextArea implements TableCellRenderer
{
private final Color SELECTION_BORDER = new Color(200, 200, 200);
private final Color ODD_BACKGR_COLOR = new Color(240, 240, 240);
private final Color EVEN_BACKGR_COLOR = Color.WHITE;
CustomTableRenderer()
{
setLineWrap(true);
setWrapStyleWord(true);
setEditable(false);
setFont(getFont());
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
setText((String) value);
setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
if (isSelected)
{
setBackground(SELECTION_BORDER);
}
else if (row % 2 != 0)
{
setBackground(ODD_BACKGR_COLOR);
}
else
{
setBackground(EVEN_BACKGR_COLOR);
}
return this;
}
}
}
Remarks:
formating of row height is based on third column, if you want to take under consideration all columns, you have to use additional "for" loop in doLayout(),
'dataModel' of this JTable is based on the List 'model',
setResultOutput() expect String[3]
Thanks for everybodys help.
Regards.

Categories