remove unused rows in jtable (Empty Rows)? - java

a question about removing unused rows in jtable i am using DefualtTableModel my table already has some data & when i update it leave some columns empty to update theme later so they are null column.. i want to remove theme with a push button before saving data.. i actually tried this code:
private void btn_ClearActionPerformed(java.awt.event.ActionEvent evt) {
table.setAutoCreateRowSorter(true);
TableRowSorter sorter = (TableRowSorter) table.getRowSorter();
sorter.setRowFilter(new RowFilterImpl());
}
i also tried this:
private void btn_ClearActionPerformed(java.awt.event.ActionEvent evt) {
table.setAutoCreateRowSorter(true);
TableRowSorter sorter = (TableRowSorter) table.getRowSorter();
sorter.setRowFilter(new RowFilter<TableModel, Integer>() {
#Override
public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
boolean included = true;
Object cellValue = entry.getModel().getValueAt(entry.getIdentifier(), 0);
if (cellValue == null || cellValue.toString().trim().isEmpty()) {
included = false;
}
return included;
}
});
}
the code above is working but i don't like it becuase it resizes rows after filtering so i want to do something with model.remove(); using if conditions.. and i want to specify columns for example column 7 & 12 and want to remove only empty rows in specified columns..
ok i tried this code:
for (int i = model.getRowCount() - 1; i >= 0; i--)
{
Object col1 = model.getValueAt( i,model.getColumnCount() - 6);
Object col2 = model.getValueAt( i,model.getColumnCount() - 11);
if (col1 == null || col2 == null)
model.removeRow(i);
}
i faced same problem and i found this code below cuasing that problem so i removed it ... i also found that it counts how many time you selected or clicked on a row and then resizes it as many you clicked!
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
int lastRow = -1;
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
if (lastRow != -1) {
table.setRowHeight(lastRow, table.getRowHeight());
}
int row = table.getSelectedRow();
table.setRowHeight(row, 23);
lastRow = row;
}
}
});
any idea guys?
thanx in advance

Create a loop to remove the data from the model.
Maybe something like:
for (int i = model.getRowCount() - 1; i >= 0; i--)
{
if (column?? == null && column?? == null)
model.removeRow(i);
}
added the problem above in table.setRowHeight();
Well, that should have been part of the original question. How do we know you have custom logic doing something strange???
In the future post a proper SSCCE that demonstrates the problem so we don't have to guess what you are doing.
i get the same problem it resizes rows
Then remove the listener:
remove the listener
delete the rows
add the listener

Related

Upon loading JTable dynamically, before selected JComboBox appears visible

I use:
Java 10 SE
Java Swing
Eclipse IDE
I have JTable, the contents gets loaded at runtime dynamically. It has some JComboBoxes. If I select the JComboBox, and then attempt to reload the table, the JComboBox appears visible at the time when the table loading is in progress.
Besides that, if the JComboBox's contents gets updated (elsewhere in different table, when the combo supposed to reflect that new contents), that new contents does not get visible staright away after loading the JTable dynamically.
The snap-shot sample of the app:
That's, the table being loaded at runtime up, and in the middle you have vsisble JComboBox persistent from the previous selection.
How to:
Get rid off that persistent JComboBox
Make the data visible instantly, upon update under the combo, once you load the table dynamically
I have the public final class TableColumnEditor extends DefaultCellEditor{
which returns the JComboBox on a specific column:
else if(row == ROW_2_DEVS_WORK_WEEKEND) {
ProjectMetrics metrics = new ProjectMetrics();
JComboBox<String> combo = new JComboBox<>();
combo.setBackground(Color.WHITE);
for(String devs : metrics.identifyDevsThatWorkAtWeekend()) {
combo.addItem(devs);
}
return combo;
}
I have the public final class TableColumnRenderer extends DefaultTableCellRenderer{
which makes sure that the view displays the JComboBox under that specific column:
else if(row == ROW_2_DEVS_WORK_WEEKEND) {
ProjectMetrics metrics = new ProjectMetrics();
JComboBox<String> combo = new JComboBox<>();
combo.setBackground(Color.WHITE);
for(String devs : metrics.identifyDevsThatWorkAtWeekend()) {
combo.addItem(devs);
break;
}
return combo;
}
The table gets loaded dynamically right here (non-essential things removed):
public static void reloadTableDynamically(JTable metricsTable){
DefaultTableModel model = (DefaultTableModel)metricsTable.getModel();
if(projectData.isEmpty()) {
metricsTable.clearSelection();
int rowCount = model.getRowCount();
for(int item = (rowCount - 1); item >= 0; item--) {
model.removeRow(item);//clears previous rows
}
metricsTable.repaint();
return;
}
model.getDataVector().clear();
int rowCount = constantRows + ((devsTask.size() == 0) ? 1 : devsTask.size());
try {
new Thread(()-> {
int lastRowID = 0;
int devsTaskID = 0;
for(int item = 0; item < rowCount; item++) {
Object[] input = null;
if(item == 0) {
input = new Object[] {"", metrics.getProjectDateRange(), "" };
}//similar branches removed
else {
devsTaskID++;
input = new Object[] {"", devsTask.get(devsTaskID).getDeveloper(), ""};
}
model.addRow(input);
metricsTable.scrollRectToVisible(new java.awt.Rectangle(metricsTable.getCellRect(lastRowID++, 0, true)));
metricsTable.repaint();
try {
Thread.sleep(Config.getInstance().getReloadInOutTable());
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
metricsTable.scrollRectToVisible(new java.awt.Rectangle(metricsTable.getCellRect(projectData.size() - 1, 0, true)));
metricsTable.repaint();//so that to reach the last row
}).start();
}
catch(Exception e) {
}
}
What do you think?
Well, I figured out how to overcome this problem.
Firstly, the JComboBox gets updated on EDT(Event Despatch Thread).
/**
* #param combo The JComboBox ref.
* #param toDisplay The value to add to it
*/
public static void updateComboBoxOnEventDespatchThread(JComboBox<String> combo, String toDisplay) {
Runnable doComboUpdate = new Runnable() {
public void run() {
combo.addItem(toDisplay);
}
};
SwingUtilities.invokeLater(doComboUpdate);
}
Under the JTable column editor:
else if(row == ROW_2_DEVS_WORK_WEEKEND) {
ProjectMetrics metrics = new ProjectMetrics();
JComboBox<String> combo = new JComboBox<>();
combo.setBackground(Color.WHITE);
Runnable doComboInsert = new Runnable() {
public void run() {
int id = 0;
for(String devs : metrics.identifyDevsThatWorkAtWeekend()) {
UIutils.updateComboBoxOnEventDespatchThread(combo, "("+ ++id +") " + devs);
}
}
};
SwingUtilities.invokeLater(doComboInsert);
return combo;
}
But the main fix, without which both issues do not go away, is following.
That is, I noticed that in order for data to appear under the table instantly, firstly, you need to select any other unrelated table's cell.
That is, the Java thread, which loads the JTable at runtime, does need to have this:
if(model.getRowCount() > 0) {
metricsTable.selectAll();
}
That's probably a hack, but it works for me!

How to add Images to a dynamically created JTable

I have a JTable which I create dynamically from List<String> objects. I do this probably completely wrong but it works. The only thing I can't get to work is adding Images to some of the cells.
All it does is, it adds the ImageIcon Object name as String to the cells. See my code below.
private static Image doneImage = getIconImage("doneImage");
private static Image notDoneImage = getIconImage("notDoneImage");
private DefaultTableModel model = new DefaultTableModel(){
#Override
public Class<?> getColumnClass(int column){
if ((column & 1) != 0 ){
return ImageIcon.class;
}else{
return String.class;
}
}
};
initTables();
JTable table = new JTable();
table.setModel(model);
private void initTables(){
model.addRow(new Object[]{});
int rowsToAdd = 0;
int rowCount = 0;
int columnId = 0;
for(HouseObject aHouse : houses){
for(RoomObject aRoom : aHouse.getRooms()){
model.addColumn(null);
model.addColumn(aRoom.getId());
model.setValueAt(aRoom.getId(), 0, columnId);
if (rowCount < aRoom.getEvents().size()){
rowsToAdd = aRoom.getEvents().size() - model.getRowCount();
for(int i = 0; i <= rowsToAdd; i++){
model.addRow(new Object[]{});
}
rowCount = model.getRowCount();
}
for(int i = 0; i < aRoom.getEvents().size(); i++){
model.setValueAt(aRoom.getEvents().get(i).getId(), i+1, columnId);
for(String houseDone : housesDone){
if(aRoom.getEvents().get(i).getId().contains(houseDone)){
model.setValueAt(doneImage , i+1, columnId+1); // this does not work
}else{
model.setValueAt(notDoneImage, i+1, columnId+1);
}
}
}
columnId = columnId+2;
}
}
}
You need to install renderer for your table
Here is the renderer:
public class IconTableCellRenderer extends DefaultTableCellRenderer {
#Override
protected void setValue(Object value) {
if (value instanceof Icon) {
setText(null);
setIcon((Icon) value);
} else {
super.setValue(value);
}
}
}
And so you must install it:
JTable table = new JTable();
table.setModel(model);
table.setDefaultRenderer(ImageIcon.class, new IconTableCellRenderer());
I have a JTable which I create dynamically from List objects.
Well you can't just add Strings to the table since then image will need to be added as an ImageIcon. So you would need a List so you can add String and Icon values.
Then you need to override the getColumnClass(...) method of your TableModel to return Icon.class for the column that contains the Icon. The table will then use the appropriate renderer for the Icon.
See: How to set icon in a column of JTable? for a working example.

JTable get all rows that are being edited

I have a JTable which has 2 columns
column 0 username
column 1 password.
for the password column it will be encrypted to SHA256.
Basically what I want to achieve is it will update all the rows in my password column to SHA256 that I have edited after my button is pressed.
so..
I have a RowData class, this will store the text being edited and the position of the text
being edited(rows,columns).
public class RowData {
int rows = 0, columns = 0;
String text = " ";
public RowData(String text,int rows, int columns) {
setEditedRows(rows);
setEditedColumns(columns);
setEditedText(text);
}
public int getEditedRows() {
return rows;
}
public int getEditedColumns() {
return columns;
}
public String getEditedText() {
return text;
}
public void setEditedRows(int rows) {
this.rows = rows;
}
public void setEditedColumns(int columns) {
this.columns = columns;
}
public void setEditedText(String text) {
this.text = text;
}
}
I wrote a TableModelListener.. I have an List to store the text and the rows and columns
after the table has changed
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel) e.getSource();
//System.out.println(model.getValueAt(row, column));
if(column == 1) {
String data = (String) model.getValueAt(row, column);
System.out.println(data);
dataList.add(new RowData(data,row,column));
}
}
});
In my button I loop through the list and retrieve the rows, and columns and text
and set the password to SHA256 to the JTable.
updateBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (table.getCellEditor() != null) {
table.getCellEditor().stopCellEditing();
for(int i = 0; i < dataList.size(); i++) {
String text = dataList.get(i).getEditedText();
int rows = dataList.get(i).getEditedRows();
int columns = dataList.get(i).getEditedColumns();
//System.out.println(dataList.get(i).getEditedText() + " " + dataList.get(i).getEditedRows() + dataList.get(i).getEditedColumns());
table.setValueAt(convertPassword.convertToSHA256(text), rows ,columns);
}
}
}
});
The result I get is I will keep printing the password endlessly in my console.
So I think that my logic is wrong and needed to be corrected.
table.setValueAt(convertPassword.convertToSHA256(text), rows ,columns);
When you change the TableModel the TableModelListener will be invoked again. The TableModelListener is invoked whether you change the data by using the JTable or by updating the TableModel directly.
The solution would be to remove the TableModelListener when you click on your button, at the start of your ActionListener. You would then need to add the TableModelListener back to the TableModel at the end of the code in case the user make further changes.
Another solution is to have 3 columns in the TableModel, username, password and sha256Password. Then you can use the JTable to display only the first two columns. See the removeColumn() method of JTable. Then your conversion code would update the TableModel using:
table.getModel().setValueAt(value, row, 2);
Now the code in your TableModel will be invoked, but because you check for updates to column 1, nothing will happen when you update column 2.
Then when you save the data you save the data from the TableModel.
Edit:
I must click into another cell before I can press my button to edit.
You need to stop the cell editing. See Table Stop Editing for a couple of solutions.

Handle entire row on TableCellRenderer

I'm implementing TableCellRenderer to make a visible diference if the last value is or not certain value.
So, the code of these implementation is:
TableColumnModel tcm = table.getColumnModel();
TableColumn col = tcm.getColumn(column);
JLabel cellComponent = new JLabel();
if (value != null)
{
cellComponent.setText( String.valueOf( value ) );
}else
cellComponent.setText( "-" );
String colName = (String) col.getHeaderValue();
if (colName.startsWith("Vigencia") && !cellComponent.getText().equals("-"))
{
long dias = Long.valueOf(cellComponent.getText());
if (dias <0)
{
dias = dias -(dias*2); //Le resto (dias x 2) para sacarle el negativo...
cellComponent.setText( String.valueOf(dias) );
cellComponent.setBorder( BorderFactory.createLineBorder(Color.RED));
}
}
to populate my table I have a Class that extends from JTable and have this method to populate the table:
public void setData(LinkedList<T> list)
{
if (list.size() == 0)
{
cleanTableData();
return;
}
int index = 0;
Object[][] o = new Object[list.size()][_columnNames.length];
for (T obj : list)
{
Object[] data = obj.toStringReporte();
o[index++] = data;
}
_tableModel = new DefaultTableModel( o, _columnNames );
setModel(_tableModel);
setColumnWidths();
}
toStringReporte method is this one:
public Object[] toStringReporte()
{
String planName = "-";
if (getPlanID() != null)
{
Plan plan = Adapter.getInstance().getElement(getPlanID(), new Plan());
planName = plan.getNombre();
}
return new Object[]{getID(),
getNombre(),
getApellido(),
getDni(),
(getEstado().equals("A") ? "Activo" : "Inactivo"),
(getSexo().equals("M") ? "Masculino" : "Femenino"),
(getFichaMedica() != null ? new SimpleDateFormat(Defines.DATE_FORMAT).format(new Date(getFichaMedica())) : "-"),
planName,
(getFechaVencimiento() != null ? SGGDateUtils.diferenceInDaysBetweenTwoDatesMS(getFechaVencimiento(), new Date().getTime()) : "-")};
}
My problem is that (as Class name tells) the only change is cell border. I want to change entire row border.
Some body know how to change the border of entire row?
Table Row Rendering shows how you might render a row level border.
You cannot do this with just a TableCellRenderer, as it works independently on each cell.
If you want to apply an effect to an entire row, you will likely need to override the prepareRenderer method of JTable.

JTable Empty cell validation for the filled rows

I am doing a project in java swing in which I have to use a JTable.
By default jtable can validate the inputs (float,int) by turning into red when wrong input is given.
But I want to validate the empty cell left in the table at the time of save button click.
Here is my code:
public boolean validCheck() {
if (jTable.getCellEditor() != null) {
jTable.getCellEditor().stopCellEditing();
}
for (int i = 0; i < jTable3.getRowCount(); i++) {
for (int j = 0; j < jTable3.getColumnCount(); j++) {
String val = jTable3.getValueAt(row, col).toString();
if (val.trim().length() == 0) {
return false;(joptionpane.showmessagedialog(null,"field empty");)
}
}
}
return true;
}
This code is checking all the rows in the table and displaying the field empty message. I need to check only filled rows(rows which have data) not all the rows in the jtable.
Any suggestions would be helpful.
You need to change your logic to first look if a row had data at all. Then (and only then), take a second pass to validate that all columns in that row are filled.

Categories