URL: https://www.overclockers.at/coding-stuff/java_jtable_aktualisieren_update_neues_prob_219571/page_1 - zur Vollversion wechseln!
Hey, ich hab nen Problem mit Java und google konnte mir da nicht helfen.
Ich habe eine Tabelle, welche bei der initialisierung ihre Daten aus einem 2-dimdensionalen Array erhält, klappt alles ohne Probleme.
Hier der Erzeugungsprozess, wobei manager.gettable() eben das 2-dimensionale Array zurückgibt.
Code:Manager manager = new Manager(); private String[] columnNames = {"Filme", "Rating", "Genre"}; dtm = new DefaultTableModel(manager.gettable(), columnNames); table = new JTable(dtm); getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
Code:dtm.fireTableDataChanged() table.repaint();
setDataVector mit manager und columnNames aufrufen, nachdem sortiert wurde?
Ich kann jetzt auch total falsch liegen aber ich würde mal sagen, dass deiner Table komplett egal ist was du mit deinem Array im Manager machst.
Du übergibst ja lediglich das Array an das DefaultTableModel. Was du dann im Manager machst ist nur im Manager.
@ nico: Die gettable()-Methode gibt mir ein String[][] zurück (habe ich oben wohl vergessen zu erwähnen).
Wenn ich es mit setDataVector machen würde, müsste ich extra Vektoren einführen, wenn ich grad nicht aufm Schlauch steh (erste mal, dass ich mit tables arbeite, sorry )?
Gibt es keine andere Möglichkeit, dass er das String[][] einfach komplett neu einliest bzw erzeugt?
@ array: stimmt, ist aber auch so gewollt. Nach dem sortieren, soll eine refresh-methode aufgerufen werden, welche eben die Tabelle neu zeichnet.
ich möchte es nicht über actionevents auf der tabelle realisieren (wenns denn geht).
die klassen sind leider bissl groß und unübersichtlich (und voller baustellen ), sonst würd ich die hier posten.
edit: hier noch mal mit mehr code
actionevent, wenn man liste sortiert:
Code:if (e.getSource() == sortMoviesbyName) { manager.sortlistbyname(); refresh(); }
das Problem ist aber, dass die "refresh" bzw repaint methode vom table nicht hergeht und mal beim Manager fragt ob sich etwas geändert hat.
Schon mal daran gedacht es mit einem Model zu lösen?
Was heißt dran gedacht, ich kenn mich mit Tabellen null aus und arbeite mich grad ein. Habe deswegen halt keine Ahnung, wie man sowas am geschicktesten macht.
Ich habe ja ein DefaultTableModel, aber keinen Plan, wie ich das nun mache.
ok ..
ungefähr so schaut ein Model aus:
Code:public class MyTableModel extends AbstractTableModel { private String[] head = {"Name", "Größe", "Pfad", "Datum", "Lesen", "Schreiben", private Manager manager; public MyTableModel(Manager manager){ this.manager = manager; } public int getColumnCount() { return head.length; } public int getRowCount() { return manager.gettable().length(); } public String getColumnName(int col) { return head[col]; } public Object getValueAt(int row, int col) { return manager.gettable()[row][col]; } public void sort(){ manager.sort(); fireTableDataChanged(); } }
Zitat von NicosetDataVector mit manager und columnNames aufrufen, nachdem sortiert wurde?
Code:dtm.setRowCount(manager.getlistlength()); dtm.fireTableStructureChanged(); dtm.setDataVector(manager.gettable(), columnNames); dtm.fireTableDataChanged();
Update!
Leider hab ich wieder ein Problem mit den Tabellen :/
Da es wohl etwas komplexer ist, erkläre ich hier meine Gedanken und unten folgen die kompletten Klassen, welche relevant sind, damit man es besser nachvollziehen kann.
Ich bin dabei, nen MovieManager zu basteln. Ich hab noch nicht so viel Übung, was "größere" Projekte in Java angeht, deswegen tue ich mich wohl bei einigen Sachen relativ schwer.
Zu den Klassen:
Die Klasse Manager ist praktisch die Controllklasse für alles, was im Hintergrund abgeht, hier eigentlich nur zwei Arrays.
Da ich nicht immer die Arrays hin und her schieben möchte, sind die static und falls die GUI-Klassen was ändern müssen, erzeugen sie einfach ein neues Manager-Objekt und bearbeiten die Arrays mit set- und get-Methoden(ist das sinnvoll?).
Die Klasse Mainwindow erzeugt das Frame, in welchem sich alles abspielt.
Damit nicht alles unübersichtlich wird und man es in Zukunft besser erweitern kann, habe ich die GUI-Elemente in andere Klassen ausgelagert (ist das sinnvoll? Oder wie macht man es am besten?).
Es gibt momentan 3 relevante GUI-Elemente:
- das Menü oben
- die Toolbar
- die Tabelle
In der Klasse Mainwindow passiert sonst eigentlich nichts. Die ActionEvents laufen jeweils in den ausgegliederten Klassen ab(geht bestimmt auch eleganter, für Input wäre ich dankbar!).
Vorher hat alles funktioniert, aber ich habe die ganze Zeit Objekte und Arrays hin und her geschoben (als Parameter für Konstruktoren), bis es irgendwann einfach total unübersichtlich und einfach "unsauber" war.
Deswegen will ich es nun anders lösen.
erst einmal die Klassen.
Mainwindow:
Code:package main; import java.awt.BorderLayout; import java.awt.GridLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import main.ui.Menu; import main.ui.Table; import main.ui.Toolbar; public class Mainwindow extends JFrame { private static final long serialVersionUID = 1L; private JPanel south = new JPanel(); private JLabel anzahlderFilme; /** * Konstruktor */ public Mainwindow (Manager manager) { super("Movie Manager"); setResizable(true); setLayout(new BorderLayout()); this.setDefaultCloseOperation(EXIT_ON_CLOSE); // Menü setJMenuBar(new Menu()); // Toolbar(north) add(new Toolbar(), BorderLayout.NORTH); // Tabelle (center) add(new JScrollPane(new Table ()), BorderLayout.CENTER); // Anzeige (south) -> WIRD NOCH NICHT GEUPDATED! <- south.setLayout(new GridLayout (1, 1)); anzahlderFilme = new JLabel ("Anzahl der Filme: " + manager.getlistlength()); south.add(anzahlderFilme); add(south, BorderLayout.SOUTH); // packen und sichbtbar machen pack(); setVisible(true); } /** * Erzeugt das Fenster * @param args */ public static void main(String[] args) { Manager manager = new Manager(); manager.importlist(); Mainwindow m = new Mainwindow(manager); } }
Code:package main.ui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import main.Manager; public class Menu extends JMenuBar implements ActionListener { private static final long serialVersionUID = 1L; private JMenuItem add, del, sortbyname, sortbyimdbrating, sortbymmrating, sortbygenre, ueber, changename, changeimdbrating, changemmrating, changegenre; /** * Konstruktor */ public Menu () { // Menü "Datei" JMenu datei = new JMenu("Datei"); add = new JMenuItem ("Film hinzufügen"); add.addActionListener(this); datei.add(add); del = new JMenuItem ("Film löschen"); del.addActionListener(this); datei.add(del); this.add(datei); // Menü "Bearbeiten" JMenu bearbeiten = new JMenu ("Bearbeiten"); changename = new JMenuItem ("Filmnamen ändern"); changename.addActionListener(this); bearbeiten.add(changename); changeimdbrating = new JMenuItem ("imdb.com-Bewertung ändern"); changeimdbrating.addActionListener(this); bearbeiten.add(changeimdbrating); changemmrating = new JMenuItem ("moviemaze.de-Bewertung ändern"); changemmrating.addActionListener(this); bearbeiten.add(changemmrating); changegenre = new JMenuItem ("Filmgenre ändern"); changegenre.addActionListener(this); bearbeiten.add(changegenre); this.add(bearbeiten); // Menü "Sortieren" JMenu sortieren = new JMenu ("Sortieren"); sortbyname = new JMenuItem ("Nach Namen sortieren"); sortbyname.addActionListener(this); sortieren.add(sortbyname); sortbyimdbrating = new JMenuItem ("Nach imdb.com-Bewertung sortieren"); sortbyimdbrating.addActionListener(this); sortieren.add(sortbyimdbrating); sortbymmrating = new JMenuItem ("Nach moviemaze.de-Bewertung sortieren"); sortbymmrating.addActionListener(this); sortieren.add(sortbymmrating); sortbygenre = new JMenuItem ("Nach Genre sortieren"); sortbygenre.addActionListener(this); sortieren.add(sortbygenre); this.add(sortieren); // Menü "Hilfe" JMenu hilfe = new JMenu ("Hilfe"); ueber = new JMenuItem ("Über MovieManager"); ueber.addActionListener(this); hilfe.add(ueber); this.add(hilfe); } /** * ActionEvents */ public void actionPerformed(ActionEvent e) { if (e.getSource() == add) { String name = JOptionPane.showInputDialog("Filmname"); if (name.length() == 0) { JOptionPane.showMessageDialog(null, "Dateinamen angeben."); } else { Manager manager = new Manager(); manager.add(name); Table table = new Table(); table.refresh(); } } if (e.getSource() == del) { } if (e.getSource() == sortbyname) { Manager manager = new Manager(); manager.sortlistbyname(); } if (e.getSource() == sortbyimdbrating) { Manager manager = new Manager(); manager.sortlistbyimdbrating(); } if (e.getSource() == sortbymmrating) { Manager manager = new Manager(); manager.sortlistbymmrating(); } if (e.getSource() == sortbygenre) { Manager manager = new Manager(); manager.sortlistbygenre(); } } }
Code:package main.ui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JOptionPane; import javax.swing.JToolBar; import main.Manager; public class Toolbar extends JToolBar implements ActionListener { private static final long serialVersionUID = 1L; private JButton addMovie; private JButton deleteMovie; private JButton sortMoviesbyName; private JButton sortMoviesbyGenre; private JButton sortMoviesbyRating; /** * Konstruktor */ public Toolbar () { addMovie = new JButton ("add"); addMovie.addActionListener(this); deleteMovie = new JButton ("delete"); deleteMovie.addActionListener(this); sortMoviesbyName = new JButton ("sort by Name"); sortMoviesbyName.addActionListener(this); sortMoviesbyRating = new JButton ("sort by Rating"); sortMoviesbyRating.addActionListener(this); sortMoviesbyGenre = new JButton ("sort by Genre"); sortMoviesbyGenre.addActionListener(this); this.add(addMovie); this.add(deleteMovie); this.add(sortMoviesbyName); this.add(sortMoviesbyRating); this.add(sortMoviesbyGenre); } /** * ActionEvents */ public void actionPerformed(ActionEvent e) { if (e.getSource() == addMovie) { String name = JOptionPane.showInputDialog("Filmname"); if (name.length() == 0) { JOptionPane.showMessageDialog(null, "Dateinamen angeben."); } else { Manager manager = new Manager(); manager.add(name); Table table = new Table(); table.refresh(); } } if (e.getSource() == deleteMovie) { } if (e.getSource() == sortMoviesbyName) { } if (e.getSource() == sortMoviesbyGenre) { } if (e.getSource() == sortMoviesbyRating) { } } }
Code:package main.ui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JTable; import javax.swing.table.DefaultTableModel; import main.Manager; public class Table extends JTable implements ActionListener { private static final long serialVersionUID = 1L; private static Object[] columnNames = {"Filme", "imdb.com-Rating", "moviemaze.de-Rating", "Genre"}; private static DefaultTableModel dtm; private static Manager manager; /** * Konstruktor * @param manager */ public Table () { manager = new Manager(); dtm = new DefaultTableModel(manager.gettable(), columnNames); this.setModel(dtm); } /** * ActionEvent */ public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub } /** * Zeichnet die Tabelle neu */ public void refresh () { manager.convert(); dtm.setRowCount(manager.getlistlength()); dtm.fireTableStructureChanged(); dtm.setDataVector(manager.gettable(), columnNames); dtm.fireTableDataChanged(); } }
Code:package main; import main.system.Movie; import main.system.Port; import main.system.Sort; import main.system.Search; public class Manager { static private Movie[] list = new Movie[0]; static private Object[][] table; /** * Konstruktor: erstellt beim Aufruf eine neue Movieliste (array) */ public Manager () { convert(); } /** * Gibt das Movieobjekt an der Stelle "index" im Array zurück * @param index int: index-Zahl * @return Movieobjekt */ public Movie getmovie (int index) { return list[index]; } /** * Gibt die Anzahl der Filme in der Movieliste zurück * @return int: Anzahl der Filme in der Movieliste */ public int getlistlength () { return list.length; } /** * Gibt die Tabelle "table" zurück * @return String[][]:zweidimensionales Array der Movieliste */ public Object[][] gettable () { return table; } /** * Konvertiert die Liste in ein zweidimensionales Array (für JTable) */ public void convert() { table = new String[list.length][4]; for (int i = 0; i < list.length; i++) { table[i][0] = getmovie(i).getname(); table[i][1] = getmovie(i).getimdbrating(); table[i][2] = getmovie(i).getmmrating(); table[i][3] = getmovie(i).getgenre(); } } /** * Fügt einen neuen Film in die Movieliste hinzu * @param name String: Name des Films, welcher hinzugefügt werden soll */ public void add (String name) { Movie[] temp = new Movie[list.length + 1]; // alte Liste kopieren for (int i = 0; i < list.length; i++) { temp[i] = list[i]; } // neues Element hinzufügen temp[temp.length-1] = new Movie(name); // zu liste referenzieren list = temp; } /** * Löscht einen Film aus der Movieliste * @param index int: Index-Zahl des Films im Array, welcher gelöscht * werden soll */ public void delete (int index) { Movie[] temp = new Movie[list.length - 1]; // alte Liste bis zu "index" kopieren for (int i = 0; i < index; i++) { temp[i] = list[i]; } // kopiere alles, was nach dem zu löschendem Element kommt, weiter in // die Liste for (int i = index; i < temp.length; i++) { temp[i] = list[i+1]; } // zu liste referenzieren list = temp; } /** * Sortiert die Liste alphabetisch nach den Namen der Filme */ public void sortlistbyname () { Sort sort = new Sort(); list = sort.sortlistbyname(list); } /** * Sortiert die Liste alphabetisch nach dem Genre der Filme */ public void sortlistbygenre () { Sort sort = new Sort(); list = sort.sortlistbygenre(list); } /** * Sortiert die Liste nach dem imdb.com-Rating der Filme */ public void sortlistbyimdbrating () { Sort sort = new Sort(); list = sort.sortlistbyimdbrating(list); } /** * Sortiert die Liste nach dem moviemazde.de-Rating der Filme */ public void sortlistbymmrating () { Sort sort = new Sort(); list = sort.sortlistbymmrating(list); } /** * Sucht in der Movieliste einen Film (vollständiger Name notwendig) * @param name String: Name des Films, welcher gesucht werden soll * @return int: Index-Zahl im Array des Films. -1, falls Film nicht gefunden */ public int searchbyfullname (String name) { Search search = new Search(); return search.searchbyfullname(list, name); } /** * Exportiert die Movieliste in eine Datei (vorher wird sie nach Namen * sortiert) */ public void exportlist () { sortlistbyname(); Port export = new Port(); export.exportlist(list); } /** * Importiert die Movieliste aus einer Datei */ public void importlist () { Port port = new Port(); list = port.importlist(); } }
wird denn immer refreshed, also bei jedem event?
momentan habe ich nur das Event "Film hinzufügen" vollständig implementiert und dort wird am schluss die reflesh()-Methode in Table aufgerufen. Also ich gehe schon davon aus, dass sie aufgerufen werden sollte.
Ich vermute den Fehler an 2 Stelle:
- das mit der Objekterzeugung und den statischen Klassenattributen funktioniert nicht so, wie ich es mir vorstelle
- die reflesh()-Methode in der Klasse Table ist nicht ganz richtig.
Aber wie gesagt, ich habe kaum bis gar keine Erfahrung mit größeren Projekten und ich verzweifel schon den ganzen Tag daran, wie ich es am besten mit OO-Design umsetze.
Ich würde statt deinem Manager ein Model verwenden, ist imho besser verwendbar und unterstützt auch Funktionen wie das Bearbeiten von Zellen. Und du sparst dir die mMn hässliche refresh Methode.
Außerdem würde ich eine Collection statt einem Array nehmen. Möglichkeiten wären eine List oder eine Map, je nach Datenmodell. - Vorteil: dynamisch, gibt delete, add, sort Methoden
Ich würde JMenu, JTable und JToolBar nicht überschreiben, sondern das ganze in der GUI Klasse machen (der Einfachheit halber, du sparst dir Code, Verwaltungsaufwand, Attribute, ...), ist aber imho auch Geschmackssache
btw. schonmal was von Model View Controller gehört?
hth
@ Model statt Manager: Du meinst bei der Tabelle mit Models arbeiten, statt das über den Manager und dem Array zu machen? Versteh es nicht ganz, sorry.
@ Collection: Ich kenne hier leider nur die LinkedList. Als ich mit der Programmierung angefangen habe, war ich mir nicht sicher, was besser ist. Dadurch, dass Filme hinzugefügt und gelöscht werden, ist die LinkedList was Dynamik angeht natürlich besser (wobei es bei einem Array jetzt nicht so der Aufwand ist imho).
Ich habe mich dann aber für ein Array entschieden, weil ich über die index-Zahl sofort auf jedes Array zugreifen kann, ohne immer durch die Liste laufen zu müssen.
Zum Datenmodel:
Das Array besteht aus Movieobjekten, welche so aussehen:
Code:package main.system; public class Movie { // Name des Films private String name; // Genre des Films private String genre = "kein Genre gesetzt"; // Rating der Seite imdb.com private String imdbrating = "kein Rating gesetzt"; // Rating der Seite moviemaze.de private String mmrating = "kein Rating gesetzt"; // url zu einer Seite (zb imdb.com) private String url; /** * Konstruktor * @param name String: Name des Filmes, welcher hinzugefügt werden soll */ public Movie (String name) { this.name = name; } public void setname (String name) { this.name = name; } public String getname() { return this.name; } public void setgenre (String genre) { this.genre = genre; } public String getgenre() { return this.genre; } public void setimdbrating (String rating) { this.imdbrating = rating; } public String getimdbrating() { return this.imdbrating; } public void setmmrating (String rating) { this.mmrating = rating; } public String getmmrating() { return this.mmrating; } public void seturl (String url) { this.url = url; } public String geturl() { return this.url; } }
Also LinkedList ist eigentlich nicht so umständlich zu verwenden JavaDoc 4 LinkedList
1k+ Zeilen? Naja kommt drauf an, man kann/soll es auf mehrere Klassen ausweiten, _nur_ sollte man abwägen was in andere Klassen kommt und was nicht. Weil imho kann man nicht alles in unterschiedlichen Klassen lösen, denn sonst kommen sehr sehr viele Objekten und Getter/Setter zusammen
Ja benutze ein Model! Weil du deutlich mehr Möglichkeiten hast! JavaDoc 4 TableModel Example 4 TableModel
hth
@ LinkedList: Hast schon Recht, werde es dann mal umbauen.
@ GUI: Auch hier wird wohl alles abgeändert werden (weil ich so momentan eh nicht weiter komme wegen meinem refresh()-Problem)
Thx für den Input, werde mich dann mal ranmachen, alles umzubauen.
Werde hier dann das Ergebnis posten (vorher eventuell Fragen haben, falls ich wieder feststecke ), ob sich mein Problem erledigt hat etc.
lg Denne
overclockers.at v4.thecommunity
© all rights reserved by overclockers.at 2000-2025