Swing 2 jTables -2 Models - 1 Datenklasse: Änderungen

Status
Nicht offen für weitere Antworten.

ralfz

Aktives Mitglied
Hallo,

Problem1:
ich habe eine Datenklasse, die ich auf 2 jTables aufteile und dazu dann eben auch 2 Modells. Basis ist aber 1 Datenklasse.
Die Models erhalten die Datenklasse als Referenz und können dann über getValue und setValue genutzt werden.

Jetzt sind aber auf der Datenklasse auch Methoden verfügbar, die neue Zeilen und Spalten erzeugen bzw. löschen.
Wie sorge ich am Besten für die Konsistenz? Darf also das jeweilige Model Methoden der Datenklasse bereitstellen und aufrufen, oder sollte es auf Änderungen (ChangeListener?) an der Datenklasse reagieren?

Problem2:
Ein Column-Header erhält beim Hinzufügen einer Spalte ein '*', als Kennzeichen dafür, dass sie neu und noch ungespeichert ist. Dazu füge ich in getColumnName einfach beim Rückgabewert das Sternchen an.
Wird nun die Datenklasse gespeichert, soll das Sternchen natürlich weg. Aber das wird nicht angezeigt/aktualisiert. Bisher rufe ich dann den TableStructureChange auf, aber der überschreibt andere Einstellungen, weil er die Tabelle komplett neu aufbaut. Wie geht das anders/geschickter?

Gruß
Zirni
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
Problem1:
ich habe eine Datenklasse, die ich auf 2 jTables aufteile und dazu dann eben auch 2 Modells. Basis ist aber 1 Datenklasse.
Die Models erhalten die Datenklasse als Referenz und können dann über getValue und setValue genutzt werden.
Und aus welchem Grund benutzt Du nicht ein Modell für die zwei Tabellen? Wo sind die Unterschiede im Modell?

Problem2:
Meine Column-Header erhalten beim Neu-Erzeugen ein '*', als Kennzeichen dafür, dass sie neu und noch ungespeichert sind. Dazu füge ich in getColumnName einfach beim Rückgabewert das Sternchen an.
Wird nun die Datenklasse gespeichert, soll das Sternchen natürlich weg. Aber das wird nicht angezeigt/aktualisiert. Bisher rufe ich dann den TableStructureChange auf, aber der überschreibt andere Einstellungen, weil er die Tabelle komplett neu aufbaut. Wie geht das anders/geschickter?
Die Bezeichnung der Spalten im Modell zu ändern ist ungeschickt. Ändere doch den [c]headerValue[/c] in der Column des ColumnModels statt dessen.

Ebenius
 

ralfz

Aktives Mitglied
-> Und aus welchem Grund benutzt Du nicht ein Modell für die zwei Tabellen? Wo sind die Unterschiede im Modell?

Die eigentliche Tabelle enthält 2 logische Bereiche. Der Benutzer soll in jedem der Beiden separat scrollen und z.B. neue Zeilen hinzufügen können. Ich hatte mir vorgestellt, dass dadurch die Benutzung übersichtlicher wird. Natürlich wird es dadurch auch komplexer die Tabellen in Bezug auf Spalten und Daten konsistenz zu halten.

Gruß
Zirni
 

Ebenius

Top Contributor
Der Inhalt soll genau der gleiche sein? Also die gleichen Spalten, die gleichen Zeilen, die selben Daten? Der Nutzer soll nur unterschiedlich scrollen, sortieren (wenn die Tabellen sortierbar sind), Spalten verschieben und verbreitern/verkleinern können? Dann nimmt man zwei Tabellen mit exakt dem gleichen Modell (also selbe Instanz). Fertig.

Ebenius
 

ralfz

Aktives Mitglied
Nein, anders:

Basis ist eine Entscheidungstabelle:
1. Bereich = Bedingungen (0. Spalte) und Bedingungsanzeiger (Spalten 1..n; Werte: t=True,f= False, -=DontCare)
2. Bereich = Aktionen (0.Spalte) und Aktionsanzeiger (Spalten 1..n; Werte: x=gültige Aktion, -=ungültige Aktion)

Hierbei wird eine 'Regel' als durchgängige Spalte einer "Anzeiger"-Spalte gelesen und später ausgewertet.

Gruß
Ralf
 

Ebenius

Top Contributor
Es gibt zu jeder Zeile in Tabelle 1 genau eine Zeile in Tabelle 2? Dann würde ich immer noch ein Tabellenmodell nehmen die alle benötigten Spalten aus Tabelle 1 und Tabelle 2 beinhaltet. Dann setzt Du den Tabellen eigene TableColumnModels. Beispiel:
Java:
/* (@)SplitTableFun.java */

/* Copyright 2009 Sebastian Haufe

 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

 * Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.GridLayout;

import javax.swing.*;
import javax.swing.table.*;

public class SplitTableFun {

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    final String[] columnNames =
          { "Bezeichner", "Wert 1", "Wert 2", "Wert 3", "Wert 4", "Wert 5" };
    final TableModel model = new DefaultTableModel(columnNames, 10);

    final JTable table1 = new JTable(model, new DefaultTableColumnModel());
    table1.addColumn(new TableColumn(0, 10));
    table1.addColumn(new TableColumn(1));
    table1.addColumn(new TableColumn(2));
    table1.addColumn(new TableColumn(3));

    final JTable table2 = new JTable(model, new DefaultTableColumnModel());
    table2.addColumn(new TableColumn(0));
    table2.addColumn(new TableColumn(4));
    table2.addColumn(new TableColumn(5));

    final JPanel contentPane = new JPanel(new GridLayout(1, 2, 6, 6));
    contentPane.add(new JScrollPane(table1));
    contentPane.add(new JScrollPane(table2));

    final JFrame f = new JFrame("Test Frame: SplitTableFun"); //$NON-NLS-1$
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
}
Oder gibt's da keine Beziehung 1 zu 1? In dem Falle müsstest Du mir erklären, was da synchron sein soll.

Ebenius
 

ralfz

Aktives Mitglied
Also,

Eine ET hat n Bedingungen, m Aktionen und r Regeln und somit r+1 Spalten. Dann ist Tabelle 1 eine n*(r+1) Matrix und Tabelle 2 eine m*(r+1) Matrix.

( Entscheidungstabelle - Wikipedia)

Meine Klasse Entscheidungstabelle ist im Moment so aufgebaut (wahrscheinlich etwas unglücklich):

[Java]
class et{
List<Bedingung> listeBedingungen;
List<Aktion> listeAktionen;
List<Regel> liste Regeln;
}

class Bedingung{
string value;
}

class Aktion{
string value;
}

class Regel{
string name;
List<BedingungsAuspraegung> liste BA;
List<AktionsAusprägung> liste AA;
}
[/Java]

Vermutlich wäre eine Vector<Vector> Variante einfacher gewesen...

Gruß
Ralf
 

Ebenius

Top Contributor
Okay, dann stand ich auf dem Schlauch oder Du hast nicht genau genug erklärt. Ersterers halte ich für nicht unwahrscheinlich. :) Aber ist ja nicht so wichtig.

In dem Fall würde ich mir ein eigenes Modell bauen, das die Datenklasse kapselt, Listener Support hat und alle von den Views benötigten Funktionen bereit stellt; wie BedingungHinzufuegen, Regel löschen, etc. Dieses Modell benachrichtigt alle Zuhörer über seine Veränderung. Wie detailliert das Modell das tut, hängt von den Anforderungen ab. Das beginnt beim einfachen ChangeListener (alle Zuhörer aktualisieren ihren Status vollständig, wenn sich der Status des SuperModells irgendwie geändert hat) und endet bei drei verschiedenen Listeners (für Regeländerungen, Aktionsänderungen und Bedingungsänderungen) mit eigenen Event-Objekten die den EventType (BEDINGUNG_GELOESCHT, BEDINGUNG_HINZUGEFUEGT, ...) und das/die betroffene(n) Element(e) weiter leitet. Dann baust Du Deine Tabellenmodelle so auf, dass sie am besten transient auf dieses neue SuperModell schauen und deren Events verarbeiten und TableModelEvents versenden. Der Aufwand ist relativ hoch; besonders dann, wenn man alles schon anders fast fertig hat. Meiner Meinung nach ist das aber ein sauberer Weg.

Eine andere Möglichkeit ist, sich eine Controller-Klasse zu bauen, die alle Tabellenmodelle kennt und die Aufgabe übernimmt, die verschiedenen GUI-Aktionen immer auf alle Tabellenmodellen zu übertragen. In dem Fall sollte die Controller-Klasse wiederum Zuhörer der Tabellenmodelle sein und deren Zustandsänderungen ebenfalls an die Nachbarn weiterreichen. Dieser Vorschlag sollte leichter auszuführen sein. Dennoch; hierbei gilt zu beachten, dass alle beteiligten Komponenten jede Änderung direkt über den Controller machen. Wenn es dabei Wege außenrum gibt, dann ist das Chaos vorprogrammiert.

Ich hoffe, ich konnte -- nachdem ich nun verstanden habe :) -- ein bisschen helfen.

Ebenius
 

ralfz

Aktives Mitglied
Hallo,

also wenn ich das ausführlich mache schreckt das scheinbar Leute ab. Ich hab das/die Probleme schon einmal hier geposet, der Thread ist immer noch ohne Anwort :( Daher erst einmal einfach erklären. Vermutlich habe ich mich dabei auch etwas unklar ausgedrückt.

Also aktuelle GUI mal als Screentshot.

Zu der Idee mit dem Durchreichen. Ich bin mir nicht ganz sicher, ob ich dich jetzt richtig verstehe. Ich dachte ich hätte den Ansatz schon teilweise umgesetzt.

1.) Eine "normale" Klasse ("DecisionTable"), die die Logik der ET enthält und auch die Methoden für verschiedene Aktionen wie Hinzufügen, Löschen von Bedingungen, Aktionen und Spalten/Regeln.

2.a) 2 Hilfsklassen = Die beiden TableModelle mit "extends AbstractTableModel". Diese werden erstellt, wenn auf der GUI ein Element in der JList gewählt wird. Dann erfolgt der Aufruf (im Event der Liste).

2.b) die getValue und setValue Methoden greifen auf die Referenz der ET zu. Das heisst die Models haben eigentlich keine Werte.

3.) zum anfänglichen Problem2: in den Hilfsklassen gibt getColumnName(int c) entweder den normalen Namen oder den Namen+'*' zurück. Wie oder wo komme ich denn an den "headerValue" der Columns? Das müsste ich dann von "aussen" im Event des Buttons zum hinzufügen einer Spalte machen? Und dann beim Speichern (über Button) wieder zurücksetzen?

[Java]
// im Event der JList:
DecisionTable dt=(DecisionTable) list.getSelectedItem();
tbl1.setModel(dt.createModel1());
tbl2.setModel(dt.createModel2());
...

// in DecisionTable:
public AbstractTableModel createModel1(this){ //übergibt dem Model eine Referenz auf die ET
...}

//das TableModel:
class MyTableModel1 extends AbstractTableModel{

public MyTableModel1(DecisionTable dt){
this.dt=dt;
...
}

public Object getValue(int r, int c){
if(c==0) return dt.getListConditions.get(r).getValue();
else return dt.getListRules.get(c-1).getListConditionQualifier().get(r).getValue();
}

public setValue(int r, int c, Object value){
if ...
dt.getList...().get(r).setValue((String)value);
}

public String getColumnName(int c){
if (c==0) return "Conditions";
else if (dt.getListRules.get(c-1).getId()>0) return dt.getListRules.get(c-1).getValue(); //gespeicherte Regel/Spalte
else return dt.getListRules.get(c-1).getValue()+"*"; //neue ungespeicherte Regel
}

[/Java]

Meine Idee wäre jetzt "einfach" in der createModel Methode das Model als Listener der ET anzumelden und in der ET-Klasse in den Veränderungsmethoden die passenden Events zu feuern.

Gruß und Danke für deine Geduld
Ralf
 

ralfz

Aktives Mitglied
Hallo noch mal,

ich möchte jetzt die Idee des letzten Postings von Ebenius aufgreifen, (leicht abgewandel):

- "eigenes Modell bauen, das die Datenklasse kapselt, Listener Support hat und alle von den Views benötigten Funktionen bereit stellt; wie BedingungHinzufuegen, Regel löschen, etc. Dieses Modell benachrichtigt alle Zuhörer über seine Veränderung."

==>> Gleich die ET-Klasse. Dazu muss diese Listener registrieren können. Ich dachte daran, diese von AbstractTableModel erben zu lassen, dann kann diese Events per fire... versenden.

- "Wie detailliert das Modell das tut, hängt von den Anforderungen ab. Das beginnt beim einfachen ChangeListener (alle Zuhörer aktualisieren ihren Status vollständig, wenn sich der Status des SuperModells irgendwie geändert hat) und endet bei drei verschiedenen Listeners (für Regeländerungen, Aktionsänderungen und Bedingungsänderungen) mit eigenen Event-Objekten die den EventType (BEDINGUNG_GELOESCHT, BEDINGUNG_HINZUGEFUEGT, ...) und das/die betroffene(n) Element(e) weiter leitet."

==>> Die jeweils vorhandenen Zellen werden "nur" über die jTable manipuliert, daher hierfür keine extra abfragen.

==>> Aktionen für das Hinzufügen/Löschen von Zeilen und Spalten werden über Buttons ausgelöst, die auf die ET-Klasse einwirken. Daher müssen die vorhandenen Methoden, um fire... Aufrufe erweitert werden.

-Dann baust Du Deine Tabellenmodelle so auf, dass sie am besten transient auf dieses neue SuperModell schauen und deren Events verarbeiten und TableModelEvents versenden."
==> Meine beiden TableModels schauen jetzt schon auf die ET-Klasse und müssen daher nur noch um die Verarbeitung der Events erweitert werden. Das sollte eigentlich nur ein Durchreichen + evtl. anpassen der Positionsmeldungen sein.

Prinzipiell könnte das dann nachher so aussehen:
Java:
public class DecisionTable extends AbstractTableModel{
   public DecisionTable(){...}

   public createCondition(...){
      ....
      fireTableRowsInserted(...);
   }

   public createAction(){
       ....
       fireTableRowsInserted(...);
   }
  
   public createRule(){
      ...
      fireTableStructureChanged();
   }

   // ähnlich für Löschen
   // ...

  public AbstractTableModel createTableModel1(){
      MyTableModel1 tm = new MyTableModel1(this);  // Referenz zur ET
      this.addTableModelListener(tm); // tm als Listener auf die ET eintragen
      return tm; // tm wird der JTable 1 als Model übergeben
  }

    public AbstractTableModel createTableModel2(){
      MyTableModel2 tm = new MyTableModel2(this);  // Referenz zur ET
      this.addTableModelListener(tm); // tm als Listener auf die ET eintragen
      return tm; // tm wird der JTable 2 als Model übergeben
  }
}
[/Java]

und die Zwischen-Modells (eins exemplarisch):

[Java]
class MyTableModel1 extends AbstractTableModel implements TableModelListener{
   public MyTableModel1(DecisionTable dt){
      //...
   }

   public Object getValueAt(int c, int r){ ...}

   public void setValueAt(int c, int r, Object value){
     //...
     fireTableCellUpdated(c,r);
   }

   // dann die Verarbeitung der Events von DT:
   
   public void tableChanged(TableModelEvent e) {
     //.... Anpassung der Indizes und Auswertung der Events;
     // + Aufruf von fireXXX
   }
}
[/Java]

Dann wird noch beim Aufruf einer DT zur Anzeige, also beim Erstellen der Hilfsmodelle der jeweilige Listener zugewiesen. Siehe DT-Code.

Ich hoffe mal das klappt jetzt so wie ich mir das vorstelle. 

Postet bitte, falls ich hier Mist baue ;)

Gruß
Ralf
 

Ebenius

Top Contributor
An sich sieht das alles schon ganz gut aus. Aber ich würde die ET-Klasse nicht selbst um Listener erweitern. Normaler Weise halte ich meine Daten-Kontainer nackig und baue mir lieber eine Klasse drum herum, die diese Datenobjekte verwaltet. Und ich würde diese Modellklasse nicht TableModelListeners verwalten lassen, sondern lieber einen eigenen Listener bauen (neues Interface das von java.util.EventListener ableitet) und ein eigenes Ereignisobjekt bauen (neue Klasse die von java.util.EventObject ableitet) das die Veränderungen besser beschreibt. Diese Modellklasse kann dann auch den Status [c]dirty[/c] haben (true, wenn nicht persistente Veränderungen vorliegen; also wenn man einen Stern im Fenstertitel darstellen würde) und die Veränderung per Ereignis bekannt geben. Sie kann ebenfalls die Information ob eine Regel persistent ist oder nicht handhaben und die Veränderung per Ereignis bekannt geben. Diese zusätzlichen Informationen kann ein Tabellenmodell ja nicht einfach so abbilden und deswegen können auch die zum Tabellenmodel gehörenden Zuhörer und Ereignisse diese Informationen nicht entgegennehmen bzw. transportieren.

Angenommen ich hätte also so eine Modellklasse, dann würde ich einen extra Listener auf dieses Modell hängen der mir mitteilt, wenn sich der Status einer Regel ändert, damit ich den [c]headerValue[/c] der Spalte modifizieren kann. Ich würde einen weiteren Listener anhängen der den Stern im Fenstertitel setzt, wenn das Modell schmutzig ist.

Die jeweiligen Tabellenmodelle würde ich dann zu Zuhörern der Modellklasse machen, die deren Ereignisse interpretieren und tabellengerecht weiter reichen.

Also alles etwas umfangreicher als Du es im letzten Beitrag beschriebst, aber die Richtung ist ähnlich.

Gute N8, Ebenius
 

ralfz

Aktives Mitglied
WOW, du schläfst auch nicht oder ?! ;)
So, ich mache für heute auch mal lieber Schluß. Danke für die Anregungen. Hört sich auf jeden Fall sauberer als meine jetzt angedachte Lösung an.

Ich habe allerdings eigentlich keine Zeit mehr und muss bald abgeben. Brauche daher eine schnelle mittelprächtige Lösung, die zumindest darauf verzichtet in den ActionEvents von Buttons table.getModel.fireXXX aufzurufen, was ich bisher nutze/nutzen musste.

Dir auch ne gute Nacht ;)
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
W 2 JTables in einem Swing-Fenster? AWT, Swing, JavaFX & SWT 5
F Zeile in mehreren Jtables bei Selektion markieren AWT, Swing, JavaFX & SWT 11
P Zwei JTables auf eine A4-Seite mit einstellbaren Rändern AWT, Swing, JavaFX & SWT 9
M Swing Inhalt meines JTables wird falsch dargestellt AWT, Swing, JavaFX & SWT 8
A befüllen eines JTables mittels Methode AWT, Swing, JavaFX & SWT 10
Helgon Zwei jTables gleich Breit AWT, Swing, JavaFX & SWT 4
S Swing Scrollpane und JTables AWT, Swing, JavaFX & SWT 6
D JTables, Test highlighten innerhalb einer Zelle AWT, Swing, JavaFX & SWT 5
T Zwei Jtables eine JscrollPane AWT, Swing, JavaFX & SWT 3
A Mehrere JTables in einem Fenster AWT, Swing, JavaFX & SWT 8
K Swing Layout-Problem mit JTables und JLists (Mindestgrößen) AWT, Swing, JavaFX & SWT 11
Meldanor JTables - Zeilen hinzufügen/löschen AWT, Swing, JavaFX & SWT 4
S Übernehmen von Inhalten aus Zellen in JTables ohne Return AWT, Swing, JavaFX & SWT 7
C drei JTables, nur eine soll selektiert sein AWT, Swing, JavaFX & SWT 2
C MouseListener für Spalte eines JTables AWT, Swing, JavaFX & SWT 4
G Drag&Drop zwischen JTables AWT, Swing, JavaFX & SWT 2
I Drag and Drop zwischen zwei JTables AWT, Swing, JavaFX & SWT 5
V Grösse eines JTables ändern AWT, Swing, JavaFX & SWT 2
A mehrere jtables verwalten AWT, Swing, JavaFX & SWT 7
F JTables überschrift und Ordnung AWT, Swing, JavaFX & SWT 2
E 13 Jtables deren zellwerte voneinander abhaengen in jtabbed AWT, Swing, JavaFX & SWT 8
T Problem bei Update von JTables in JTabbedPane AWT, Swing, JavaFX & SWT 2
L Erste Spalte eines JTables soll nicht editierbar sein. AWT, Swing, JavaFX & SWT 7
J Daten in verschiedenen JTables AWT, Swing, JavaFX & SWT 5
K Objekt in eine bestimmte Zelle eines JTables legen AWT, Swing, JavaFX & SWT 3
G Jtables und die Tabellenbreite???? AWT, Swing, JavaFX & SWT 13
N Zwei JTables in einem Frame AWT, Swing, JavaFX & SWT 8
M Swing MVC-Pattern - View mit mehreren Models AWT, Swing, JavaFX & SWT 5
S Swing Auf Änderungen eines Models in der View einer JTable reagieren AWT, Swing, JavaFX & SWT 1
Kenan89 3D Models aus anderen Spielen in eigene einfügen AWT, Swing, JavaFX & SWT 3
X Swing Models (JTable, JList etc.) statisch deklarieren ? AWT, Swing, JavaFX & SWT 18
MQue JTable mit verschiedenen Models AWT, Swing, JavaFX & SWT 4
B JList Anzeige aktualisieren (Models) AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben