I've to create a java swing app that allows the user to menage some Oracle tables.
I've implemented the JTable in this way:
public class TableModel extends AbstractTableModel{
.
.
.
public List <List <String> > result = null;
.
.
.
public void createTable(ResultSet r) throws SQLException {
rs = r;
numcols = getColumnCount();
result = new ArrayList();
while (rs.next()) {
List <String> row = new ArrayList<>(numcols);
for (int i=1; i<= numcols; i++)
row.add(rs.getString(i).replace("00:00:00.0", "")); //just managing stuffs .. nothing important. Don't care of this replace.
result.add(row);
}
fireTableStructureChanged();
}
public void addRow(){
List <String> row = new ArrayList<>();
for(int i=1;i<=getColumnCount();i++)
row.add("");
result.add(row);
fireTableStructureChanged();
}
public Object getValueAt(int row, int col) {
return result.get(row).get(col);
}
public int getColumnCount() {
if (rs == null) {
return 0;
}
try {
return rs.getMetaData().getColumnCount();
} catch (SQLException e) {
System.err.println("error in colcount");
return 0;
}
}
public int getRowCount() {
int totalRows = 0;
try {
rs.last();
totalRows = rs.getRow();
rs.beforeFirst();
} catch(Exception ex) {
return 0;
}
return totalRows ;
}
}
so, I store database data into the arraylist and then I print the table using the arraylist.
Now in the addRow() function I add to that arraylist an empty record (in my mind an empty record is a record composed of all null ("") strings).
Finally using the fireTableStructureChanged() method I expect the table to refresh itself.. but this will never occur and I don't understand why.
I've already checked that the new row is successfully loaded into the arraylist:
I got all the data stored in the table of the Database into the arraylist and the new row is successfully loaded in the arraylist.
so I swear the problem is about that fireTableStructureChanged() method.
Thanks :3
Try using fireTableRowsInserted(int firstRow, int lastRow) instead of fireTableStructureChanged()
Here's the javadoc for the structure changed ...
Notifies all listeners that the table's structure has changed. The number of columns in the table, and the names and types of the new columns may be different from the previous state. If the JTable receives this event and its autoCreateColumnsFromModel flag is set it discards any table columns that it had and reallocates default columns in the order they appear in the model. This is the same as calling setModel(TableModel) on the JTable.
So that one will only work if the columns types changed ...
If you are lazy go for this one: fireTableDataChanged()
I found the solution.
That's quite embarassing..
#tsolakp you helped me a lot!
Since before using ArrayList I was working on ResultSet directly, I forgot to update getrowcount.
So, since the inserting was only "client side" on the arraylist, the rows displayed were only "n" (where n was the number of rows on the database). So I would never displayed my new row since it was not loaded into the database.
That's all :)
Maybe working hard on coding, makes these errors invisible :X
Related
I want to populate a table with data.
The following Code are two bits out of the controller, because I sadly don't know which part is important.
Each function is supposed to take an Observable List which was declared in the main phase and clear it out.
Then add new Entries according to the current status of the arrays and in the end use populate() to populate the table with it.
But this sometimes fails. The data is added into the arrays, but it isn't shown in the table.
Has anybody an idea what could be the reason for that?
public void showAll() {
//Clear existing data
Main.data = FXCollections.observableArrayList();
//add new data on base of the arrays
for (int i = 0; i < Main.array_anz.length; i++) {
if (Main.array_pla[i] != 0) {
Main.data.add(new Article(Main.array_bez[i], Main.array_pla[i], Main.array_gew[i], Main.array_pre[i], Main.array_anz[i], Main.array_kat[i]));
} else {
i++;
}
}
//Show the data in the table
populate();
}
private void populate() {
ArtikelbezeichnungTable.setCellValueFactory(new
PropertyValueFactory<Article, String>("artikelbezeichnung"));
LagernummerTable.setCellValueFactory(new PropertyValueFactory<Article,
Integer>("lagernummer"));
GewichtTable.setCellValueFactory(new PropertyValueFactory<Article,
Double>("gewicht"));
AnzahlTable.setCellValueFactory(new PropertyValueFactory<Article,
Integer>("anzahl"));
KategorieTable.setCellValueFactory(new PropertyValueFactory<Article,
String>("kategorie"));
StorageTable.setItems(Main.data);
}
I want to verify the existence of an element in two JTable that displays questions
The program is when I click on a question in the first list it will be transferred to the second JTable but I do not want to add duplication restrictions so I did not want an issue to be added twice in the second list I want make an added control if it will add the user can not add the second time
table = new JTable();
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
for (int i = 0; i < questions2.size(); i++) {
/* the control code */
Question selected=questions.get(table.getSelectedRow());
questions2.add(selected);
questions.remove(selected);
initDataBindings();
}
}
});
My Result
I do not want this
since you are using Jtables in the question,
you need to check if the value exists in the jtable first if the value doesnt exist then you can add it to the jtable. in the code you have submitted you are not checking if the value exists.
public boolean ifExists(JTable table,string entry) {
int rowCount = table.getRowCount();
int columnCount = table.getColumnCount();
for (int i = 0; i < rowCount; i++) {
String value = "";
for (int j = 0; j < columnCount; j++)
value = value + " " + table.getValueAt(i, j).toString();
if (value.equalsIgnoreCase(entry)) {
return true;
}
}
return false;
}
in the above code im checking the existence of the data using a for loop.
it will iterate over the jtable and return true if the value exist.
if the return value is false then you can go on and add the data. try it with the above code.
Use Set. Lets say you have a first List:
List<Question> questions1 = new ArrayList<Question>();
now, Question must have this methods:
#Override
public int hashCode() {
// Let your IDE generates it based on variables
}
#Override
public boolean equals() {
// Let your IDE generates it based on variables
}
With this method, Set will be able to figure out if two Question are equal, and create hashCode, needed for storing. Best way is if you have unique id, but other stuff can help to. If you add Question class to your Answer, I might help you decide the best implementation of equals() and hashCode() methods.
Now, you place them in HashSet, as Users does some action:
HashSet<Question> questionsSet = new HashSet<Question>();
boolean isPresentInList = questionsSet.contains(question);
questionsSet.add(question);
Method contains will check if that question is present in questionsSet. add will check if there is an equal question in it, defined by rules in equals() method, and if it is, it will override it, else it will just add. In this way, you will not have duplicates in questionsSet.
Now, when you need an arrayList from questionsSet do this:
List<Question> questions2 = Arrays.asList(questionsSet);
Let's say I have a sqlite table named "table" with the rows id, text1, text2
now I have an ArrayList with the content, let's say:
id:0,text1:this is the first text,text2: this is the second text
id:21, text1: blabla, text2: blabla2
...
now i want to make a comparision between sqlite row and every single element row in arraylist.
for example i want to say delete every row in sqlite table which is not equal with any row in arraylist.
I could not find any equal thread that contains my question.. maybe you can help me or give me some link. thank u
Here you have some example code. You should get the idea:
public void removeRows(DatabaseAdapter dbAdapter, ArrayList<SomeObject> list) {
SQLiteDatabase db = dbAdapter.openWritableDatabase();
Cursor rows = db.query(/ *perform some query on SQLite db*/);
while(rows.moveToNext()) {
int id = rows.getInt(0);
String text1 = rows.getString(1);
String text2 = rows.getString(2);
boolean included = false;
for(SomeObject obj : list) {
if(obj.getId() == id && obj.getText1().equals(text1) && obj.getText2().equals(text2)) {
included = true;
break;
}
}
if(!included) {
db.delete(/*perform deletion of row*/);
}
}
}
Edit: To add to database those objects from list which are not yet in it do something like this:
public void addListToDb(DatabaseAdapter dbAdapter, ArrayList<SomeObject> list) {
SQLiteDatabase db = dbAdapter.openWritableDatabase();
Cursor rows = db.query(/ *perform some query on SQLite db*/);
for(SomeObject obj : list) {
boolean included = false;
while(rows.moveToNext()) {
int id = rows.getInt(0);
String text1 = rows.getString(1);
String text2 = rows.getString(2);
if(obj.getId() == id && obj.getText1().equals(text1) && obj.getText2().equals(text2)) {
included = true;
break;
}
}
rows.moveToPosition(-1);
if(!included) {
db.insert(/*perform insert of object*/);
}
}
}
There is also another way to accomplish this task. Loop over elements of your list and add every element to database using SQLiteDatabase#insertWithOnConflict(String table, String nullColumnHack, ContentValues initialValues, int conflictAlgorithm) method and pass SQLiteDatabase.CONFLICT_IGNORE as a conflictAlgorithm. Above method will add element if it not yet exists in database. Otherwise it will ignore it. Important thing to remember is that when we try to insert a row which already exists in database with CONFLICT_IGNORE conflict algorithm we will get -1 result instead of primary key of existing row (Android documentation is misleading here).
I have a function called FetchInbox() which fetches the header information (Sender, subject, date sent) of an email and then adds it to a Vector of String Vectors.
What I want to be able to do is to refresh this table as new emails come in and update the table by first running FetchInbox() again, and then using this to repopulate the table.
I know this can be done using a TableModel, but I have yet to find a example which uses Vectors and not Object[][]. Any assistance with this would be appreciated.
DefaultTableModel has constructors and methods that take Vectors instead of Object[]s.
The old version of DefaultTableModel only used Vectors, the Object[] parameters are newer methods that were added around the time Generics came to Java.
http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
When you create a table without providing it a model, it will have DefaultTableModel as it's default model. This model has two function:
setDataVector(Vector dataVector, Vector columnIdentifiers): Where dataVector is a Vector(which represents the data rows of table) of Vector and comlumnIdentifiers is Vector containing identifiers. It will show your table as you are providing the Vector.
addRow(Vector dataRow): it will add a data row to your dataVector as defined above.
So it is really simple to get the model and invoke these function:
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setDataVector(dataVector, comlnIdentifiers);
In your context, dataVector has the type vector<vector<string> >. But depending on Vector is not really a good choice. It is much safer and effective if your directly work with Object[]. The DefaultTableModel has similar function with Object array too.
setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
addRow(Object[] rowData)
Check out the Tutorial page: How to Use Table to know many more things you can do with table and it's model.
This should work, but #jzd's answer is probably what you want, with the caveat that, according to the documentation, the column Vectors might be truncated or padded if their length does not match the number of columns you want in your table.
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
class test{
public static void main(String[] _) {
// Test data.
final Vector<Vector<String>> rows = new Vector<Vector<String>>();
for (int i = 0; i < 4; i++) {
Vector<String> row = new Vector<String>();
for (int j = 0; j < 5; j++) {
row.add(String.format("%s, %s", i, j));
}
rows.add(row);
}
// With AbstractTableModel, you only need to implement three methods.
TableModel model = new AbstractTableModel() {
public int getRowCount() {
return rows.size();
}
public int getColumnCount() {
return rows.elementAt(0).size();
}
public Object getValueAt(int row, int column) {
return rows.elementAt(row).elementAt(column);
}
};
// Test the TableModel in a JTable.
JFrame jf = new JFrame("test");
jf.setSize(512, 384);
jf.setContentPane(new JScrollPane(new JTable(model)));
jf.show();
}
}
have a look at GlazedLists - it'll save you a ton of time.
with it you can dynamically bind a JTable to a List of objects such that any change in the objects is reflected in the table and vice-versa.
getRowCount() gets the number of rows that are set so i can't use it.
This is what I did and it doesn't work:
private String[][] getContentsFromTable(){
int cols= jTable1.getColumnCount();
int rows=jTable1.getRowCount();
System.out.print(rows);
String items[][]= new String[rows][cols];
if(jTable1.getCellEditor()!=null)
jTable1.getCellEditor().stopCellEditing();
for(int i=0;i< jTable1.getRowCount();i++){
for (int j=0;j<jTable1.getColumnCount();j++){
//skip subtotal
if(j!=3){
if(jTable1.getValueAt(i,j)!=null){
String om=jTable1.getValueAt(i,j).toString();
if(om.trim().length()!=0){
items[i][j]=om;
//System.out.print(""+i+",j "+j+": "+items[i][j]);
}
}
}
}
}
return items;
}
edit: the table is editable and i need to get all the data from rows so i have to go over it and identify the number of not null rows so i can use them in a loop and store the data in the database
Kind of too late but for anyone who is having problems with NULL rows, .getValueAt is throwing a null exception so do not try to use it for checking null rows.