UITree: Knotendarstellung

Allgemeine Fragen zur Entwicklung von und mit JVx.

UITree: Knotendarstellung

Postby Gerhard » Wed Apr 23, 2014 10:55 am

Hallo!

Gibt es eine Möglichkeit die Darstellung eines UITree Knotens zu beeinflussen?
Zum Beispiel würde ich gerne deaktivierte Datensätze anders (ausgegraut) darstellen als aktive. Oder in einem anderen Fall wäre es notwendig, zusätzlichen Text neben der dargestellten Column hinzuzufügen, bzw mehrere Columns anzuzeigen.
In all diesen Fällen wäre das Editieren der Daten über den Tree deaktiviert.

Das Setzen eines CellFormaters hat überhaupt keine Auswirkungen, die Klasse scheint nicht verwendet zu werden.
Code: Select all
tree.setCellFormatter(new ICellFormatter() {
         @Override
         public ICellFormat getCellFormat(IDataBook pDataBook, IDataPage pDataPage, IDataRow pDataRow, String pColumnName, int pRow, int pColumn) {
            System.out.println("cellformat");
            return null;
         }
      });

Im NodeFormatter lässt sich nur das Image verändern.
Code: Select all
tree.setNodeFormatter(new INodeFormatter() {
         @Override
         public IImage getNodeImage(IDataBook pDataBook, IDataPage pDataPage, IDataRow pDataRow, String pColumnName, int pRow, boolean pExpanded, boolean pLeaf) {
            System.out.println("nodeimage");
            return null;
         }
      });
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby Support@SIB » Wed Apr 23, 2014 12:25 pm

Der Standard Swing Tree kann nur eine Spalte anzeigen. Da dies in fast allen Technologien ebenso ist, ist die Implementierung auf diesen „Standard“ beschränkt.
Cellformatter wird aktuell vom Tree nicht verwendet.

Html formattierter Text wird aber sowohl von Swing wie auch von Vaadin unterstützt.

Code: Select all
  <html><font color="#FF0000">My formatted Text</font></html>

Auf diese Art und Weise kann man sich auch mehere Spalten mit fixem Abstand erzeugen.

Am besten ist es, eine zusätzliche Spalte (zB. „TREE_LABEL“) einzuführen, und diese mit dem gewünschten html text zu befüllen.
Dafür gibt es 3 Möglichkeiten:
    - In einer View diese zusätzliche Spalte hinzufügen
    - Am Server vor dem open der DBStorage eine zusätzliche nicht writable Spalte hinzufügen und in einem eventCalculateRow Listener befüllen
    - Am Client im RemoteDataBook vor dem open eine Spalte hinzufügen, und in eventAfterReload (in einer for-Schleife in allen Zeilen) den Text in die Spalte schreiben
Eine weitere Lösung ist, falls Sie schon eine Swing Komponente besitzen, die die Anforderungen erfüllt,
diese mit Hilfe einer UICustomKomponent hinzuzufügen.

Code: Select all
  panel.add(new UICustomComponent(mySwingControl), UIBorderLayout.CENTER)

Hier ist zu beachten, dass dies natürlich nicht mehr Plattform unabhängig ist.
Unter Vaadin müsste man sich dann selbst um ein Control kümmern.
User avatar
Support@SIB
 
Posts: 198
Joined: Mon Sep 28, 2009 1:56 pm

Re: UITree: Knotendarstellung

Postby Gerhard » Wed Apr 23, 2014 1:32 pm

Danke, werde wohl einen der 3 Lösungsansätze umsetzen.
Leider muss man bei diesem Design die Zusatzspalte für die jeweilige Zeile selbst aktualisieren, sobald sich betroffene Werte ändern, damit es im Tree angezeigt wird.
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby Support@SIB » Wed Apr 23, 2014 3:42 pm

Ob man eine Client oder eine Server Lösung wählt, hängt davon ab, ob man die Zeile nach Änderung eines Wertes speichern kann/ darf.

Wenn man speichern darf, empfiehlt sich eine Server Variante (egal welche).
Mit folgendem Util kann man sich das Speichern bei jeder Wertänderung einschalten:
Code: Select all
ProjXUtil.saveImmediate(dataBook);

Mehr muss man nicht tun, weil der Client nach einem Update automatisch die aktuellen Werte als Antwort erhält, und somit sofort den richtigen Tree Label anzeigt.

Darf man nicht speichern, muss man am Client berechnen:
Dann sollte man die Funktion teilen in:
- eine Zeile berechnen
- alle Zeilen durchgehen in der man eine Zeile berechnen aufruft.

Code: Select all
dataBook.eventValuesChanged(this, "doCalculateCurrentRow");
dataBook.eventAfterReload(this, "doCalculateAllRows");
User avatar
Support@SIB
 
Posts: 198
Joined: Mon Sep 28, 2009 1:56 pm

Re: UITree: Knotendarstellung

Postby Gerhard » Tue Apr 29, 2014 1:22 pm

Habe nun die Client-Variante umgesetzt. Diese funktioniert wie beschrieben. Danke.
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby Gerhard » Tue May 06, 2014 1:50 pm

Leider funktioniert es doch nicht so wie erwartet.

Folgenden Code habe ich im initializeModel:
Code: Select all
      ColumnDefinition columnTreeLabel = new ColumnDefinition("TREE_LABEL");
//      columnTreeLabel.setReadOnly(true);
//      columnTreeLabel.setWritable(false);
      rdbTest.getRowDefinition().addColumnDefinition(columnTreeLabel);
      rdbTest.eventAfterReload().addListener(this, "doCalculateAllRows");
      rdbTest.open();

Im doCalculateAllRows soll nun einfach der Name als TREE_LABEL gesetzt werden:
Code: Select all
   public void doCalculateAllRows(DataBookEvent pEvent) throws Throwable {
      IDataBook dataBook = pEvent.getChangedDataBook();
      int rowCount = dataBook.getRowCount();
      for (int i = 0; i < rowCount; i++) {
         IDataRow row = dataBook.getDataRow(i);
         Object name = row.getValue("NAME");
         row.setValue("TREE_LABEL", name);
         System.out.println(row.getValue("TREE_LABEL"));
      }
      for (int i = 0; i < rowCount; i++) {
         IDataRow row = dataBook.getDataRow(i);
         System.out.println(row.getValue("TREE_LABEL"));
      }
   }


Nach dem Aufruf von setValue, wird der Name in der Konsole angezeigt.
In der zweiten For-Schleife ist der Name aber weg. Wieso ist er direkt nach dem Setzen vorhanden, dann aber nicht mehr?
Im Tree wird mir ebenfalls nichts angezeigt.
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby mhandsteiner » Tue May 06, 2014 3:21 pm

Einfache Antwort:
Resistente Änderungen können nur in der aktuell selektierten Zeile eines DataBooks durchgeführt werden, damit sauber alle Events durchlaufen werden.
Die Änderung muss mit saveSelectedRow gespeichert werden. Bei Reload werden alle nichtgespeicherten Änderungen verworfen, und der aktuelle Stand aus der Datenbank geladen.
Mit getDataRow(i) erhält man ein clone der i. Zeile. Änderungen der geclonten Zeile haben keine Auswirkungen auf die Daten des DataBooks. Man kann diese als Übergabe Parameter, Filter Zeile, Zwischenspeicher verwenden.

Hintergrund:
Eine Zeile in einem DataBook hat immer den Status isUpdating()==true, wenn Werte geändert wurden. Ändern kann man nur die aktuell selektierte Zeile mit setValue(). Mit getOriginalRow() erhält man den Zustand vor der Änderung.
Ein restoreSelectedRow stellt den ursprünglichen Zustand wieder her, mit saveSelectedRow speichert man die Daten. Da in diesem Fall keine WritebackColumn geändert wird, erfolgt auch kein call zum Server.
Eine neue Zeile hat analog zum Update den Status isInserting()==true, und eine zum Löschen markierte Zeile isDeleting()==true.

Genaue Event Definition findet man unter:
http://forum.sibvisions.com/viewtopic.php?f=11&t=197

Weiters ist Rowlevel Fetch on Demand nicht berücksichtigt. getRowCount() gibt die Anzahl bereits gefetchter Zeilen der bestehenden DataPage zurück. Da ohnehin alle Zeilen beschrieben werden, reicht ein fetchAll.

Der Code muss wie folgt aussehen:

Code: Select all
public void doCalculateAllRows(DataBookEvent pEvent) throws Throwable {
      IDataBook dataBook = pEvent.getChangedDataBook();
      dataBook.fetchAll();
      int rowCount = dataBook.getRowCount();
      int selectedRow = dataBook.getSelectedRow();
      for (int i = 0; i < rowCount; i++) {
         dataBook.setSelectedRow(i);
         Object name = dataBook.getValue("NAME");
         dataBook.setValue("TREE_LABEL", name);
         dataBook.saveSelectedRow();
      }
      dataBook.setSelectedRow(selectedRow);

      for (int i = 0; i < rowCount; i++) {
         IDataRow row = dataBook.getDataRow(i);
         System.out.println(row.getValue("TREE_LABEL"));
      }
   }
mhandsteiner
 
Posts: 14
Joined: Mon Sep 28, 2009 2:17 pm

Re: UITree: Knotendarstellung

Postby Gerhard » Wed May 07, 2014 10:34 am

Super! Nachdem ich nun die Werte nicht mehr in einer Kopie der Row setze, funktioniert der Tree korrekt.
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby Gerhard » Wed May 07, 2014 12:36 pm

Tja, zu früh gefreut...
Der Tree funktionierte nur auf den ersten Blick korrekt.

Folgende Probleme gibt es:
Im Tree werden 2 Ebenen angezeigt. Die Fehler beginnen in der zweiten Ebene. Es werden nämlich nur die Datensätze korrekt berechnet, die im Detail-DataBook gerade enthalten sind.
Klickt man im Tree auf das + um einen Knoten zu öffnen, passiert im Detail-DataBook natürlich nichts. Der Knoten wird geöffnet, die Detail-Datensätze angezeigt, aber keine Berechnung durchgeführt.
Das selbe Problem entsteht beim Klick auf den Aktualisieren-Button, um alle Daten neu zu laden. Auch hier werden nur die sich aktuell im Detail-DataBook befindlichen Datensätze berechnet, alle anderen Knoten auf zweiter Ebene aber falsch dargestellt.

Um das ganze korret lösen zu können, müsste ich die Spalte wohl schon am Server hinzufügen, und dort die Berechnung ebenfalls durchführen. Und am Client dann nur noch die Änderungen am aktuellen Datensatz beachten. Oder sehe ich hier etwas falsch?

Ganz schön viel Aufwand, nur um die Darstellung des Tree-Lables zu beeinflussen.
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby mhandsteiner » Thu May 08, 2014 11:27 am

Das Problem lässt sich clientseitig lösen, wobei serverseitig ist es am einfachsten.

Client Lösung:
Reload Listenber nur auf das MasterDataBook hängen.
Code: Select all
public void doCalculateAllRows(DataBookEvent pEvent) throws Throwable {
  doCalculateAllRows(rdbMaster, rdbDetail);
}

public void doCalculateAllRows(IDataBook pMasterDataBook, IDataBook pDetailDataBook) throws Throwable {
      pDataBook.fetchAll();
      int rowCount = pDataBook.getRowCount();
      int selectedRow = pDataBook.getSelectedRow();
      for (int i = 0; i < rowCount; i++) {
         pDataBook.setSelectedRow(i);
         Object name = pDataBook.getValue("NAME");
         pDataBook.setValue("TREE_LABEL", name);
         pDataBook.saveSelectedRow();
         
         if (pDetailDataBook != null)
         {
             doCalculateAllRows(pDetailDataBook, null);
         }
      }
      pDataBook.setSelectedRow(selectedRow);
   }


Serverseitig Lösung:
In der View mitliefern:
select '<html>'||name||'</html>' tree_label
,name
,...
from my_table

Funktioniert out of the Box. Wenn man keine View erzeugen will, kann man die Spalten auch bei der DBStorage als QueryColumns setzen.
mhandsteiner
 
Posts: 14
Joined: Mon Sep 28, 2009 2:17 pm

Re: UITree: Knotendarstellung

Postby Gerhard » Mon May 26, 2014 3:01 pm

Habe die DB Lösung umgesetzt. Zu beachten ist, dass die View alle Spalten enthalten muss, die sonst automatisch gejoint werden.

Was noch nicht korrekt funktioniert, ist die Aktualisierung der Anzeige, wenn ein Datensatz bearbeitet wird. Und zwar ändert der Label des Trees nicht automatisch die Größe.

Hier ein Beispiel:
In tree1.png sieht man die Ausgangslage. Ich habe einen Tree-Knoten selektiert. Darüber befinden sich die Textfelder zum editieren der Daten.
Nun hängen ich an den Text "test" noch weitere Zeichen an, und navigiere auf einen anderen Knoten, um die Änderungen in die Datenbank zu schreiben.
In tree2.png ist das Ergebnis zu sehen, der Tree-Label wird nicht größer, sondern zeigt ... an.
Attachments
tree1.png
tree1.png (5.11 KiB) Viewed 6331 times
tree2.png
tree2.png (4.75 KiB) Viewed 6331 times
Gerhard
 
Posts: 15
Joined: Tue Apr 22, 2014 5:14 pm

Re: UITree: Knotendarstellung

Postby mhandsteiner » Mon May 26, 2014 7:12 pm

Der JTree validiert nur die Größe des aktuell selektierten Knotens.
Durch das direkte selektieren im Tree wird aber erst der Wert des ursprüngliche Knoten geändert, aber die Größe nicht mehr validiert, da er nicht mehr selektiert ist.

Eine Abhilfe schafft eventuell:
ProjXUtil.saveImmediate(rdbTabelle);
Dies forciert das Speichern nach jeder Wertänderung. Somit sollte noch der richtige Knoten selektiert sein, und die Größe validiert werden.

Ich habe ein Bug Ticket in JVx erstellt, und einen Bugfix eingecheckt, der alle sichtbaren Knoten des Tree's validiert.

Bitte das morgige JVx nightly probieren, ob das Problem generell (auch ohne obigen Workaround) behoben ist.
mhandsteiner
 
Posts: 14
Joined: Mon Sep 28, 2009 2:17 pm


Return to Entwicklung