Modyfikacja JTable

0

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 ??

0

Korzystasz z AbstractTableModel ?? Powinieneś wykorzystać sprzężenie zwrotne jak to się tak ładnie nazywa :P Użyj fireTableCellUpdated(int row, int col)

0

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ż).

0

fireTableDataChanged()

0

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;/.

0

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();
	}	
}
0

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.

1

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;
}
0

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); 
        } 
    } 
0

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

0

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

0

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

0

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

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