Question:
I have a JFrame
, where inside it has a JTable
and a JButton
(Change) that calls another JFrame. In this other JFrame, a data change is performed according to the selected row in the table and saved in the DB by clicking on a JButton (Save).
My problem is that the data is not automatically updated in my JTable when I save the change, so how do I call a function from a JFrame that is already open?
It doesn't work to do the following:
public class JFAltera extends javax.swing.JFrame {
...
private void jbSalvarActionPerformed(java.awt.event.ActionEvent evt) {
JFrameTabela jFrameTabela = new JFrameTabela();
jFrameTabela.atualizaJTable();
}
...
}
public class JFrameTabela extends javax.swing.JFrame {
...
public void atualizaJTable(){
...
}
...
}
Because I don't want to instantiate a new JFrame but call the (public) function of a JFrame that is already open.
Verifiable example of classes:
JFrameTable Class:
import javax.swing.table.DefaultTableModel;
public class JFrameTabela extends javax.swing.JFrame {
public JFrameTabela() {
initComponents();
readJTable(); // Atualiza os dados na tabela
}
public void readJTable(){
DefaultTableModel tableModel = (DefaultTableModel) jTable.getModel();
//Inicia a tabela com 0 linhas novamente
tableModel.setNumRows(0);
//Inserir 10 Linhas
for(int i = 0; i < 10; i++){
tableModel.addRow(new Object[]{
"Teste 1",
"Teste 2",
"Teste 3",
"Teste 4"
});
}
}
@SuppressWarnings("unchecked")
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTable = new javax.swing.JTable();
jbAlterar = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{null, null, null, null},
{null, null, null, null},
{null, null, null, null},
{null, null, null, null}
},
new String [] {
"Title 1", "Title 2", "Title 3", "Title 4"
}
));
jScrollPane1.setViewportView(jTable);
jbAlterar.setText("Alterar");
jbAlterar.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbAlterarActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(226, 226, 226)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(426, 426, 426)
.addComponent(jbAlterar)))
.addContainerGap(401, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(28, 28, 28)
.addComponent(jbAlterar)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 70, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 228, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(89, 89, 89))
);
pack();
}
private void jbAlterarActionPerformed(java.awt.event.ActionEvent evt) {
//Abro o meu JFrameAltera e envio os dados da linha selecionada
JFrameAltera obj = new JFrameAltera();
obj.setVisible(true);
obj.preencheDados(jTable.getValueAt(jTable.getSelectedRow(),0).toString(),
jTable.getValueAt(jTable.getSelectedRow(),1).toString(),
jTable.getValueAt(jTable.getSelectedRow(),2).toString(),
jTable.getValueAt(jTable.getSelectedRow(),3).toString());
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(JFrameTabela.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(JFrameTabela.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(JFrameTabela.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(JFrameTabela.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new JFrameTabela().setVisible(true);
}
});
}
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTable jTable;
private javax.swing.JButton jbAlterar;
}
Classe JFrameAltera:
public class JFrameAltera extends javax.swing.JFrame {
public JFrameAltera() {
initComponents();
}
public void preencheDados(String string1, String string2, String string3, String string4){
//Preenche os campos com as informações das linha selecionada no "JFrameTabela"
jf1.setText(string1);
jf2.setText(string2);
jf3.setText(string3);
jf4.setText(string4);
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jf1 = new javax.swing.JTextField();
jf2 = new javax.swing.JTextField();
jf3 = new javax.swing.JTextField();
jf4 = new javax.swing.JTextField();
jbSalvar = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jbSalvar.setText("Salvar");
jbSalvar.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbSalvarActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(117, 117, 117)
.addComponent(jf1, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(32, 32, 32)
.addComponent(jf2, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(36, 36, 36)
.addComponent(jf3, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(jf4, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(241, 241, 241)
.addComponent(jbSalvar)))
.addContainerGap(458, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(69, 69, 69)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jf1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jf2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jf3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jf4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(63, 63, 63)
.addComponent(jbSalvar)
.addContainerGap(292, Short.MAX_VALUE))
);
pack();
}
private void jbSalvarActionPerformed(java.awt.event.ActionEvent evt) {
//Aqui eu gravo as informações no BD (Funcionando)
//***********É aqui que eu preciso chamar minha função "readJTable" do "JFrameTabela" que já está aberto.
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(JFrameAltera.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(JFrameAltera.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(JFrameAltera.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(JFrameAltera.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new JFrameAltera().setVisible(true);
}
});
}
private javax.swing.JButton jbSalvar;
private javax.swing.JTextField jf1;
private javax.swing.JTextField jf2;
private javax.swing.JTextField jf3;
private javax.swing.JTextField jf4;
}
Answer:
When working with more than one screen, the ideal is always to use only one JFrame
as the main screen and create JDialogs
as secondary screens, because in addition to the modal feature, you can link them all to the main frame.
As the code presented is very generic, I'll try to answer on top of it. Following the previous tip, I recommend that you change the JFrameAltera
class so that it is a JDialog
dependent on the JFrameTabela
class, so it is much easier to exchange information between them.
So the class signature would look like this:
public class JFrameAltera extends javax.swing.JDialog {
Another detail is that on the button that opens the new window, you are passing the sequence between 1 and 4 as the number of columns, when in fact the numbering of rows and columns in java always starts at 0, so the numbering for 4 columns goes from 0 to 3. Another problem is that you don't really check if there are any selected rows in the table before retrieving the data, and this will throw ArrayIndexOutOfBoundsException
, because the getSelectedRow()
method returns -1 when there is no selection, and -1 does not it is part of the range of rows in a table.
In your JFrameAltera
class, after changing to JDialog
, the constructor will look like this:
public JFrameAltera(Frame parent, boolean isModal) {
super(parent, isModal);
initComponents();
}
The first parameter represents which frame the screen originated from, and the second makes the screen modal (that is, while it is open, the originating screen is blocked for change).
In the save button event, you will continue saving the new data to the database, and close the screen by adding this.dispose();
.
Based on the code presented, you will create a method where you will abstract the data saved in an object and return it, I used the Object
class here just to demonstrate:
public Object[] recuperaDados(){
Object[] obj = {
jf1.getText(),
jf2.getText(),
jf3.getText(),
jf4.getText()
};
return obj;
}
Now in the main class, in the same method where you open the change window, you will change it as follows:
private void jbAlterarActionPerformed(java.awt.event.ActionEvent evt) {
if (jTable.getSelectedRow() != -1) {
JFrameAltera tela2 = new JFrameAltera(this, true);
tela2.preencheDados(jTable.getValueAt(jTable.getSelectedRow(), 0).toString(),
jTable.getValueAt(jTable.getSelectedRow(), 1).toString(),
jTable.getValueAt(jTable.getSelectedRow(), 2).toString(),
jTable.getValueAt(jTable.getSelectedRow(), 3).toString());
tela2.setVisible(true);
Object[] obj = tela2.recuperaDados();
for (int i = 0; i < obj.length && i < jTable.getColumnCount(); i++) {
jTable.setValueAt(obj[i], jTable.getSelectedRow(), i);
}
}
}
The method now checks if there is a selected row before opening the screen ( getSelectedRow() != -1
), and as soon as the screen is closed, it already retrieves the data and saves it in the table.
With these changes, the readtable
method loses its meaning and can be removed.