Odświeżanie JTable

0

Mam problem, ponieważ nie wiem jak odświeżyć JTable po dodaniu rekordu do bazy danych. Sytuacja jest następująca. Po uruchomieniu programu ładuje się Ramka (JFrame), zawierająca różne przyciski (między innymi przycisk dodawania nowych rekordów do bazy), oraz obiekt JTable, który wypełnia się danymi, pobieranymi z bazy danych przy uruchamianiu aplikacji.
Chcąc dodać nowy rekord wybieramy stosowny przycisk na głównym oknie co powoduje wyświetlenie JDialoga, w którym znajduję się stosowny formularz. Po zatwierdzeniu tego okna, rekord wędruje do bazy danych lecz brakuje aktualizacji obiektu JTable.
Czytałem, że aby uzyskać zamierzony efekt można skorzystać z metody fireTableDataChanged(), którą powinno się zaimplementować w modelu tabeli; itp., jednak nie wiem jak je zaimplementować w przypadku mojej aplikacji, tzn. próbowałem różnych kombinacji, szukałem na googlach i nie znalazłem nic sensownego.
Na listingu poniżej przedstawiłem kod mojego modelu tabeli:

import javax.swing.table.*;
import java.util.*;
import java.sql.*;

/**
 *
 * @author Yuras
 */
/**
 * Klasa modelu tabeli
 * @author Yuras
 */
class MyTableModel extends AbstractTableModel {

    String[] columnNames = {"Id",
        // tutaj nazwy 7 pozostalych kolumn 
    };

    private Object[][] obiekt() {
        ArrayList dane = null;
        try {
            Baza baza = new Baza();
            dane = baza.Odczyt();
        } catch (SQLException ex) {
        }


        Object[][] ob = new Object[dane.size()][8];
        for (int i = 0; i < dane.size(); i++) {
            String[] linia = (String[]) dane.get(i);
            ob[i][0] = linia[0];
            ob[i][1] = linia[1];
            ob[i][2] = linia[2];
            ob[i][3] = linia[3];
            ob[i][4] = linia[4];
            ob[i][5] = linia[5];
            ob[i][6] = linia[6];
            ob[i][7] = linia[7];

        }
        return ob;
    }
    private Object[][] data = obiekt();

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return data.length;
    }

    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        return data[row][col];

    }

    @Override
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return true;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {

        data[row][col] = value;
        fireTableCellUpdated(row, col);
    }
}

Do obsługi bazy danych wykorzystywana jest klasa Baza przytoczona na powyższym listingu. JTable znajduję się na panelu PanelTresci, który jest zarazem osobną klasą, wywoływaną na panelu głównym klasa Panel główny.</i>

0

Skorzystaj z metody

fireTableRowsInserted(...)

i analogicznie

fireTableRowsDeleted(...)

0

Znalazłem już gdzieś te metody, ale zasadnicze pytanie jak mam je zaimplementować. Ponieważ gdy dodaje rekord, robie to w innym okienku niż znajduje się tabela.
Próbowałem w modelu stworzyć metodę
addRow();
która wywołuje przytoczone powyżej polecenie
a następnie po dodaniu rekordu wywołać
new MyTableModel().addRow();
lecz jednak jest to chyba bez sensu, ponieważ tworzy to nie jako nowy obiekt modelu i nie odwołuje się w żaden sposób do tego istniejącego już, chyba że się mylę...

0
JTable table = ...
((MyTableModel)table.getModel()).addRow(row);
0

Ale w którym momencie mam to wywołać?
Przedstawię szybko strukturę aplikacji.

Po uruchomieniu aplikacji ładuje się ramka na której umieszczony jest panel główny. Na panelu głównym znajdują się 2 panele. Pierwszy z nich zawiera przyciski m.in. przycisk dodawania nowych filmów. Na drugim znajduje się właśnie obiekt JTable, realizowany przez kod:

MyTableModel model = new MyTableModel();
table = new JTable(model);

Dane, zgodnie z tym co napisałem w postach wyżej pobierane są w modelu. Korzystamy ze specjalnie napisanej w tym celu klasy Baza.

I teraz najważniejszy punkt dodawanie. Dodawanie jest realizowane na innym, nowym panelu. W momencie nacisnięcia przycisku dodającego rekord uruchamiana jest metoda dodawania operująca na bazie danych, której całkowity kod został przedstawiony poniżej:

    public void dodaj(Object[] row) throws SQLException {
        int id_nosnika = 0, id_grupy = 0, id_jakosc = 0;
        Statement st1 = conn.createStatement();
        ResultSet rs1 = st1.executeQuery("SELECT id_nosnika FROM nosnik WHERE nosnik='" + row[2] + "'");
        while (rs1.next()) {
            id_nosnika = rs1.getInt("id_nosnika");
        }
        rs1 = st1.executeQuery("SELECT id_grupy FROM grupa WHERE nazwa_grupy='" + row[3] + "'");
        while (rs1.next()) {
            id_grupy = rs1.getInt("id_grupy");
        }
        rs1 = st1.executeQuery("SELECT id_jakosc FROM jakosc WHERE nazwa_jakosc='" + row[4] + "'");
        while (rs1.next()) {
            id_jakosc = rs1.getInt("id_jakosc");
        }
        rs1.close();

        String sql = "INSERT INTO spis VALUES (null,'"+row[1]+"',"+id_nosnika+","+id_grupy+","+id_jakosc+",'"+row[5]+"','"+row[6]+"','"+row[7]+"')";
        st1.execute("SET NAMES 'utf8'");
        st1.executeUpdate(sql);
        st1.close();
    }    

I teraz moje pytanie, gdzie należy umieścić wywołanie metody addRow(Object[] row)?
Kod metody addRow(Object[] row) przedstawiony został poniżej:

    public void addRow(Object[] row) throws Exception {
        if (row.length != getColumnCount()) {
            throw new Exception("Niewłaściwe dane");
        }
               Object[][] newdata=new Object[data.length+1][8];
                 for(int i=0; i<data.length; i++)
                        for(int j=0; j<8; j++)
                               newdata[i][j]=data[i][j];
              for(int i=0; i<8; i++)
                     newdata[data.length][i] = row[i];
            this.data=newdata;
            fireTableDataChanged();
            //fireTableRowsInserted(0, 0);
        
    }
0

Tą metodę wywołaj na końcu metody addRow, oczywiście wywołaj ją na odpowiednim obiekcie klasy MyTableModel. Wtedy JTable zapyta model o nowy wiersz i doda go do tabeli.

0

Ale obiekt MyTableModel, który wyświetla dane znajduje się w jednej klasie, a samo dodawania danych przeprowadzane jest w innej klasie, więc chyba nie mogę w żaden sposób przekazać tego.. Możliwe, że się mylę, mógłbyś to może zobrazować jakimś kawałkiem kodu? Z góry dzięki, bo mi się już wszystko zaczęło plątać...

0

Jeśli dwie klasy mają współpracować, to obiekty jednej z nich powinny zawierać referencje do obiektów drugiej klasy, jeżeli klasa odpowiadająca u Ciebie za dopisywanie nazywa się Dopisywacz, to dodaj w klasie
pole

MyTableModel model;

zapewnij sobie (konstruktorem lub metodą setModel()) by pole model wskazywało na używany przez ciebie model danych i po dopisaniu wywołaj model.fireTableDataChanged();
pozdrawiam

0

Ja rozumiem o co chodzi, ale nie wiem jak właśnie w kodzie wykonać te referencję. Wiem, że to prawdopodobnie prosta sprawa.
Ta tabela znajduje się w klasie PanelTresci
i tutaj tworze nowy obiekt modelu:

MyTableModel model = new MyTableModel(); // tworze nowy obiekt modelu
public PanelTresci(){
table = new JTable(model); // podłączam go do tabeli
// inne akcje
...

klasa w której wpisuje nowe rekordy to RamkaDodawania
Utworzyłem tutaj niezbędne pole

MyTableModel  model;

i teraz nie wiem jak utworzyć referencje do obiektu model utworzonego w klasie PanelTresci.
Bo mogę wykonać znowu

model = new MyTableModel();

ale dostane w zamian kolejny obiekt, który nie odświeży mojej tabelki, a jak wykonać te referencję? Muszę chyba odświeżyć swoje podstawy Javy...

0

Jeśli pole model w klasie RamkaDodawaniai jest prywatne (a powinno takie być), to dodaj metodę

public void setModel(MyTableModel m)
{
     model=m;
}

Jeżeli obiekt klasy RamkaDodawania jest tworzony w klasie PanelTresci, to zrób coś takiego

PanelTresci pt=new PanelTresci();
pt.setModel(model);

ewentualnie zdefiniuj inny konstruktor i zrób tak

PanelTresci pt=new PanelTresci(model);

Jeśli RamkaDodawania oraz PanelTresci są tworzone w jeszcze innej klasie, to uzupełnij
klasę PanelTresci o metodę public MyTableModel getModel() i zrób coś takiego

PanelTresci pt=new PanelTresci();
RamkaDodawania rd=new RamkaDodawania();
......
pt.setModel(rd.getModel());
0

Dzięki wielkie:) Działa:)

1 użytkowników online, w tym zalogowanych: 0, gości: 1