Java program with GUI controlling derby database using DefaultTableModel:
I've a method which successfully inserts a new record to my database. When I restart the program, the new record is visible in JTable (GUI). However, I can't get the JTable to refresh and display the added record promptly.
I've read through a lot of answered questions here but nothing has worked for me so far. Any idea?
GUI class:
public class GUIClients {
ClientDatabase cDB = new ClientDatabase();
DefaultTableModel tableModel = new DefaultTableModel();
JTable table = new JTable(tableModel);
JScrollPane scrollPane = new JScrollPane(table);
JPanel panel = new JPanel(new BorderLayout());
public JPanel createPanel() {
cDB.createTable(tableModel);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
panel.add(scrollPane);
panel.add(table, BorderLayout.CENTER);
panel.add(table.getTableHeader(), BorderLayout.NORTH);
...
return panel;
}
Insert dialogue with save button:
public class InsertDialog extends GUIClients {
...
saveB = new JButton("Save");
saveB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
cl = cDB.getClient(InsertDialog.this);
cDB.insert(cl);
tableModel.setRowCount(0);
cDB.createTable(tableModel);
table.setModel(tableModel);
dialogPanel.dispose();
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
});
dialogPanel.add(saveB);
...
Method for creating DefaultTableModel from database data:
public class ClientDatabase implements Database {
public static ResultSet rs;
public void createTable(DefaultTableModel d) {
try {
d.addColumn("ID");
d.addColumn("Name");
d.addColumn("Surname");
d.addColumn("Mobile");
d.addColumn("Email");
d.addColumn("Notes");
rs.beforeFirst();
while (rs.next()) {
int id = rs.getInt("ID");
String name = rs.getString("NAME");
String surname = rs.getString("SURNAME");
String mobile = rs.getString("MOBILE");
String email = rs.getString("EMAIL");
String notes = rs.getString("NOTES");
d.addRow(new Object[]{id, name, surname, mobile, email, notes});
}
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
...
I've a method which successfully inserts a new record to my database.
Then you are also responsible for adding the data to the TableModel at the same time.
You can either use the addRow(...) or insertRow(..) method of the DefaultTableModel to update the date in your TableModel and the JTable will then be updated.
Or the other approach is to redo the query and then use the JTable.setModel(...) method to replace the old TableModel with the new TableModel.
There is no automatic synching of database and TableModel.
Related
I can't manage to display the JTable in a JFrame. Actually I have extracted the data from an ArrayList and filled the JTable row by row. I have checked that the JTable is filled, the number of rows is equal to the rows in the original ArrayList. Yet running the function shows a blank GUI. I really do not see the problem in my code:
public Graphicalinterface4() {
//super (new GridLayout(1,0));
//panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
getdata2 in=new getdata2();
try {
ArrayList<Piece> test=in.getList();
ArrayList<Piece> classified=in.classify(test);
JTable table=getlocaltable(classified);
table.setFillsViewportHeight(true);
JScrollPane scrPane=new JScrollPane(table);
//scrPane.setSize(800,690);
//scrPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.add(scrPane);
//scrPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
}
catch (IOException ex) {
ex.printStackTrace();
}
}
public JTable getlocaltable(ArrayList<Piece> in) {
//new Object[]{"Type","Company","reference","description","price","To order"}));
//DefaultListModel<Piece> testlst=new DefaultListModel<Piece>();
int sz=in.size();
String[] columns=new String[] {
"Type","Company","reference","description","price","To order"
};
DefaultTableModel model = new DefaultTableModel();
//JTable table=new JTable(null, in.toArray());
for (int i=0;i<sz;i++) {
Piece p=in.get(i);
String type=p.gettype();
String company=p.getasc();
String reference=p.getref();
String description=p.getdesc();
String price=p.getprice();
String image=p.getimage();
System.out.println(type);
//DefaultTableModel model=(DefaultTableModel) table.getModel();
model.addRow(new Object[]{type,company,reference,description,price,Integer.toString(0)});
}
JTable table=new JTable(model);
System.out.println(table.getRowCount());
return table;
}
static Graphicalinterface4 ssp;
public static void main(String[] args) throws IOException {
SwingUtilities.invokeLater(new Runnable() {
public void run() {ssp=new Graphicalinterface4();}
});
}
DefaultTableModel model = new DefaultTableModel();
You have 0 columns in the TableModel. The columns displayed is determined by the columns in the TableModel, not the number of items in each row. So adding rows of data has no effect.
Read the DefaultTableModel API for the proper constructor to use that will accept the "columns" variable as a parameter.
Thanks! I had not initialized the DefaultTableModel correctly. In the API the String[] and Object[][]{} are inverted(DefaultTableModel(String, Object[][]{}), but this works for me.
public JTable getlocaltable(ArrayList<Piece> in) {
//new Object[]{"Type","Company","reference","description","price","To order"}));
int sz=in.size();
String[] columns=new String[] {
"Type","Company","reference","description","price","To order"
};
DefaultTableModel model = new DefaultTableModel(new Object[][]{}, columns);
//JTable table=new JTable(model);
for (int i=0;i<sz;i++) {
Piece p=in.get(i);
String type=p.gettype();
String company=p.getasc();
String reference=p.getref();
String description=p.getdesc();
String price=p.getprice();
String image=p.getimage();
System.out.println(type);
//DefaultTableModel model=(DefaultTableModel) table.getModel();
model.addRow(new Object[]{type,company,reference,description,price,Integer.toString(0)});
}
JTable table=new JTable(model);
System.out.println(table.getRowCount());
return table;
}
Am programming of the application that manage football's players and clubs
I'm real stopped in small part and I couldn't find for it any solution after the try of many ideas.
Simply: I have a JTable and I want to refresh it after any task (Insert, Update or Delete).
That's the code
//for fill the JTable
// class controllApp
class controllApp(){
public DefaultTableModel getCleubData() {
Vector<Vector<String>> data = new Vector<Vector<String>>();
Vector<String> colum = new Vector<String>();
colum.add("id_c");
colum.add("coach");
colum.add("nom_cleub");
colum.add("DATE_CREATION");
colum.add("COULEUR_MAILLOT");
colum.add("COUNTRY");
String query = "select id_c,coach,nom_cleub,date_creation,couleur_maillot,country from CLEUB ORDER BY ID_C";
try {
Connection conn = ReportDriver.connectDB(DB_CONNECTION, DB_USER,
DB_PASSWORD);
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
Vector<String> vstring = new Vector<String>();
vstring.add(rs.getString("id_c"));
vstring.add(rs.getString("coach"));
vstring.add(rs.getString("nom_cleub"));
java.sql.Date date = rs.getDate("date_creation");
java.text.DateFormat df = java.text.DateFormat.getDateInstance();
vstring.add(df.format(date));
vstring.add(rs.getString("couleur_maillot"));
vstring.add(rs.getString("country"));
vstring.add("\n\n\n\n\n\n\n");
data.add(vstring);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException ex) {
}
}
}
DefaultTableModel d = new DefaultTableModel(data, colum);
return d;
}
}
//fill frame in other class (frame classe)
// class frame() to call controllAPP.getJoueurdata()
class frame(){
private static JTable table1;
AbstractTableModel model;
model = new controllApp().getJoueurData();
table1 = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table1);
scrollPane.setBounds(6, 29, 807, 297);
panel.add(scrollPane);
}
the solution is to get the Jtable's Model then add Vector data to it, then you have to set the model to the existing JTable.
I have a JTable which populates data from DB. I want to refresh data in JTable every 10 minutes (for testing 10 sec is enough). I tried do it with a Thread, but I found that it is not good idea, and I need to use SwingWorker
public class Monitor extends JFrame{
JTable jtable = null;
JTabbedPane jtp = null;
JPanel jp1 = null;
JPanel jp2 = null;
JLabel label1 = null;
JLabel label2 = null;
public void setJTable(Vector data, Vector columnNames) {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jtable = new JTable(data, columnNames);
JScrollPane scrollPane = new JScrollPane(jtable);
jp1.add(scrollPane);
}
public void updateJTable(Vector data, Vector columnNames) {
jtable = new JTable(data, columnNames);
}
public Monitor() {
setTitle("Monitor System");
//Panel with tabs for navigation
jtp = new JTabbedPane();
getContentPane().add(jtp);
//tab1, info from dba_jobs
jp1 = new JPanel();
//tab2 info from QueueInfo
jp2 = new JPanel();
label1 = new JLabel();
label1.setText("tab1");
label2 = new JLabel();
label2.setText("tab2");
jp1.add(label1);
jp2.add(label2);
jtp.add("Tab1", jp1);
jtp.add("Tab2", jp2);
}
}
And my Demo class:
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Statement stmt = null;
Connection conn = null;
ResultSet rs = null;
Vector<String> columnNames = new Vector<String>();
Vector<Vector> rowData = new Vector<Vector>();
DBMonitor dbmonitor = new DBMonitor();
Monitor monitor = new Monitor();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
rowData = dbmonitor.getJobsData();
columnNames = dbmonitor.getColumnNames();
monitor.setJTable(rowData, columnNames);
monitor.setSize((int) dim.getWidth(), (int) dim.getHeight());
monitor.setVisible(true);
boolean interrupt = true;
while (interrupt) {
try {
rowData = dbmonitor.getJobsData();
columnNames = dbmonitor.getColumnNames();
monitor.updateJTable(rowData, columnNames);
try {
Thread.sleep(10000);
} catch (InterruptedException ie) {
return;
}
JOptionPane.showMessageDialog(null, "SLEEP!");
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
System.err.println(e.getMessage());
}
}
}
}
How I can do it with SwingWorker? I don't get a concept of that way.
In the doInBackground() method of the SwingWorker you have you while loop that:
retrieves the data from the database
creates your TableModel
use the publish() method of the SwingWorker to pass the TableModel to the 'process()` method of your SwingWorker
sleeps for 10 seconds
Then in the process() method of the SwingWorker you:
use the TableModel that was passed to the process() method to update your JTable.
Read the section from the Swing tutorial on Concurrency for more information and a working example or search the forum for more SwingWorker examples.
First, I would start with a Timer of some sort, I'm going to use a Swing Timer as it easy, but you could use a java.util.Timer instead...
private Timer updateTimer;
//...
updateTimer = new Time(10000, new ActionListener() {
public void actionListener(ActionEvent e) {
}
});
updateTimer.setRepeats(false);
updateTimer.start();
This allows you to be notified in about 10 seconds time...
Then you need a SwingWorker that can do the actual work...
public class UpdateWorker extends SwingWorker<TableModel, Void> {
private Monitor monitor;
private Timer updateTimer;
public UpdateWorker(Monitor monitor, Timer updateTimer) {
this.monitor = monitor;
this.updateTimer = updateTimer;
}
#Override
protected TableModel doInBackground() throws Exception {
Vector<Vector> rowData = dbmonitor.getJobsData();
Vector columnNames = dbmonitor.getColumnNames();
DefaultTableModel model = new DefaultTableModel(rowData, columnNames);
return model;
}
#Override
protected void done() {
try {
TableModel model = get();
monitor.updateTable(model);
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
updateTimer.restart();
}
}
Now in the actionPerformed method of the ActionListener assigned to the timer, you would do something like..
public void actionListener(ActionEvent e) {
UpdateWorker worker = new UpdateWorker(monitor, this);
worker.execute();
}
To execute the worker. The reason for having a non-repeating timer is to ensure that the next update is set for n seconds from when the update completes, so you don't get overlapping updates
Oh, and this will require to update your Monitor to accept a TableModel rather then the Vectors you are using to create one, it's just simpler that way...
I've 2 panels. One where the user inserts the data and the other with a JTable where the results will be shown.
My problem is when the user press's the ok (in my case apply) JButton the data is computed but is not shown on the JTable, nothing changes in the JTable.
For my JTable I'm using the Bean Table Model from tips4Java (http://tips4java.wordpress.com/2008/11/27/bean-table-model/).
One weird thing is if I send data (lets call this data 'A') to the table when the program starts it is shown on the table and if later on I try to update the table, the table does not update. But when I don't send data to the table at start up but try to update/send the table with data 'A' it does not update.
So my question is, why is not the JTable showing whatever data I send to?
Here's my code:
JButton listenere that starts the processing and sends the data to the table:
crashForm.setFormListener(new FormListener() {
#Override
public void formEvent(OptionsFormEvent oe) {
String readTable = oe.getReadFromTable();
int access = oe.getAccess();
int transition = oe.getTransition();
boolean smooth = oe.isTrainCrash();
ArrayList<String> allTrains = new ArrayList<>();
List crashedTrainList = new ArrayList<>();
try {
allTrains = controller.getUniqueTrains(controller.connectServer(), readTable, "trainid");
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "An error occured while getting trains data\n"
+ "Error description: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
try {
for (int i = 0; i < allTrains.size(); i++)
{
ArrayList<Train> trainDataList = new ArrayList<>();
ArrayList<Train> crashedProccessedData = new ArrayList<>();
String query = "the sql query...";
trainDataList = controller.getTrainData(controller.connectServer(), readTable, query);
crashedProccessedData = controller.detectCrash(access, transition, trainDataList);
crashedTrainList.addAll(crashedProccessedData);
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "An error occured while detecting a crash.\n"
+ "Error description: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
System.out.println("Total crashes detected:" + crashedTrainList.size());
tablePanel.createTable(Train.class, crashedTrainList, true, false, tableLabels);
tablePanel.fireTableDataChanged();
}
});
}
And here's my tablePanel class:
public TablePanel() {
}
public void createTable(Class c, List data, boolean toolBarUp,
boolean toolBarBottom, ArrayList<String> labelsCheckBox) {
beanTableModel = new BeanTableModel(c, data);
columnModel = new XTableColumnModel();
table = new JTable(beanTableModel);
table.setColumnModel(columnModel);
table.createDefaultColumnsFromModel();
if(toolBarUp == true)
{
final JToolBar toolBarTop = new JToolBar();
// Create the Show ALL
JButton reset = new JButton("Reset");
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(Component c : toolBarTop.getComponents()){
if(c instanceof JCheckBox){
JCheckBox checkBox = (JCheckBox) c;
checkBox.setSelected(false);
columnModel.setAllColumnsVisible();
}
}
int numberOfColumn = columnModel.getColumnCount();
for(int aux = 0; aux < numberOfColumn; aux++)
{
int num = columnModel.getColumnCount();
TableColumn column = columnModel.getColumnByModelIndex(aux);
columnModel.setColumnVisible(column, true);
}
}
});
toolBarTop.add(reset);
// Create a JCheckBox for each column
for(int i = 0; i < labelsCheckBox.size(); i++)
{
final int index = i;
toolBarTop.add(new JCheckBox(new AbstractAction(labelsCheckBox.get(i)) {
#Override
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(index);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
}
setLayout(new BorderLayout());
add(toolBarTop, BorderLayout.NORTH);
add(new JScrollPane(table), BorderLayout.CENTER);
// add(toolBarDown, BorderLayout.SOUTH);
}
final JToolBar toolBarDown = new JToolBar();
toolBarDown.add(new JButton(new AbstractAction("Save Table") {
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}));
}
public void createTable(Class c, Class cAncestor) {
beanTableModel = new BeanTableModel(c, cAncestor);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void createTable(Class c, Class cAncestor, List data) {
beanTableModel = new BeanTableModel(c, cAncestor, data);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
beanTableModel.fireTableDataChanged();
}
public void createTable(Class c) {
beanTableModel = new BeanTableModel(c);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void createTable(Class c, List data)
{
beanTableModel = new BeanTableModel(c, data);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
//to refresh the table everytime there is an update
public void fireTableDataChanged()
{
beanTableModel.fireTableDataChanged();
}
So again, my question is: Isn't my JTable not updated with the new results every time I send new data to it?
You should never invoke fireTableDataChanged manually. Only the TableModel is responsible for invoking this event.
From your code it looks like you are creating a new TableModel, JTable and JScrollPane every time you make a change. Any time you add a component to a visible GUI the basic code should be:
panel.add(....);
panel.revalidate();
panel.repaint();
By default all components have a size of zero so since you don't invoke revalidate() then never get a proper size and there is nothing to paint. Also, it is never a good idea to simply keep adding components to the CENTER of your panel since the old component are still part of the container.
However, there is a better solution. There is no need to keep creating new components. All you need to do is create an new TableModel and then use:
table.setModel( newlyCreatedModel );
and the model will be added to the table and the table will repaint itself automatically.
I have jFrame2 which contains jTable with 4 columns (the jTable taking data from table in database which contain 20 columns)
Also I have jFrame1 which I have used it to fill database.
What I want to do that when I select row in jTable and click jButton, it must open jframe1 showing all data for that row.
i will clear what i want in points
*i want open jframe1 from jframe2 via jbutton(this task is done and this is the code)
public void actionPerformed(ActionEvent e) {
if(e.getSource()==jButton2){
jframe2 regFace =new jframe2();
regFace.setVisible(true);
}}
*once jframe1 opened by jbutton in jframe2 it must show in it fields all data of selected row in jframe2>>this point mean
........-sql query executed once jfram1 opened by Jbutton in jframe2
.........-showing data in jtextfield taking from database by query i mentioned in line above (this task is done and this is the code but not completed)
try {
dbconnect = new myDbConnection();
ResultSet resultSet =null;
resultSet = dbconnect.excuteQuery("SELECT id, area,location, status1 FROM pledges where id='17'");
while (resultSet.next()){
id.setText(resultSet.getString(1));
area.setText(resultSet.getString(2));
location.setText(resultSet.getString(3));
status.setText(resultSet.getString(4));
// i = Long.parseLong(rs1.getString(1));
}
*in brief i want understand jframe1 that please if you opened by jframe2 execute a query and fill text fields by that query
*this is picture would clear better
here
It sounds like the part you are having trouble with is how to get the selected data from the table into the fields in jframe1.
A lot of this depends on the TableModel that is used in your JTable. Assuming you just used a DefaultTableModel, you can get the selected row data like this:
#Override
public void actionPerformed(ActionEvent e) {
int viewRow = myJTable.getSelectedRow();
int modelRow = myJTable.convertRowIndexToModel(viewRow);
DefaultTableModel model = (DefaultTableModel) myJTable.getModel();
// You will get a compiler warning on the following line, but there's not much you can do about it beside suppress it
Vector<Object> rowVector = (Vector<Object>) model.getDataVector().get(modelRow);
jframe2 regFace =new jframe2();
regFace.setSelectedRow(rowVector);
regFace.setVisible(true);
}
And you would have the following method in your jframe2 class:
public void setSelectedRow(Vector<Object> row ) {
id.setText(row.get(0).toString());
area.setText(row.get(1).toString());
location.setText(row.get(2).toString());
status.setText(row.get(3).toString());
// continue for all columns
}
before i put the answer i would thank #wolfcastle such a nice person.He almost answer the question and i'm just modify it to adapt it with sql query and database.
this is the code for jfrme2
public void actionPerformed(ActionEvent e) {
if(e.getSource()==jButton2){
int viewRow = jTable1.getSelectedRow();
int modelRow = jTable1.convertRowIndexToModel(viewRow);
Object oc= jTable1.getModel().getValueAt(modelRow, 0);
String vv=oc.toString();
DefaultTableModel model = (DefaultTableModel) jTable1.getModel();
jframe1 regFace =new jframe1();
try {
regFace.setSelectedRow(vv);
} catch (SQLException ex) {
Logger.getLogger(showp1.class.getName()).log(Level.SEVERE, null, ex);
}
regFace.setVisible(true);
}
}
and the the code for jframe1
public void setSelectedRow(String row ) throws SQLException {
dbconnect = new myDbConnection();
ResultSet resultSet =null;
System.out.print(row);
resultSet = dbconnect.excuteQuery("SELECT id, area,location, status1 ,date1,insname,oname,bname,street,junction,INSPSITION,recname1 FROM pledges where id='"+row+"'");
while (resultSet.next()){
id.setText(resultSet.getString(1));
area.setText(resultSet.getString(2));
location.setText(resultSet.getString(3));
status.setText(resultSet.getString(4));
date.setText(resultSet.getString(5));
insname.setText(resultSet.getString(6));
oname.setText(resultSet.getString(7));
bname.setText(resultSet.getString(8));
street.setText(resultSet.getString(9));
junction.setText(resultSet.getString(10));
insposition.setText(resultSet.getString(11));
recname.setText(resultSet.getString(12));
}
}