JTable get all rows that are being edited - java

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.

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.

remove unused rows in jtable (Empty Rows)?

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

Calculate the sum of a last column values and put it on TextField?

I have a Jtable with columns of Quantity, price and amount. If the user enters quantity and price, the amount value will show at the time of key releasing. It's working perfectly.
I am also having one textfield below the table, that shows the sum of table's last column values.
When the user changes the data, at the same time the JTextField values also will be change.
Now I am using a mouse click event. When clicking on the textField it will calculate sum of table last column values and display.
Can anyone help me?
Here is my code:
int rowCount = Table.getRowCount();
int lastRow = rowCount - 1;
//System.out.println("Last Row = " + lastRow);
//System.out.println("Last Row Value is = " + Table.getValueAt(lastRow, 0));
if (Table.getValueAt(lastRow, 0) == null) {
DefaultTableModel tmodel = (DefaultTableModel) Table.getModel();
tmodel.removeRow(lastRow);
}
else {
double value;
double total = 0;
//System.out.println("Row Count = " + rowCount);
for (int i = 0; i < rowCount; i++) {
value = (double) Table.getValueAt(i, 5);
total = total + value;
}
totalField.setText(new DecimalFormat("##.##").format(total));
}
But I don't want this mechanism.
When the user enters some values or modifies the values, at the same time that value will reflect in Textfield.
Instead of MouseListener, use a KeyListener on the JTable.
table.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent arg0) {
// You can set the value of textField to the value of Jtable column here.
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
});
But beware that this will be called for every keystroke on the table column. So you should keep the processing inside the keyTyped() method to a minimum.
I believe you want a focusListener for the textField, as and when a user clicks on this textField this event gets triggered.
Get the values from the table and do the math here.
JTextField textField = new JTextField("A TextField");
textField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
//do here
}

Add and remove from one Table To another

I am facing a problem with the functionality of removing a row(s) form one table view to another table view currently I have two button one add row form the bottom table to the above and the next add from the above the the botton. the button that add from bottom to top called add and the button that add from top to bottom called remove in both once the row is copied across it get deleted from the original table.
The problem I am facing is:
when I add all the row from the bottom table to the top table
if I sort Column 0 in top table ,then try to remove the row from the top table to the bottom table
the row do not get deleted from the top table although it is added in the bottom table.
Could you please Help me solve this problem or advice me on a better way?
Here is my current code:
Remove button:
btnRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
spTable.removeAll();
x = resultTable.getSelectedRows();
String[] cName= {"Column 0","Column 1","Column 2","Column 3","Column 4","Column 5","Column 6","Column 7","Column 8"};
if(rTable.getRowCount()==0){
model=addToNew(resultTable,x,cName,model);
}else{ model =addToExisting(resultTable,rTable, x, model);
}
deletRows(x,resultTable);
rTable.setModel(model);
JScrollPane spS = new JScrollPane(rTable);
rTable.getColumnModel().getColumn(1).setPreferredWidth(290);
spS.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
spS.setPreferredSize(new Dimension(800,200));
rTable.setFillsViewportHeight(true);
spTable.add(spS);
validate();
}});
Add button:
btnAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
panel.removeAll();
x = rTable.getSelectedRows();
String[] cName= {"Column 0","Column 1","Column 2","Column 3","Column 4","Column 5","Column 6","Column 7","Column 8"};
if(resultTable.getRowCount()==0){
model=addToNew(rTable,x,cName,model);
}else{ model =addToExisting(rTable,resultTable, x, model);
}
deletRows(x,rTable);
resultTable.setModel(model);
JScrollPane spS = new JScrollPane(resultTable);
resultTable.getColumnModel().getColumn(1).setPreferredWidth(290);
spS.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
spS.setPreferredSize(new Dimension(800,170));
panel.add(spS);
resultTable.setFillsViewportHeight(true);
validate();}});
deletRow
public void deletRows(int[] selected, JTable t){
for(int i = selected.length-1;i>=0;i--){
int y = selected[i];
((DefaultTableModel)t.getModel()).removeRow(y);
validate();}}
/**
* this method allow to add rows to an New table
*/
public DefaultTableModel addToNew(JTable t1,int[] selected,String[] ColName, DefaultTableModel m){
String[] name = ColName;
int col = name.length;
m =new DefaultTableModel();
for(int i= 0;i<col;i++){
m.addColumn(name[i]);
}
Object[] data= new Object[col];
for(int i =0; i<selected.length;i++){
int y= selected[i];
for (int z =0; z<col;z++){
if( t1.getValueAt(y, z)!= null){
String value = t1.getValueAt(y, z).toString();
data[z]= value;
}else{
data[z]=null;
}
}
m.addRow(data);
}
return m;
}
/* this method allow to add rows to an Existing table */
public DefaultTableModel addToExisting(JTable t1,JTable t2, int[] selected, DefaultTableModel m){
m =(DefaultTableModel)t2.getModel();
Object[] data= new Object[m.getColumnCount()];
for(int i =0; i<selected.length;i++){
int y= selected[i];
for (int z =0; z<m.getColumnCount();z++){
if( t1.getValueAt(y, z)!= null){
String value = t1.getValueAt(y, z).toString();
data[z]= value;
}else{
data[z]=null;
}
}
m.addRow(data);
}
return m;
}

Categories