I am facing a strange problem with the Jtable. I have a small standalone java application in which I have used Jtable that shows data that is retrieved from database. User can view and edit the data. Once he edit the cell and presses the update button then the edited values will be updated in the database. Now what happening is for the first time when user edit the data and click on update button then the values are properly persisted in the database and user gets out of the module. But again if he/she goes to the same module and edits some more cells and click on update button then in back end i get old value from those cells although the Jtable shows the latest updated values in the cells.
Below is the code.
private JTable jt;
private TableRowSorter<TableModel> tableSorter;
private Dao dao=new Dao();
updateDetails.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
boolean isSuccessful = true;
int rowCount = jt.getRowCount();
List<EmployeeMaster> empMasterList = new ArrayList<>();
int j = 0;
for (int i = 0; i < rowCount; i++) {
EmployeeMaster master = new EmployeeMaster();
j = 0;
try {
master.setEmpId(Long.parseLong((String) jt.getValueAt(i, j)));
j++;
compId.setName(Long.parseLong((String) jt.getValueAt(i, j)));
j++;
compId.setNumber((String) jt.getValueAt(i, j));
j++;
empMasterList.add(master);
}
dao.updateAllEmpDetails(empMasterList);
homePanel.setVisible(true);
UpdateEmp.setVisible(false);
}
}
});
getDataFromDBtoJtable.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
List<EmployeeMaster> empMasterList = dao.getAllEmpDetails();
String data[][] = new String[empMasterList.size()][3];
int i = 0;
int j = 0;
for (EmployeeMaster employeeMaster : empMasterList) {
j = 0;
data[i][j] = String.valueOf(employeeMaster.getEmpId());
j++;
data[i][j] = String.valueOf(employeeMaster.getName());
j++;
data[i][j] = String.valueOf(employeeMaster.getNumber());
i++;
}
String column[] = { "ID", "Name", "Number"};
jt = new JTable(data, column) {
public boolean isCellEditable(int row, int column) {
if (column == 0 || column == 1 || column == 2)
return false;
else
return true;
};
};
tableSorter = new TableRowSorter<TableModel>(jt.getModel());
jt.setBounds(12, 12, 1200, 400);
jt.setRowSorter(tableSorter);
homePanel.setVisible(false);
UpdateEmp.setVisible(true);
JScrollPane pane = new JScrollPane(jt);
pane.setBounds(1, 40, 1150, 300);
setBounds(0, 0, 2000, 800);
UpdateEmp.add(pane);
}
});
updateDetails -> button to get the data from jtable and update it in database
getDataFromDBtoJtable -> button to get data from Database and show it in Jtable
Whenever user hits the updateDetails i am updating the database and forcing user to get out of the module. So everytime whenever user get into jtable module he/she gets new Jtable instance. But still unable to identify what's going wrong.
Related
Ok so I am trying to make a chess game in swing. I have a program that creates a 2d array of JButton's 8x8. I then create them all in a loop doing stuff like going back and forth between white/black and adding an action event. The problem i am having is that each button has the same action event and it is the event that is created last I.E. button on Row 8 column H is the action listener for all of the buttons in the array. Here is a snippet of code that is where I am creating the buttons and adding them.
I also have an Enum Columns that just goes from int to character 1 to H for example. selectPosition and targetPosition are objects that have two members columns and rows.
public void initializeGui(boolean isWhite) {
boolean shouldBeWhite = true;
for(int i = 0; i< 8; i++){
for(int j = 0; j < 8; j++){
column = i+1;
row = j+1;
JButton square = new JButton();
square.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
final int thisRow = row;
final int thisColumn = column;
selectPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
selectPosition.setRow(thisRow);
if(isSelecting){
System.out.print("Selecting square to move. Row: " + thisRow + " Column: " + Columns.getColumnsFromInt(thisColumn));
selectPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
selectPosition.setRow(thisRow);
} else{
System.out.print("Targeting square to move to. Row: " + thisRow + " Column: " + Columns.getColumnsFromInt(thisColumn) + "\n");
targetPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
targetPosition.setRow(thisRow);
}
System.out.println("");
isSelecting = !isSelecting;
}
});
if(shouldBeWhite){
square.setBackground(Color.WHITE);
shouldBeWhite = false;
}else{
square.setBackground(Color.BLACK);
shouldBeWhite = true;
}
if (j == 7){
shouldBeWhite = !shouldBeWhite;
}
chessBoardSquares[i][j] = square;
gui.add(chessBoardSquares[i][j]);
}
}
if(isWhite){
setInitialPiecesWhiteStart();
}else{
setInitialPiecesBlackStart();
}
}
Further up as a member of this class are the following:
int column = 0, row = 0;
When I click on any of these buttons i see printed
Selecting square to move. Row: 8 Column: H
Targeting square to move to. Row: 8 Column: H
Selecting square to move. Row: 8 Column: H
Targeting square to move to. Row: 8 Column: H
and so on. My question is why are these buttons all given the same action event? My logic walk through would be something like create the first button set column = i+1 and row = j+1 then add an action listener with an action event that sets the current row/column values to the inner final variables and then prints out the thisRow and thisColumn associated with that action event. Am i overriding the values at the end or do i have the scope wrong? Basically how am i creating these buttons actions listeners incorrectly?
You could...
Use the actionCommand API to pass information between the button and the ActionListener...
JButton btn = new JButton();
btn.setActionCommand(row + "x" + column);
btn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//...
}
});
The problem here is you're relying on String parsing to extract the values, which can get messy quickly
You could...
Create a custom ActionListener which takes the values you want to use...
public class SquareActionListener implements ActionListener {
private int column;
private int row;
public SquareActionListener(int row, int column) {
this.row = row;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
//...
}
}
This de-couples the ActionListener from the rest of the code and provides you the information you need, although, you may need to pass additional information (such as the model) as well for it to work
You could...
Make use of the Action API which is designed to be provide self contained units of work, it's generally a more re-usable solution, but might be a little beyond what you need right now
public class SquareAction extends AbstractAction {
private int column;
private int row;
public SquareAction(int row, int column) {
this.row = row;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
//...
}
}
This looks alot like the last suggestion, but instead of adding it as the button's ActionListener, you actually apply it to the button directly...
JButton btn = new JButton(new SquareAction(row, column));
The button then uses other properties (which I've not set) to set itself up
I had the same issue when making a tic-tac-toe game. I used each button's hashcode to trace back which button was actually pushed. This is what my button setup looked like:
hashcodes= new ArrayList<Integer>();
for (int i=1;i<=9;i++) {
JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setHash(button.hashCode());
testWinner();
testDraw();
}
});
hashcodes.add(button.hashCode());
panel.add(button);
}
}
private void setHash(int hashcode) {
for (int h:hashcodes) {
if (h==hashcode) {
//do stuff
}
}
}
This is my Test class, and it works perfectly.
public class Test extends javax.swing.JFrame {
private javax.swing.JButton[][] buttons;
private final int ROW = 8;
private final int COLUMN = 8;
public Test() {
initComponents();
}
private void initComponents() {
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.setExtendedState(javax.swing.JFrame.MAXIMIZED_BOTH);
this.buttons = new javax.swing.JButton[ROW][COLUMN];
this.setLayout(new java.awt.GridLayout(ROW, COLUMN));
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COLUMN; j++) {
final int row = i;
final int column = j;
buttons[i][j] = new javax.swing.JButton(
String.format("Button %d-%d", i, j));
buttons[i][j].addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
// System.out.println(
// String.format("You have just pressed the button at row %d and column %d", row, column));
javax.swing.JOptionPane.showMessageDialog(
Test.this, String.format("You have just pressed the button at row %d and column %d", row, column));
}
});
this.add(buttons[i][j]);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Test().setVisible(true);
}
}
I have a problem with my JTable. Firstly I selected some entries in my table. However when I deselect some of them, the table could not understand it.
Example scenario: I select job1 and 2 for the testing after that I change my mind and de-select job2. But in the result I saw job1 job1 and job2 ( job 1 seen 2 times and even though I dis-select job 2 I saw them.) Or after selected all the jobs ( choose all button) I want to deselect all of them (Clear button) when I click clear all the table seems empty. It is good but somehow the background of the program still protect the all old selection. How can I solve this?
Try:
I created the row of my table by read csv file.
public class JobSelectionListPanel extends JPanel {
private static final long serialVersionUID = 5198916547962359735L;
private static JobSelectionListPanel INSTANCE = new JobSelectionListPanel();
public static JobSelectionListPanel getInstance() {
return INSTANCE;
}
private JTable table;
private JButton next, back, btnClear, btnNewButton, btnChooseAll;
private JobList fnnJobList = new JobList();
private JobSelectionListPanel() {
table = new JTable();
JScrollPane scrollPane = new JScrollPane(table);
table.setBorder(new CompoundBorder());
// Read all FNN jobs from file
try {
fnnJobList.readFromFile("rules.csv");
} catch (IOException e1) {
System.out.println("You are not able to read the rules.csv file");
}
// Create ArrayList of JobNames
Object[][] initialData = new Object[fnnJobList.size()][1];
int i = 0;
for (Job jobDes : fnnJobList) {
initialData[i][0] = (Object) jobDes.getJobname();
i++;
}
String[] columnNames = new String[] { "", "Your preferences" };
table.setModel(new DefaultTableModel(initialData, columnNames) {
private static final long serialVersionUID = 1L;
#SuppressWarnings("rawtypes")
Class[] columnTypes = new Class[] { Object.class, Boolean.class };
#SuppressWarnings({ "unchecked", "rawtypes" })
public Class getColumnClass(int columnIndex) {
return columnTypes[columnIndex];
}
});
table.getColumnModel().getColumn(1).setPreferredWidth(80);
table.getColumnModel().getColumn(1).setMinWidth(40);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setCellSelectionEnabled(true);
I user want to choose all rows then I implemented this.
btnChooseAll = new JButton("Choose all");
btnChooseAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DefaultTableModel chooseAllData = (DefaultTableModel) table.getModel();
if (DeviceGroups.DeviceAList.size() == 0 || DeviceGroups.DeviceBList.size() == 0
|| DeviceGroups.DeviceCList.size() == 0 || DeviceGroups.DeviceDList.size() == 0)
JOptionPane.showMessageDialog(null,
"You should choose at least 1 device for each test device to apply this test case", "Invalid OPTION",
JOptionPane.ERROR_MESSAGE);
else
for (int i = 0; i < chooseAllData.getRowCount(); i++) {
for (int j = 1; j < chooseAllData.getColumnCount(); j++) {
chooseAllData.setValueAt(true, i, j);
}
}
}
});
For clear all preferences :
btnClear = new JButton("Clear all");
// Clear button create a model of JTable and delete all the rows of table!!
btnClear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DefaultTableModel clearTableData = (DefaultTableModel) table.getModel();
for (int i = 0; i < clearTableData.getRowCount(); i++) {
for (int j = 1; j < clearTableData.getColumnCount(); j++) {
clearTableData.setValueAt(null, i, j);
}
}
}
});
I see the following problem in your code: mixing up view indexes and model indexes. This is the offending snippet:
for (int i = 0; i < table.getRowCount(); i++) {
if (table.getValueAt(i, 1) != null) {
if (((Boolean) table.getValueAt(i, 1)).booleanValue()) {
String jobName = (((DefaultTableModel) table.getModel()).getValueAt(i, 0).toString());
You are using the i variable to denote view row indices, since you are checking values in this statement: table.getValueAt(i, 1) != null.
But then a bit further you are using i to index the model:
String jobName = ((DefaultTableModel) table.getModel()).getValueAt(i, 0).toString();
If i is to be a view index, you need to convert it to a model index before indexing the model:
String jobName = ((DefaultTableModel) table.getModel()).getValueAt(table.convertRowIndexToModel(i), 0).toString();
Also, when columns would be switched around in the view (ie on screen in your GUI), the following will probably not work as intended:
table.getValueAt(i, 1) != null
You most likely mean to say, get the second column value in the model, not the view. Best rewrite then as
table.getValueAt(i, table.convertColumnIndexToView(1)) != null
i know this has been answered before but considering im still a newbie i cant figure out a way to give actions and block the cell editing, i have tried it in several ways,i can successfully render the buttons however when i click on it, it edits the cell instead of pressing the button, i know that in order to avoid the cell editing i should create an abstract table and overide this method:
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col < 3) {
return false;
} else {
return true;
}
}
however im using a default JTable,so this is the code i am using for the Panel and cell renderer:
class PlusMinusCellRenderer extends JPanel implements TableCellRenderer {
public Component getTableCellRendererComponent(
final JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
if(column < 3)
{
JLabel campo = new JLabel(value.toString());
this.add(campo);
}
if(column > 2)
{
//this is a button
this.add(botaoteste);
materialtable.revalidate();
materialtable.repaint();
}
return this;
}
and this is the code i am using to retrieve data from sql to the Jtable(I customised the DefaultJTable code)
String[] columnNames={"teste","abc","def"};
Object[][] data = new Object[1][4];
if(createConnection())
{
try {
Statement statemt = conLogin.createStatement();
ResultSet rs = statemt.executeQuery("SELECT * FROM Materiais");
//ResultSet rs = statemt.executeQuery("SELECT * FROM Materiais");
rsmtdata = rs.getMetaData();
//int columns = rsmtdata.getColumnCount();
columnNames = new String[]{rsmtdata.getColumnName(1),rsmtdata.getColumnName(2),rsmtdata.getColumnName(3),"Deletar"};
if(rs.next())
{
data[0][0] = rs.getString(1);
data[0][1] = rs.getString(2);
data[0][2] = rs.getString(3);
data[0][3] = new Boolean(false);
}
while (rs.next())
{
Object[][] temp = new Object[data.length+1][4];
for(int i=0;i < data.length;i++)
{
for(int j = 0;j < 4;j++)
{
temp[i][j] = data[i][j];
}
}
temp[data.length][0] = rs.getString(1);
temp[data.length][1] = rs.getString(2);
temp[data.length][2] = rs.getString(3);
temp[data.length][3] = new Boolean(false);
data = temp;
}
materialtable = new javax.swing.JTable(data, columnNames);
materialtable = new javax.swing.JTable(data, columnNames){
public TableCellRenderer getCellRenderer( int row, int column ) {
return new PlusMinusCellRenderer();
}
};
materialtable.setRowHeight( 32 );
} catch (SQLException ex) {
Logger.getLogger(ProfessorForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Create the scroll pane and add the table to it.
materialtable.setBackground(new java.awt.Color(153, 255, 51));
materialtable.setSelectionBackground(new java.awt.Color(255, 255, 51));
materialtable.setSelectionForeground(new java.awt.Color(255, 102, 0));
jScrollPane3.setViewportView(materialtable);
so to render the button inside the table i based on this thread:
Adding Buttons inside cell of JTable along with data?
my question is very straight forward, how can i disable Row editing(just like the isCellEditable() method usage) and give action to the buttons?
any help here is greatly appreciated and please take it to consideration im still novice so please detailed information or samples is needed !
Kind regards,
Romulo Romero
You need both a renderer and and editor, as shown in this example. See How to Use Tables: Editors and Renderers for details. Tangentially, you should override the method isCellEditable() in your TableModel rather than extending JTable.
i know this has been answered before but considering im still a newbie i cant figure out a way to give actions and block the cell editing, i have tried it in several ways,i can successfully render the buttons however when i click on it, it edits the cell instead of pressing the button, i know that in order to avoid the cell editing i should create an abstract table and overide this method:
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col < 3) {
return false;
} else {
return true;
}
}
however im using a default JTable,so this is the code i am using for the Panel and cell renderer:
class PlusMinusCellRenderer extends JPanel implements TableCellRenderer {
public Component getTableCellRendererComponent(
final JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
if(column < 3)
{
JLabel campo = new JLabel(value.toString());
this.add(campo);
}
if(column > 2)
{
//this is a button
this.add(botaoteste);
materialtable.revalidate();
materialtable.repaint();
}
return this;
}
and this is the code i am using to retrieve data from sql to the Jtable(I customised the DefaultJTable code)
String[] columnNames={"teste","abc","def"};
Object[][] data = new Object[1][4];
if(createConnection())
{
try {
Statement statemt = conLogin.createStatement();
ResultSet rs = statemt.executeQuery("SELECT * FROM Materiais");
//ResultSet rs = statemt.executeQuery("SELECT * FROM Materiais");
rsmtdata = rs.getMetaData();
//int columns = rsmtdata.getColumnCount();
columnNames = new String[]{rsmtdata.getColumnName(1),rsmtdata.getColumnName(2),rsmtdata.getColumnName(3),"Deletar"};
if(rs.next())
{
data[0][0] = rs.getString(1);
data[0][1] = rs.getString(2);
data[0][2] = rs.getString(3);
data[0][3] = new Boolean(false);
}
while (rs.next())
{
Object[][] temp = new Object[data.length+1][4];
for(int i=0;i < data.length;i++)
{
for(int j = 0;j < 4;j++)
{
temp[i][j] = data[i][j];
}
}
temp[data.length][0] = rs.getString(1);
temp[data.length][1] = rs.getString(2);
temp[data.length][2] = rs.getString(3);
temp[data.length][3] = new Boolean(false);
data = temp;
}
materialtable = new javax.swing.JTable(data, columnNames);
materialtable = new javax.swing.JTable(data, columnNames){
public TableCellRenderer getCellRenderer( int row, int column ) {
return new PlusMinusCellRenderer();
}
};
materialtable.setRowHeight( 32 );
} catch (SQLException ex) {
Logger.getLogger(ProfessorForm.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Create the scroll pane and add the table to it.
materialtable.setBackground(new java.awt.Color(153, 255, 51));
materialtable.setSelectionBackground(new java.awt.Color(255, 255, 51));
materialtable.setSelectionForeground(new java.awt.Color(255, 102, 0));
jScrollPane3.setViewportView(materialtable);
so to render the button inside the table i based on this thread:
Adding Buttons inside cell of JTable along with data?
my question is very straight forward, how can i disable Row editing(just like the isCellEditable() method usage) and give action to the buttons?
any help here is greatly appreciated and please take it to consideration im still novice so please detailed information or samples is needed !
Kind regards,
Romulo Romero
You need both a renderer and and editor, as shown in this example. See How to Use Tables: Editors and Renderers for details. Tangentially, you should override the method isCellEditable() in your TableModel rather than extending JTable.
I am just beginning to program using Java Swing. I am not very familiar with each of the many Java Swing Classes, and have ran into a stumbling block regarding the creation of a Table.
I am trying to figure out how to add a table to a Java Swing Program I am making. I have looked at docs.oracle.com to try and figure it out but I am getting an error when I try to access the values of the table. I will include my code to help show what I am currently trying to do and where the error is.
This is my code for making the table and the table model (I think the problem is that my table model is not working correctly):
/*Create the Table Entry*/
columnNames = new String[listoffields.size()+1];
columnNames[0] = "Record Number";
for(int a = 1; a < columnNames.length;a++){
columnNames[a] = listoffields.get(a-1).getTitle();
}
int count = 1;
data = new Object[numrecords][listoffields.size()+1];
for(int a = 0; a < numrecords;a++){
for(int b = 0; b < listoffields.size()+1;b++){
if(b == 0){
data[a][b] = count;
count++;
}
else{
data[a][b] = "";
}
}
}
/* create the table */
JTable table = new JTable(data,columnNames);
table.setCellSelectionEnabled(true);
table.setModel(new AbstractTableModel() {
public String getColumnName(int col) {
return columnNames[col].toString();
}
public int getRowCount() { return data.length; }
public int getColumnCount() { return columnNames.length; }
public Object getValueAt(int row, int col) {
return data[row][col];
}
public boolean isCellEditable(int row, int col) {
return (col >= 1);
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
});
JScrollPane scrollPane = new JScrollPane(table);
table.setFillsViewportHeight(true);
/* addthe table to the JTable tableentry*/
tabelentry.setLayout(new BoxLayout(ProjectFrame.tabelentry, BoxLayout.Y_AXIS));
tabelentry.add(scrollPane);
tabelentry.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
After the table is displayed and I edit the blank values for each cell, I click a submit button that submits the cell. However, the following error is encountered:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
at java.util.Vector.elementAt(Unknown Source)
at javax.swing.table.DefaultTableModel.getValueAt(Unknown Source)
at Client.GUIComponents.ProjectFrame$1.submit(NameOfFile.java:LineNumber)
The error is encountered when trying to submit as follows:
public void submit(){
String recordvalues = ""; //contains a String representation of what I want to submit
for(int a = 0; a < numberoffields;a++){
for(int b = 0; b < numberofrecords;b++){
if(a != 0){ //I want to skip the first column
recordvalues = recordvalues + (String) tabelentry.getModel().getValueAt(b, a) + ","; //The error is at this line in the code
}
}
}
}
I provided my code to give an example of the current problems I am encountering and what I have currently tried. To generalize my question, I am wondering how to correctly write a table model class so that I can access the values at each of the cells in the table. Any assistance would be helpful. Thanks a ton!
My immediate thought is that you're creating two different table models.
JTable table = new JTable(data,columnNames);
table.setCellSelectionEnabled(true);
table.setModel(new AbstractTableModel() {...
new JTable(data,columnNames) is actually creating it's own DefaultTableModel based on the information you are providing it. Try removing the table.setModel(new AbstractTableModel() {... code
The other, associated, problem is, I don't know how data and columnNames are declared.
Have a read through How to Use Tables for more details
Updated
The other problem, as pointed about by Hovercraft, is you adding one table to another and then accessing the wrong model.
The table creation should look more like...
tableEntry = new JTable(data,columnNames);
JScrollPane scrollPane = new JScrollPane(tableEntry );
tableEntry .setFillsViewportHeight(true);
// Don't forget to add the scroll pane to you view !!
Then you submit method should look more like...
public void submit(){
String recordvalues = ""; //contains a String representation of what I want to submit
TableModel model = tableEntry.getModel();
for(int a = 0; a < model.getColumnCount();a++){
for(int b = 0; b < model.getRowCount();b++){
if(a != 0){ //I want to skip the first column
recordvalues = recordvalues + (String) model.getValueAt(b, a) + ","; //The error is at this line in the code
}
}
}
}
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
This exception means that the column size of your table is 0, I think it's because you don't add columns into your TableModel.
Try to create several TableColumn Column = new TableColumn(); then add these columns to your table