» »

[Java] Urejanje baze z JTable

[Java] Urejanje baze z JTable

vonNeumann ::

Pozdravljeni,

V moji aplikaciji želim urejat (update, insert into, delete,..) bazo preko JTable-a.
Do sedaj sem napisal kos kode, ki vsebino tabele v bazi prenese v JTable (sem napisal svoj class, ki deduje AbstractTableModel). Ko JTabel spremenim (spremenim vrednost v celici, zbrišem vrstico, dodam vrstico) bi se morala, z gumbom, posodobit tudi baza. Tuki imam precej pomešane pojme. Kako tableModelListener (tableChanged) uporabit, kako uporabit FireTable metode (FireTableChanged, FireTableCellUpdated,..) in pa kako naredit, da so vse celice editable.
Bi prosil nekoga če mi obrazloži to filozofijo :)

Hvala

vonNeumann ::

Kar se tiče dela z bazo sem napisal sledeče, ki izpiše celotno (izbrano) tabelo v bazi v JTable. V
V JComboBox-u izberem ime tabele (z poizvedbo dobim imena tabel- ni v tem odseku kode) nato JTable napolnimo.

private void jComboBox_imenaTabelItemStateChanged(java.awt.event.ItemEvent evt) {                                                      
        System.out.println("Sem v comboBox-u");
        Statement statement;
        String query;
        ResultSet rs;
        int stolpec;
        tabela = jTable_PodBaza;
        ResultSetMetaData rsm;
        

        try {

            Object obj = jComboBox_imenaTabel.getSelectedItem();
            String izbrano = obj.toString();
           
            qtm = new QueryTableModel();
            tabela.setModel(qtm);
            qtm.setHostURL("jdbc:mysql://localhost:3306/chat");
            qtm.setQuery("select * from " + izbrano);     
       
        } catch (Exception e) {
            e.printStackTrace();
        }
    }     


QueryTableModel je class, ki deduje AbstractTableModel. Tukej se izvede poizvedba in napolni tabelo:
Sem malenkost spremenil že napisan source :)

import java.awt.*;
import java.sql.*;
import java.util.*;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.table.*;

class QueryTableModel extends AbstractTableModel {
  Vector cache; // will hold String[] objects . . .
  Vector cache2;

  int colCount;

  String[] headers;

  Connection db;

  Statement statement;

  String currentURL;

    
  public QueryTableModel() {
    cache = new Vector();
    cache2 = new  Vector();
    new Driver() {

            @Override
            public Connection connect(String url, Properties info) throws SQLException {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public boolean acceptsURL(String url) throws SQLException {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public int getMajorVersion() {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public int getMinorVersion() {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public boolean jdbcCompliant() {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public Logger getParentLogger() throws SQLFeatureNotSupportedException {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
  }
 public void addEmptyRow () {
String[] rowData = new String[colCount] ;
for(int i=0;i< colCount;i++)
rowData[i] = "" ;
cache.addElement(rowData);
System.out.println("vector:" +cache.size());
fireTableChanged(null); 
 }
 public void addEmptyRow2 (String upIme,String ip, int port) {
     try {
 Vector ram = new Vector();
String[] rowData2 = {upIme,ip,Integer.toString(port)} ;
ram.add(rowData2);
cache2.addElement(rowData2);
fireTableChanged(null);

System.out.println("velikost vector2: "+cache2.size());
System.out.println("vector2: "+cache2.get(0).toString());
     }
     catch (Exception e){e.printStackTrace();}
 
 }
 public boolean isCellEditable(int row, int col)  
        { return true; }  

  public String getColumnName(int i) {
    return headers[i];
  }

  public int getColumnCount() {
    return colCount;
  }

  public int getRowCount() {
    return cache.size();
  }

  public Object getValueAt(int row, int col) {
    return ((String[]) cache.elementAt(row))[col];
  }

  public void setHostURL(String url) {
    if (url.equals(currentURL)) {
      // same database, we can leave the current connection open
      return;
    }
    // Oops . . . new connection required
    closeDB();
    initDB(url);
    currentURL = url;
  }

  // All the real work happens here; in a real application,
  // we'd probably perform the query in a separate thread.
  public void setQuery(String q) {
    cache = new Vector();
    try {
     // izvede se poizvedba in iz nje (preko metaData) dobimo stevilo stolpcev. 
      ResultSet rs = statement.executeQuery(q);
      ResultSetMetaData meta = rs.getMetaData();
      colCount = meta.getColumnCount();

      // Now we must rebuild the headers array with the new column names
      headers = new String[colCount];
      for (int h = 1; h <= colCount; h++) {
        headers[h - 1] = meta.getColumnName(h);
      }

      // and file the cache with the records from our query. This would
      // not be
      // practical if we were expecting a few million records in response
      // to our
      // query, but we aren't, so we can do this.
      while (rs.next()) {
        String[] record = new String[colCount];
        for (int i = 0; i < colCount; i++) {
          record[i] = rs.getString(i + 1);
        }
        cache.addElement(record);
      }
      fireTableChanged(null); // notify everyone that we have a new table.
    } catch (Exception e) {
      cache = new Vector(); // blank it out and keep going.
      e.printStackTrace();
    }
  }

  public void initDB(String url) {
    try {
      db = DriverManager.getConnection(url,"root","");
      statement = db.createStatement();
    } catch (Exception e) {
      System.out.println("Could not initialize the database.");
      e.printStackTrace();
    }
  }

  public void closeDB() {
    try {
      if (statement != null) {
        statement.close();
      }
      if (db != null) {
        db.close();
      }
    } catch (Exception e) {
      System.out.println("Could not close the current connection.");
      e.printStackTrace();
    }
  }
}

Sedaj me zanima kako "poslušat" JTable. Ob morebitni spremembi(spreminanje vrednosti v celici, dodajanje vrstice, izbris vrstice)bi posodobil bazo oz. tabelo (ko uporabnik pritisne na gumb). Sicer sem že precej poizvedoval po googlu ampak nisem dobil potrebnih informacij. Pišem pa chat aplikacijo (server in client) - končujem . Zelo bi bil hvaležen vsakršne pomoči. Hvala

Zgodovina sprememb…

vonNeumann ::

Ne morem verjet, da nobeden ne zna pomagat pri tem primeru ?!
Sej vendar ni tako težak... :|

win64 ::

JTable kontrola je ena izmed kompleksnejših. Za prikaz polj uporablja cell render(mogoče tudi painter) za urejanje polja pa cell editor.
Cell editor se registrira na JTable za posamezen podatkovni tip in ob urejanju celice JTable potem kliče CellEditor za pridobitev kontrole za urejanje. Po končanem urejanju kliče CellEditor za obdelavo vnesešene vrednosti.

Več pa si lahko na internetu najdeš:
http://docs.oracle.com/javase/1.4.2/doc...
http://www.exampledepot.com/egs/javax.s...

vonNeumann ::

Hvala za odgovor win64. Sedaj vem kako bi uredil težavo glede osveževanja JTable-a. Gremo tipkat :)
Kakšen listener oz. event(za JTable) uporabim če želim, da se blok kode (dobim ime stolpca(entiteta), st. vrstice(id), da se izvede update stavek na bazi ter osveži JTable) izvede ko uporabnik spremeni vrednost v celici ?

win64 ::

Shranjevanje boš moral opraviti v celoti v celleditorju.
v metodi getTableCellEditorComponent() si shrani številko vrstice in stolpca in kar potrebuješ, to potem uporabi v getCellEditorValue(). Ime stolpca dobiš preko TableModel-a z metodo getColumnName().

http://docs.oracle.com/javase/1.4.2/doc...

Osveževanje je zelo problematično.
Osvežiš načeloma s setModel(), vendar ima ta metoda en pogoj, ki ne osveži tabele, če ima TableModel enako referenco, tako ne moreš klicati table.setModel(getModel()).
Da je zadeva hujša ne dovoli null vrednosti, zato ne moreš napisati:
table.setModel(null); table.setModel(prejsniModel);

Tako, da moraš razširiti JTable in prekriti to metodo(pobrano iz izvorne kode jave):
JTable table = new JTable(){
 @Override public void setModel(TableModel dataModel) {
        if (dataModel == null) {
            throw new IllegalArgumentException("Cannot set a null TableModel");
        }
       // if (this.dataModel != dataModel) {
            TableModel old = this.dataModel;
            if (old != null) {
                old.removeTableModelListener(this);
            }
            this.dataModel = dataModel;
            dataModel.addTableModelListener(this);

            tableChanged(new TableModelEvent(dataModel, TableModelEvent.HEADER_ROW));

            firePropertyChange("model", old, dataModel);

            if (getAutoCreateRowSorter()) {
                setRowSorter(new TableRowSorter<TableModel>(dataModel));
            }
      //  }
    }
};

vonNeumann ::

živjo,
S pomočjo MyTableCellEditor-ja uspešno posodabljam bazo (uspešno pridobivam vrednost iz celice).
Izgleda pa takole:
int col = tabela.getSelectedColumn();
int row = tabela.getSelectedRow();
System.out.println("colIndex: "+col+" rowIndex: "+row);
Object value = tabela.getValueAt(row, col);

 MyTableCellEditor mtce  = new MyTableCellEditor();
 mtce.getTableCellEditorComponent(tabela, value, true, row, col);
 Object cell = mtce.getCellEditorValue();
 tabela.setValueAt(cell.toString(), row, col);
 System.out.println(cell.toString());


   Statement statement;
   String query;
   ResultSet rs =null;
  Connection conection;
                 
 try{                            
                      
                      Class.forName("com.mysql.jdbc.Driver").newInstance();
                          conection = DriverManager.getConnection("jdbc:mysql://localhost:3306/chat", "root", "");

                          statement = conection.createStatement();
                          query = "update "+izbrano+" set "+qtm.getColumnName(col)+" = '"+cell.toString()+"' where  "+qtm.getColumnName(0)+" = "+qtm.getValueAt(row, 0);
                        System.out.println("update uporabnik set "+qtm.getColumnName(col)+" = '"+cell.toString()+"' where  "+qtm.getColumnName(0)+" = "+qtm.getValueAt(row, 0));
                        statement.executeUpdate(query);
                        
 }                       
 catch (Exception e){e.printStackTrace();}
         

Kakšen komentar?

Imam pa težave s osveževanjem JTable-a. Kadar spremenim vrednost celice v JTable in pritisnem enter se vrdnost povrne. Tudi če ne pritinem enter in pritisnem gumb "posodobi bazo" mi pobere prejšnjo vrednost. Ni mi čisto jasno kako lahko z setModel(model); osvežiš JTable če model ne dobi nove vrednosti celice.
Lahko malo bolj podrobno pojasniš ? :D

Zgodovina sprememb…

win64 ::

Ja, ko posodobiš vrednosti v podatkih, moraš posodobiti tudi JTable.
To pa lahko narediš z setModel metodo.

vonNeumann ::

Živjo

Glede na to, da mi zmanskuje časa in to urejanje ne uspem spravit v delujoče stanje, bom to urejal z JTextField-i po
vzoru oracle obrazcev za ažuriranje podatkov.
Imam pa vprašanj, ki je off topic (da ne odpiram nove teme).
Če imam več niti (vse imajo DataInputStream)in iz strežniške aplikacije preko DataOutPutStream-a pošljem nek String. Kako naj naredim, da določena nit dobi ta String. Sedaj vse niti dobijo ta String. Niti se ustvarjajo spotoma (za vsak dvogovor). Naloga teh niti je sprejemanje sporočil.

Zgodovina sprememb…



Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[JAVA] HTTPS client

Oddelek: Programiranje
173058 (1788) peterv6i
»

Java skeniranje map in podmap

Oddelek: Programiranje
61072 (961) nightrage
»

android črta

Oddelek: Programiranje
412272 (1543) g333kk
»

[android] vstavljanje slike

Oddelek: Programiranje
71145 (1042) messi
»

JAVA-NALOGA- Pomoc NUJA!!!!!

Oddelek: Programiranje
61593 (1516) bijonda

Več podobnih tem