Witam, mam problem z edycją komórek w mojej Tabeli (JTable), chodzi o to że po edycji, zmienione dane w komórce się nie zapisują. Jak zrobić, żeby dane zapisywały się po edycji np. do ArrayListy, albo tablicy??
Nadpisz w klasie z modelem dziedziczącej po DefaultTableModel (lub w klasie z tabelą dziedziczącej po JTable) metodę setValuAt(Object value, int wiersz, int kolumna)
. value
, to to co wpisał użytkownik podczas edycji, wiersz
i kolumna
to współrzędne edytowanej komórki. Jeżeli nadpiszesz metodę w klasie dziedziczącej po JTable (a nie po modelu), to musisz uwzględnić, że współrzędne dotyczą widoku i mogą się różnić od współrzędnych w modelu jeżeli dopuszczalne jest sortowanie i przestawianie kolumn.
No człowieku... przydałoby się trochę kodu. Jaki masz TableModel, gdzie są te dane?
Próbowałeś
tableModel.fireTableDataChanged();
?
Dane przechowuję w tablicy 2-wymiarowej i w liście Array, ponieważ pobieram je z pliku, zrobiłem coś takiego
Object[][] data;
public Object getValueAt(int row, int col)
{
return data[row][col];
}
public void setValueAt(Object value, int row, int col)
{
data[row][col] = value;
tablica[row][col]= (String) data[row][col]; //tablica to właśnie ta moja tablica w której przechowuję dane.
}
Chcę po prostu żeby te dane po edycji, zapisały się w mojej tablicy, a później żeby się zaktualizowały(odpowiednie linijki) w pliku. (Np. edytuję 3 komórkę w 1 wierszu, oczywiście w programie jest indeksowanie od 0, ale to tylko dla przykładu, to dane w tablicy[1][3] się zmienią, a w pliku zaktualizuje się 3 linijka.
dodane znaczniki <code class="java"> - fp
W tablicy juz zakualizowałeś. Kiedy ma się aktualizować w pliku? Bez sensu jest by przepisywac cały plik po zmianie kazdej komórki. Zapisuj jak uzytkownik zamyka program. W głównym oknie:
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
Dodaj do okna WindowListenera, w metodzie windowClosing() zapisz nowa wersje pliku i wywołaj System.exit(0);
Przy wywoływaniu metod get i set mam błąd..
int wiersz = tabela.getEditingRow();
int kol = tabela.getEditingColumn();
model.getValueAt(wiersz, kol); // w tej linijce mam błąd Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1 czyli że coś z rozmiarem tablicy?
model.setValueAt(dane, wiersz, kol);
dodane znaczniki <code class="java"> - fp
Ty nie masz wywoływać metod getValueAt i setValueAt. One zostana wywołane automatycznie. Ty je masz tylko napisać.
A jak dodać tego WindowListenera?
mam główną klasę Okno która dziedziczy po JFrame i implementuje ActionListenera i w niej jest wszystko co znajduje się w tym oknie, JTabela, przyciski itd.
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
//zapisanie do pliku
System.exit(0);
}
});
Nie mam pojęcia czemu, ale ta edycja nie działa..
public class Okno extends JFrame implements ActionListener {
JMenuBar menuBar;
JMenu menuPlik, menuEdycja;
JMenuItem mNowe, mWyjscie, mEdycja, mUsun;
JLabel lZadania;
JPanel pNowe;
JTable tabela;
JScrollPane scrollPane;
Object[][] dane;
int ileLinijek=0;
String[][] tablica;
//String[][] rowData;
String [] kolumny= {"Data", "Godzina", "Zadanie"};
ArrayList<String> w = new ArrayList<String>();
DefaultTableModel model;
public Okno()
{
setSize(700,400);
setTitle("Terminarz zadań");
setLayout(null);
menuBar = new JMenuBar();
menuPlik = new JMenu("Plik");
menuEdycja = new JMenu("Edycja");
lZadania = new JLabel("Twoje zadania");
lZadania.setBounds(10,10,100,20);
mNowe = new JMenuItem("Nowe zadanie", 'N');
mWyjscie = new JMenuItem("Wyjście");
mEdycja = new JMenuItem("Edytuj");
mUsun = new JMenuItem("Usuń");
menuPlik.add(mNowe);
menuPlik.addSeparator();
menuPlik.add(mWyjscie);
mNowe.addActionListener(this);
mWyjscie.addActionListener(this);
mEdycja.addActionListener(this);
mUsun.addActionListener(this);
mNowe.setAccelerator(KeyStroke.getKeyStroke("ctrl N"));
mWyjscie.setAccelerator(KeyStroke.getKeyStroke("ctrl X"));
mEdycja.setAccelerator(KeyStroke.getKeyStroke("ctrl E"));
mUsun.setAccelerator(KeyStroke.getKeyStroke("ctrl Q"));
menuEdycja.add(mEdycja);
menuEdycja.add(mUsun);
setJMenuBar(menuBar);
menuBar.add(menuPlik);
menuBar.add(menuEdycja);
add(lZadania);
Odczyt();
model = new DefaultTableModel(tablica,kolumny);
tabela = new JTable();
tabela.setModel(model);
tabela.setBounds(100,100,660,300);
tabela.getColumnModel().getColumn(0).setMinWidth(80);
tabela.getColumnModel().getColumn(0).setMaxWidth(80);
tabela.getColumnModel().getColumn(1).setMinWidth(120);
tabela.getColumnModel().getColumn(1).setMaxWidth(120);
tabela.setRowHeight(30);
tabela.setVisible(true);
RowSorter<DefaultTableModel> sorter = new TableRowSorter<DefaultTableModel>(model);
tabela.setRowSorter(sorter);
add(tabela);
scrollPane = new JScrollPane(tabela);
scrollPane.setBounds(10,30,660,300);
scrollPane.setVisible(true);
add(scrollPane);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent we)
{
try
{
FileWriter plik = new FileWriter("Zadania.txt");
PrintWriter pw = new PrintWriter(plik);
for(int i=0;i<(w.size())/3;i++)
{
for(int j=0;j<3;j++)
{
pw.println(tablica[i][j]);
}
}
pw.close();
} catch (IOException ex) {
Logger.getLogger(OknoNowe.class.getName()).log(Level.SEVERE, null, ex);
}
System.exit(0);
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
Object zrodlo = e.getSource();
if(zrodlo==mNowe)
{
OknoNowe ok = new OknoNowe();
ok.setVisible(true);
}
if(zrodlo==mWyjscie)
dispose();
if(zrodlo==mUsun) //Usuwanie zaznaczonego wiersza w JTabeli
{
int odp = JOptionPane.showConfirmDialog(null, "Czy jesteś pewny/a,"
+ " że chcesz usunąć zadanie?", "Potwierdzenie", JOptionPane.YES_NO_OPTION);
if(odp==JOptionPane.YES_OPTION)
{
int wiersz = tabela.getSelectedRow();
model.removeRow(tabela.getSelectedRow());
int Od = wiersz*3;
int Do = wiersz*3+3;
w.subList(Od,Do).clear();
for(int i=0;i<(w.size())/3;i++)
{
for(int j=0;j<3;j++)
{
tablica[i][j] = w.get((3*i)+j);
}
}
for(int i=0;i<(w.size())/3;i++)
{
for(int j=0;j<3;j++)
{
System.out.println(tablica[i][j]+" ");
}
}
try
{
FileWriter plik = new FileWriter("Zadania.txt");
PrintWriter pw = new PrintWriter(plik);
for(int i=0;i<(w.size())/3;i++)
{
for(int j=0;j<3;j++)
{
pw.println(tablica[i][j]);
}
}
JOptionPane.showMessageDialog(null, "Wiersz usunięto pomyślnie :)");
System.out.print("Wielkośc array "+w.size()+"\n wielkosc tablicy " +tablica.length+"\n");
pw.close();
} catch (IOException ex) {
Logger.getLogger(OknoNowe.class.getName()).log(Level.SEVERE, null, ex);
}
}else if(odp==JOptionPane.NO_OPTION)
{
}
}
}
protected void Odczyt() //Czytanie z pliku do ArrayListy a później przepisanie do tablicy
{
try {
File plik = new File("Zadania.txt");
Scanner skaner = new Scanner(plik);
while(skaner.hasNext())
{
ileLinijek++;
skaner.nextLine();
}
} catch (FileNotFoundException ex) {
Logger.getLogger(Okno.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.print("Ilosc linijek: "+(ileLinijek-1)/3+" ");
try {
File plik = new File("Zadania.txt");
Scanner skaner = new Scanner(plik);
/*for(int i=0;i<(ileLinijek-2)/3;i++)
for(int j=0;j<3;j++)*/
while(skaner.hasNext())
{
w.add(skaner.nextLine());
}
} catch (FileNotFoundException ex) {
Logger.getLogger(Okno.class.getName()).log(Level.SEVERE, null, ex);
}
tablica = new String[w.size()/3][3];
System.out.print("wielkosc array "+w.size()+"\n");
for(int i=0;i<w.size()/3;i++)
{
for(int j=0;j<3;j++)
{
tablica[i][j] = w.get((3*i)+j);
}
}
for(int i=0;i<w.size()/3;i++)
{
for(int j=0;j<3;j++)
{
System.out.println(tablica[i][j]);
}
}
}
public Object getValueAt(int row, int col)
{
return dane[row][col];
}
public void setValueAt(Object value, int row, int col)
{
dane[row][col] = value;
tablica[row][col]= (String) dane[row][col];
}
}
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent we) //zapis
{
try
{
FileWriter plik = new FileWriter("Zadania.txt");
PrintWriter pw = new PrintWriter(plik);
for(int i=0;i<(w.size())/3;i++)
{
for(int j=0;j<3;j++)
{
pw.println(tablica[i][j]);
}
}
pw.close();
} catch (IOException ex) {
Logger.getLogger(OknoNowe.class.getName()).log(Level.SEVERE, null, ex);
}
System.exit(0);
}
});
public void setValueAt(Object value, int row, int col)
{
dane[row][col] = value;
tablica[row][col]= (String) dane[row][col];
}
A gdzie jest
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
W 2 klasie o nazwie Test gdzie jest tylko metoda main w której mam
public static void main(String[] args)
{
Okno o = new Okno();
o.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
o.setVisible(true);
}
Napisz klasę, która dziedziczy po DefaultTableModel, w niej umieść metody setValueAt i getValueAt. Jak zrobisz z niej klasę wewnetrzną, to nie będziesz musiał niczego przekazywać.
class Model extends DefaultTableModel
{
...
}
...
model = new Model();
tabela = new JTable(model);
ale ona musi być w oddzielnym pliku czy nie??
Klasa wewnętrzna w osobnym pliku?
public class Okno extends JFrame implements ActionListener {
...
class Model extends DefaultTableModel
{
}
}
Wstawiłem do konstruktora Okno i wyskakuje błąd
found: java.lang.String[][],java.lang.String[]
reason: actual and formal argument lists differ in length
w tej linijce
model = new Model(tablica,kolumny);
Jak zrobisz z niej klasę wewnetrzną, to nie będziesz musiał niczego przekazywać
model = new Model();
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
at java.util.Vector.elementAt(Vector.java:470)
at javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:294)
at Okno.<init>(Okno.java:118)
at Test.main(Test.java:16)
Trochę przesadziłem, że niczego nie trzeba przekazywać.
model = new Model(kolumny,w.size()/3);
tabela = new JTable(model);
...
class Model extends DefaultTableModel
{
public Model(Object[] columns,int rowCount)
{
super(columns,rowCount);
}
public Object getValueAt(int row, int col)
{
return tablica[row][col];
}
public void setValueAt(Object value, int row, int col)
{
tablica[row][col] = (String) value;
}
}
Ok zmienia, ale teraz problem bo w nazwach kolumn jest jakieś "java.lang..." bla bla....
W ogóle cała tabela się pokićkała, nie wczytuje z wszystkiego z pliku.
I jednak muszę mieć zapis do pliku od razu po edycji każdej komórki, a nie przy wyłączaniu, ponieważ mam drugie okienko w którym wypełniam formularz i zapisuje właśnie do pliku i zapisuje się ale dopóki nie zamknę tego pierwszego głównego okienka, jak zamknę to po prostu wstawia to co było wcześniej (zapamiętane już przez tablicę).
Ok, już sobie poradziłem z tymi kolumnami i zapisem, wszystko jest ok, ale jeszcze mam pytanie bo za każdym razem gdy w tej 2 ramce wypełniam formularz i zapisuje, muszę zamknąć i włączyć aplikację żeby dane pojawiły się w tabeli i chciałbym się dowiedzieć czy da się tak zrobić żebym nie musiał wyłączać i włączać aplikacji?
Zmodyfikuj dane w zmiennej tablica i wywołaj (odpowiednią) metodę fireTable....
właśnie tablica się odświeża ładnie, a tabela coś nie chce...