Mam taki problem. Wyświetlam dane z bazy danych w JTable. W programie jest opcja dodania rekordu. Jak odświeżyć ta tabele żeby pokazywała tez ten dodany rekord ??
Korzystasz z AbstractTableModel ?? Powinieneś wykorzystać sprzężenie zwrotne jak to się tak ładnie nazywa :P Użyj fireTableCellUpdated(int row, int col)
Tak urzywam AbstractTableModel. Ale fireCellUpdated pozawa tylko zmienic zawatrośc istniejącej komorki a ja musze dodać (usunąć) cały wiersz (powiekszyć (zmniejszyć) tabele a nie zmienic to co isnieje już).
fireTableDataChanged()
Poniżej zamieszczam kod mojej tabeli. Chce usunąćcały ostatni rząd, jak zostana wprowadzone zmiany w pierwszym rzedzie w pierwszej kolumnie. Cos mi nie idzie.
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
//wewnetrzna klasa z tabela
public class TabelaGraczy extends AbstractTableModel implements TableModelListener{
String[] nazwy;
Object[][] dane;
Object[] pola;
JTable tabela;
JScrollPane suwak;
DefaultTableModel tabModel;
int row, column;
public TabelaGraczy() {
tabModel = new DefaultTableModel();
tabela = new JTable(tabModel);
suwak = new JScrollPane(tabela);
pola = new String[6];
nazwy = new String []{"1","2","3","4","5","5"};
for(int a=0;a<nazwy.length;a++)
{
tabModel.addColumn(nazwy[a]);
}
for(int a=0;a<3;a++)
{
dodajRekord();
}
tabela.getModel().addTableModelListener(this);
}
public void dodajRekord()
{
tabModel.addRow(new Object[] {"Cos","Cos","Cos","Cos","Cos", "Nie"});
}
public void tableChanged(TableModelEvent e) {
row = e.getFirstRow();
column = e.getColumn();
String wartosc = tabela.getValueAt(row,column).toString();
if(row==0 && column==0)
{
System.out.println("zmiana w tabeli rzad" + this.getRowCount() + " kolumna " + this.getColumnCount());
fireTableRowsDeleted(4,4);
}
}
public int getRowCount() {
return this.row;
}
public int getColumnCount() {
return this.column;
}
public Object getValueAt(int rowIndex, int columnIndex) {
return dane[row][column];
}
}
Probowałem różne opcje fireTable.... i bez skutku;/.
Ja zrobiłbym to tak:
package table;
import javax.swing.table.AbstractTableModel;
public class MyTableModel extends AbstractTableModel {
private Object[][] data;
private int column;
public MyTableModel(Object[][] data, int column) throws Exception {
try {
Object o=data[0][column-1];
}catch(IndexOutOfBoundsException e) {
throw new Exception("Nieprawidłowa ilość kolumn");
}catch(NullPointerException e) {
throw new Exception("Brak danych");
}
this.data=data;
this.column=column;
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return column;
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public boolean isCellEditable(int row, int col) {
return false;
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
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][column];
for(int i=0; i<data.length; i++)
for(int j=0; j<column; j++)
newdata[i][j]=data[i][j];
for(int i=0; i<column; i++)
newdata[data.length][i] = row[i];
this.data=newdata;
fireTableDataChanged();
}
public void delRow(int row) throws IndexOutOfBoundsException {
if(data.length == 0) return;
Object[][] newdata=new Object[data.length-1][column];
for(int i=0; i<row; i++)
for(int j=0; j<column; j++)
newdata[i][j]=data[i][j];
for(int i=row+1; i<data.length; i++)
for(int j=0; j<column; j++)
newdata[i-1][j]=data[i][j];
this.data=newdata;
fireTableDataChanged();
}
}
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JOptionPane;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import table.MyTableModel;
public class Main extends JFrame implements ActionListener {
private JTable table;
private JTextField rowdata;
private JButton add;
private JButton del;
public Main() {
this.setSize(400,300);
this.setResizable(false);
this.setTitle("JTable Example");
this.setLayout(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
initComponents();
addNPlaceComponents();
}catch(Exception e) {
System.out.println("Blad ladowania komponentów:\n"+e.getMessage());
System.exit(-1);
}
this.show();
}
private void initComponents() throws Exception {
Object[][] example_data = {
{"Jeden"},
{"Dwa"},
{"Trzy"}
};
table = new JTable(new MyTableModel(example_data,1));
rowdata = new JTextField("");
add=new JButton("Dodaj");
add.setActionCommand("add");
add.addActionListener(this);
del=new JButton("Usuń");
del.setActionCommand("del");
del.addActionListener(this);
}
private void addNPlaceComponents() {
JScrollPane sp=new JScrollPane(table);
JLabel rowdata_lab=new JLabel("Wiersz:");
this.setLayout(null);
this.add(sp);
this.add(rowdata);
this.add(add);
this.add(del);
this.add(rowdata_lab);
sp.setBounds(5,5,380,200);
rowdata_lab.setBounds(5,210,rowdata_lab.getPreferredSize().width,20);
rowdata.setBounds(10+rowdata_lab.getPreferredSize().width,210,100,20);
add.setBounds(5,235,add.getPreferredSize().width,25);
del.setBounds(10+add.getPreferredSize().width,235,del.getPreferredSize().width,25);
}
public void actionPerformed(ActionEvent e) {
//---dodaj
if(e.getActionCommand().equalsIgnoreCase("add")) {
if(rowdata.getText().equals("")) {
JOptionPane.showMessageDialog(this,"Wpisz jakąś daną w polu 'wiersz'","Brak danych",JOptionPane.WARNING_MESSAGE);
return;
}
try {
MyTableModel model=(MyTableModel)table.getModel();
Object[] row=new Object[1];
row[0]=rowdata.getText();
model.addRow(row);
rowdata.setText("");
}catch(Exception ex) {
JOptionPane.showMessageDialog(this,"Nie można dodać wiersza:\n"+ex.getMessage(),"Błąd",JOptionPane.ERROR_MESSAGE);
return;
}
}
//--usun
else if(e.getActionCommand().equalsIgnoreCase("del")) {
int selected = table.getSelectedRow();
if(selected == -1) return;
try {
MyTableModel model=(MyTableModel)table.getModel();
model.delRow(selected);
}catch(Exception ex) {
JOptionPane.showMessageDialog(this,"Nie można usunąć wiersza:\n"+ex.getMessage(),"Błąd",JOptionPane.ERROR_MESSAGE);
return;
}
}
}
public static void main(String[] args) {
new Main();
}
}
jacobus2k no twoj kod działa, ale za zadne skarby niemoge zaimplementowac go do swojej tabeli. I czy nie ma jakiegos "normalnego" sposobu na aktualizacje danych w tabeli? Za termin normalny rozumiem kilkanascie lini kodu, a nie 2 klasy i 200 lini kodu, zeby osiągnąć "odświerzanie" zawartosci tabeli. Dla mnie to trche nielogiczne.
Dałem ten przykład, by pokazać ci jak to działa. Z Twojego kodu niewiele mogłem zrozumieć.
Więc zacznijmy od podstaw.
JTable można utworzyć na wiele sposobów (patrz API). Jednym z nich jest konstruktor:
JTable(TableModel dm)
TableModel jest interfejsem, czyli najprościej mówiąc rzutowaniem pewnej klasy, na zestaw metod.
W tym przypadku klasy AbstractTableModel.
AbstactTableModel jak wiesz jest klasą abstrakcyjną, czyli wymaga implementacji. Więc tworzysz sobie TabelaGraczy.
Wewnątrz znajduje się macierz z danymi, u Ciebie było by to:
private Object[][] dane
Te dane, wewnątrz klasy TabelaGraczy, możesz poddawać zmianom. Np.: dodać wiersz. Dodanie wiersza, równa się zwiększeniem długości tablicy o 1, i wypełnieniu , analogicznie usunięcie wiersza zmniejszeniu długości tablicy o 1, i odpowiednim przegrupowaniu danych.
Następnie musisz odświeżyć dane, masz do wyboru szereg metod
patrz API: http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/table/AbstractTableModel.html
np:
fireTableDataChanged()
//Notifies all listeners that all cell values in the table's rows may have changed.
fireTableRowsDeleted(int firstRow, int lastRow)
//Notifies all listeners that rows in the range [firstRow, lastRow], inclusive, have been deleted.
fireTableRowsInserted(int firstRow, int lastRow)
//Notifies all listeners that rows in the range [firstRow, lastRow], inclusive, have been inserted.
fireTableRowsUpdated(int firstRow, int lastRow)
//Notifies all listeners that rows in the range [firstRow, lastRow], inclusive, have been updated.
W swoim przykładzie dałem po prostu odświeżenie wszystkich danych;)
Teraz przerobiłem twój kod:
import javax.swing.table.AbstractTableModel;
public class TabelaGraczy extends AbstractTableModel {
private final static int COLUMN_LENGTH = 6;
private Object[][] dane;
private Object[] pola;
public TabelaGraczy() {
this.pola = new String[COLUMN_LENGTH]; //nie wiem po co to jest
//teraz niebardzo rozumiem jakie maja byc poczatkowe wartosci danych
//wiec dam tak:
this.dane = new Object[0][0];
}
public int getRowCount() { //zwraca liczbe wierszy macierzy danych wiec wystarczy;
return dane.length;
}
public int getColumnCount() { //zwaraca ilosc kolumn, a ta jest stała i wynosi 6
return COLUMN_LENGTH;
}
public Object getValueAt(int rowIndex, int columnIndex) { //zwraca obiekt macierzy o wskazanych indeksach
return dane[rowIndex][columnIndex];
}
public void dodajWiersz(Object[] row) throws Exception {
/* Chcesz dodac nowy wiersz, czyli tablice, ktorej dlugosc
* rowna jest dlugosci kolumn twojej macierzy danych */
//sprawdzamy czy ilosc danych wejsciowych *row rowna jest ilosci kolumn macierzy:
//jezeli nie wyrzucamy wyjatek
if(row.length!=COLUMN_LENGTH) throw new Exception("Niewłaściwe dane");
/*Teraz, najprostrzym sposobem, na dodanie wiersza do macierzy jest
*zwiekszenie jej dlugosci o 1, w tym celu, tworzymy nowa, tymczasowa
*macierz *newdata */
Object[][] newdata=new Object[dane.length+1][COLUMN_LENGTH];
/* Teraz tymczasowa macierz, trzeba wypelnic starymi danymi */
for(int i=0; i<dane.length; i++)
for(int j=0; j<COLUMN_LENGTH; j++)
newdata[i][j]=dane[i][j];
//zostaje nam pusty wiersz ktory zapełniamy danymi wejsciowymi *row
for(int i=0; i<COLUMN_LENGTH; i++)
/*data.length odpowiada poprzedniej dlugosci macierzy,
*czyli obecnie dlugosci ostatniego wolnego wiersz nowej macierzy */
newdata[dane.length][i] = row[i];
this.dane=newdata;//teraz zapisujemy nowa macierz w miejsce starej
fireTableRowsInserted(dane.length-1, dane.length-1);//i odswiezamy tabele, dodaliśmy tylko jeden wierzs
}
/*Jezeli nie ma takiego wiersza poprostu wyrzuci IndexOutOfBoundsException
*nie musiałem nawet tego wymuszać, ale chciałem to podkreślić */
public void usunWiersz(int row) throws IndexOutOfBoundsException {
/* Usuniencie wiersza jest analogicznie,
* Najpierw wybieramy który wiersz chcemy usunąc *row */
if(dane.length == 0) return; //przy zerowej ilosci wierszy nic nie mozemy usunac
Object[][] newdata=new Object[dane.length-1][COLUMN_LENGTH]; //nowa macierz jest krótrza o 1
/* Teraz wypełniamy nowa macierz starymi danymi, do wiersza
* który chcemy usunąć */
for(int i=0; i<row; i++)
for(int j=0; j<COLUMN_LENGTH; j++)
newdata[i][j]=dane[i][j];
/* Kontynuujemy wypełnianie, ale od wiersza o jeden większego
* niż ten który chcemy usunąć */
for(int i=row+1; i<dane.length; i++)
for(int j=0; j<COLUMN_LENGTH; j++)
newdata[i-1][j]=dane[i][j]; //uwaga indeks nowej macierzy nie może przeskoczyć o 1 dlatego i-1
this.dane=newdata;//teraz zapisujemy nowa macierz w miejsce starej
fireTableRowsDeleted(row, row); //odswiezamy tabele, usunelismy tylko jeden wiersz
}
}
Teraz by utworzyć swoją tabele wystarczy, że zrobisz tak:
JTable tabela = new JTable(new TabelaGraczy());
Jeżeli będziesz chciał otrzymać dostęp do klasy TabelaGraczy, by np: dodać wiersz wystarczy, że zrobisz tak:
TabelaGraczy gracze = (TabelaGraczy)tabela.getModel();
Object[] wiersz = {"Jeden","Dwa","Trzy","Cztery","Pięć","Sześć"};
//try-catch bo wymuszałem obsługe wyjątku
try {
gracze.dodajWiersz(wiersz);
}catch(Exception e) {
System.out.println("Błąd "+e.getMessage());
}
Analogicznie usówanie"
TabelaGraczy gracze = (TabelaGraczy)tabela.getModel();
try {
gracze.usunWiersz(1);
}catch(IndexOutOfBoundsException e) {
System.out.println("Błąd "+e.getMessage());
}
Jeżeli chodzi o pole:
Object[] nazwy
w twoim oryginalnym kodzie, zapewne chodziło ci o nagłówki kolumn. Zauważ, że nie ma konstruktora opierającego się o TableModel i umożliwiającego nadanie
nazw kolumnom. Gdyż nie wiadomo jakie dane będą wchodzić w skład tabeli.
Możesz wtedy rozszerzyć klase JTable, tj utworzyć klase dziedzicząćą po JTable np:
public class MojaTabela extends JTable {
}
Wówczas, jeżeli chcesz dodać owe nagłówki, wystarczy, że przeciążysz metode
String getColumnName(int column)
np:
public String getColumnName(int column) {
if(column == 0) return "Jeden";
else if(columnt == 1) return "Dwa";
//itd
else return null;
}
Możesz też wyłączyć nagłówki przeciążając metode
JTableHeader getTableHeader()
W sposób następujący:
public JTableHeader getTableHeader() {
return null;
}
Witam. Idąc tropem ostatniego posta dziedziczę po klasie JTable i przeciążyłem metodę getName ale nazwy kolumn nie są widoczne. Nagłówki kolumn znajdują się w Arrayliscie w modelu mojej tabeli i są zwracane przez metodę getHeader. Metoda getName w ogóle nie jest wywoływana przy tworzeniu tabeli. Z góry dzieki za pomoc i pozdrawiam.
private class MyTable extends JTable
{
public MyTable (TableModel model)
{
super(model);
}
public String getColumnName(int column)
{
System.out.println(((MyTableModel)getModel()).getHeader(column));
return ((MyTableModel)getModel()).getHeader(column);
}
}
jacobus2k albo ktos inny ktos sie zna na rzeczy:
Dziala mi ( i wlasnie jej teraz uzzywam ) tabela zmodyfikowana przez jacobus2k'a ale mam pytanania:
1)W jednej komorce musze trzymac bardzo dlugi text, mozna zrobic tak zeby kazda komorka posiadala jeszcze jakis komponent ( moze jakis inny pomysl)? ( w tym momencie wyswietla mi tylko pierwsza linijke z calego textu);/
2) Jak zmienic szerokosc kolumn ?
Dzieki za kazde uwagi!
Dodalem Eveb: Mouse pressed i kod:
private void paragraphsTableMouseClicked(java.awt.event.MouseEvent evt) {
int row = paragraphsTable.rowAtPoint( evt.getPoint() );
int column = paragraphsTable.columnAtPoint( evt.getPoint() );
if ( row != -1 && column != -1 )
{
//paragraphsTable.getCellEditor().getTableCellEditorComponent(paragraphsTable, column, isSelected, row, column);
//System.out.println( paragraphsTable.getCellEditor().toString() );
System.out.println(paragraphsTable.getValueAt(row, column).toString() );
}
}
i dziala, ale oczwyscie nadal bede wdzieczny za inne rozwiaznia:)
2)
Wciaz prosze o pomoc
Ad. 2
Java ma doskonałą dokumentację. http://java.sun.com/javase/6/docs/api/. Po prostu tam zajrzyj, wyszukaj właściwą klasę (w typ przypadku TableColumn) i wszystkiego się dowiesz.
pozdrawiam
a ja mam taki problem:
class MyTableModel extends AbstractTableModel {
private String[] columnNames = { "id", "nazwa", "typ", "parametr1", "data poczatek", "data koniec"};
private Object[][] data = rowData;
public void up(Object[][] rowData)
{
this.data=rowData;
this.fireTableDataChanged();
}
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];
}
}
TableModel model = new MyTableModel();
JTable jtable1 = new JTable(model);
nie mogę się odwołać do funkcji up(rowData[][]) a do pozostałych (nadpisanych) mogę, kompilator w ogóle tej funkcji nie widzi :/ nie działa ani model.up(dane) ani jtable1.getModel().up
byc moze utworzyles obiekt na zasadzie:
AbstractTableModel model = new MyTableModel();
Wtedy dostepne dla Ciebie beda tylko metody klasy AbstractTableModel
Jeśli to jest przyczyna, zmien na:
MyTableModel model = new MyTableModel();
lub przed skorzystaniem z obiektu dokonaj rzutowania na odpowiedni typ