Programm Überblick BaumDesigner


Inhalt:
    1. Was ist BaumDesigner
    2. Was benötigt man?
    3. Installation und Starten des Programms
    4. Benutzung der Software
    5. Lösungsalgorithmen
      5.1. Baumerstellung (Quelltextauszug)
      5.2. Speichern/Laden des Baumes

1. Was ist BaumDesigner?

Zugegeben, der Name ist gewöhnungsbeürftig, die Software jedoch nicht. Ich entwickelte diese kleine Applikation, weil ich eine kompfortable Lösung suchte, um einen JavaScript-Baum-Menü zu erstellen. Wie im nächsten Kapitel zu lesen ist, kann man sich all die Sourcen von dem TreeMenu aus dem Netz ziehen. Sie sind Open Source. Genau wie meine Anwendung auch. Zieht man jedoch nur die Sourcen, ist es etwas mühselig, von Hand die ganzen Menüdaten einzutragen, da sich oft auch Fehler einschleichen können, die zur Fehlfunktion des Baummenüs führen. Die Anwendung hier, stellt somit eine grafische Ergänzung dar, welche es ermöglicht, schnell an sein eigenes schönes Baummenü zu erstellen. Hier ein paar Bilder von meiner Anwendung:

Das Hauptmenü:
Öffnen eines Baumes:
Mein Menü:

zurück

2. Was benötigt man?

Zunächst die Quellen im Downloadbereich. Ist dies erledigt, kommt es nur darauf an, unter welchem Betriebssystem man es kompilieren und ausführen möchte. Getestet habe ich es sowohl unter Linux als auch unter Windows. Je nachdem werden die Java-Runtime, bzw. die Java SDK (hier 1.3.1 oder höher) benötigt. Unter dem folgenden Link:

Sun Java SDK for Linux/Windows

können Sie bezogen werden. Danach müssen Sie sich die JavaScript-Baummenü-Quellen von:

Mortens Treemenu in JavaScript

Vielen Dank auch für seine Entwicklungsarbeit. Ist dies erledigt kann man mit dem nächsten Kapitel fortfahren.


zurück

3. Installation und Starten des Programms

Unter Linux: Quellen auspacken mit: tar -xvzf bdesigner.tar.gz
make eingeben fertig!
Programm starten mit run.
Unter Windows: Quellen auspacken mit: WinZip oder WinRAR, o.ä...
javac BaumDesigner.java eingeben (Eingabeaufforderung) fertig!
Programm starten mit java BaumDesigner

Allgemein: Achten Sie auf Gross und Kleinschreibung!

zurück

4. Benutzung der Software

Die Benutzung ist dank MVC Steuerung recht komfortabel und einfach. Folgende Tabelle gibt Ihnen ein Überblick über die wichtigsten Funktionen:

Hinzufügen: Klickt man auf diesen Button, so wird ein neuer Eintrag in dem Baum erzeugt. Wichtig ist jedoch, daß vorher im Baum der Eintrag angeklickt wird, wohin der neue Menüpunkt eingefügt werden soll. Ist noch gar kein Men&uum;punkt vorhanden, dann muß einmalig auf Navigationsbaum geklickt werden.
Löschen: Ist ein Baummenüpunkt angewählt, so führt ein Klick auf Löschen zum unweigerlichen Entfernen des Menüpunktes.
Ändern: Sobald irgentetwas im Baum ausgewählt wird, erscheint unten in den Textfeldern, der jeweilige Name und der Querverweis (Link) der zu ihm gehört. Will man Änderungen daran vornehmen, so müssen dort die Einträge verändert werden und anschließend auf Ändern geklickt werden.
Beenden: Ist Klar oder ?!? :-)
HTML: noch nicht implementiert.
JavaScript: Erstellt das Baummenü als JavaScript-Quelltext, welches mit den obigen Quellen zusammen in den eigenen HTML-Quelltext eingefügt werden kann. Die Ausgabe des Quelltextes erfolgt sowohl auf der Konsole, als auch in dem kleinen Vorschaufenster. Unter Linux kann man von der Konsole den markierten Text kopieren, unter Windows einfach alles im Vorschaufenster markieren und mit STRG+C kopieren. In Ihrer jeweiligen HTML-Bearbeitungsanwendung mit STRG+V wieder einfügen.
Laden: Abgespeicherten Baum laden.
Speichern: Erstellten Menübaum speichern.

zurück

5. Lösungsalgorithmen

Zum Quelltext allgemein: Der vollständige Quelltext ist im tar.gz-File enthalten und kann frei kopiert und verändert werden. Ich möchte nur kurz auf meine Programmlösung eingehen, so daß im Falle einer Modifikation der ursprüngliche Gedankengang für mich nachvollziehbar bleibt. Wenn Sie eine bessere Lösung entwickeln sollten, und meine als Vorlage nehmen, so würde ich gerne (ist kein Muß) eine Version zugeschickt bekommen, denn wie gewöhnlich, kann man nie auslernen, und erst recht nicht in der Programmierwelt. Es lebe Open Source. Nun zum Quelltext.

5.1. Baumerstellung (Quelltextauszug)

Der Kommentierte Quelltext:
    private void Baum2JavaScript() {
      JSStringList.clear();
      Baum2Liste.clear();
      Enumeration enum;
      for (enum = top.preorderEnumeration() ; enum.hasMoreElements() ;) {
        try {
          Item Element = (Item) enum.nextElement();
          System.out.println(Element.returnLinkName());
          if (Baum2Liste.add(Element)) System.out.println("Element eingefügt");
          else System.out.println("Element nicht eingefügt");
        }
        catch (java.lang.NullPointerException e) {
          // tue erst mal nichts
        }
      }
      System.out.println("Gebe Baum als JavaScript aus:\n");
      ListIterator iter = Baum2Liste.listIterator();
      char c='"'; // Fuer die JavaScript Funktionen
      int tiefe=0; // Fuer den Tiefenvergleich
      JSStringList.add("var menu = null;"); // Initialer Zustand
      JSStringList.add("var menu = new MTMenu();");
      for (;iter.hasNext();) {
        try {
          Item Element = (Item) iter.next();
          if (Element.getParent().toString().compareTo("Navigationsbaum")==0) {
          // Ist das der Fall handelt es sich um die Root-Elemente
          if (Element.returnLinkName().compareTo("*")!=0) {
            String line = "";
            if (Element.isLeaf()) { // Ist es ein Blatt oder ein Knoten ?
              line = "menu.addItem( new MTMenuItem( "+c+Element.toString()+c+", "+c+
                Element.returnLink()+c+ ", "+c+"text"+c+" ));";
              JSStringList.add(line);
            }
            else {
              line = "menu.addItem( new MTMenuItem( "+c+Element.toString()+c+" ));";
              JSStringList.add(line);
            }
          }
          tiefe = Element.returnTiefe();
        }
        else {
          if (tiefe
            if (Element.returnLinkName().compareTo("*")!=0) {
              Item Hilfe = (Item) Element.getParent();
              String newLine = "var "+Hilfe.returnLinkName()+" = null;";
              JSStringList.add(newLine);
              newLine = Hilfe.returnLinkName()+" = new MTMenu();";
              JSStringList.add(newLine);
            }
          }
          String line = Element.getParent().toString();
          while (line.compareTo(Element.getParent().toString())==0) {
            if (Element.returnLinkName().compareTo("*")!=0) {
            String newLine = "";
            Item Hilfe = (Item) Element.getParent();
            if (Element.isLeaf()) { // Ist es ein Blatt oder ein Knoten ?
              newLine =
              Hilfe.returnLinkName()+".addItem( new MTMenuItem( "+c+
              Element.toString()+c+", "+c+Element.returnLink()+c+", "+c+"text"+c+" ));";
              JSStringList.add(newLine);
            }
            else {
              newLine =
              Hilfe.returnLinkName()+".addItem( new MTMenuItem( "+c+
              Element.toString()+c+" ));";
              JSStringList.add(newLine);
            }
          }
          tiefe = Element.returnTiefe();
          Element = (Item) iter.next();
        }
        // Unterschieden werden muss jetzt, ob das Element tiefer oder nicht tiefer liegt
        // Vergleich der Tiefen
        Item Hilfe = (Item) iter.previous(); // Diese Stelle scheint ungenau zu sein
        if (tiefe>Element.returnTiefe()) {
          Hilfe = (Item) Element.getParent();
          String newLine ="";
          if (Element.getParent().toString().compareTo("Navigationsbaum")==0)
            newLine = "menu";
          else
            newLine = Hilfe.returnLinkName();
            // fixes the problem with some links like C/C++ on 03.04.2002
            newLine = newLine+".makeLastSubmenu( "+isValid(line)+" );";
            JSStringList.add(newLine);
          }
        }
      }
      catch (java.lang.NullPointerException e) {
        // tue erst mal nichts
      }
    }
}

zurück

5.2 Speichern/Laden des Baumes

Diese Persistenzhaltung, die die Swing-Klassen mitbringen, genauer gesagt, die Serialisierbarkeit der einzelnen Java-Klassen ist wirklich erwähnenswert. Man muß sich keine Gedanken machen, wie beispielsweise bei der QT-Bibliothek für C++ unter Linux/Windows und einen eigenen Datei stil erfinden, sonder kann auf die schnelle Abspeicherung der Java-Klassen zurückgreifen. Zunächst wieder zum Quelltext. Hier sind die speziellen Stellen in meinem Source-Code:

    if (pressed==Speichern) {
      // Speichern des Baumes
      try {
        // Dialog aufrufen
        JFileChooser fchoose = new JFileChooser();
        int returnVal = fchoose.showSaveDialog(null);
        if (returnVal==JFileChooser.APPROVE_OPTION) {
          FileOutputStream ostream = new FileOutputStream(fchoose.getSelectedFile().getName());
          ObjectOutputStream JTreeStream = new ObjectOutputStream(ostream);
          JTreeStream.writeObject(top);
          JTreeStream.flush();
          ostream.close();
        }
      }
      catch (java.io.FileNotFoundException e) {
        // Nichts machen vorserst
      }
      catch (java.io.IOException e) {
        // Nichts machen vorserst
      }
    }
    if (pressed==Laden) {
      // Laden des Baumes
      try {
        // Dialog aufrufen
        JFileChooser fchoose = new JFileChooser();
        int returnVal = fchoose.showOpenDialog(null);
        if (returnVal==JFileChooser.APPROVE_OPTION) {
          FileInputStream istream = new FileInputStream(fchoose.getSelectedFile().getName());
          ObjectInputStream JTreeStream = new ObjectInputStream(istream);
          Item root = (Item) JTreeStream.readObject();
          istream.close();
          System.out.println(Navigator.isRootVisible());
          Item LoadedItem = (Item) root.getFirstChild();
          for (int i=0;i!=root.getChildCount()+2;i++) {
            top.add(LoadedItem);
            LoadedItem = (Item) root.getNextNode();
          }
          DefaultMutableTreeNode Last = new DefaultMutableTreeNode ("*");
          top.add(Last);
          Navigator.updateUI();
        }
      }
      catch (java.io.IOException e) {
        // Nichts machen vorserst
      }
      catch (java.lang.ClassNotFoundException e) {
        // Nichts machen vorerst
      }
    }

Alles soweit leicht nachvollziehbar. Schwerpunkt sind hier die writeObject und readObject- Methoden. Wichtig ist nur, wie auch hier im Beispiel zu sehen, daß, eigene Object-Instanzen, wie Item, welches von DefaulMutableTreeNode erbt, auch über eine writeObject und readObject-Methode verfügt. Diese sehen hier wie folgt aus:

    private void writeObject(java.io.ObjectOutputStream out)
    throws IOException {
      out.writeObject(linkname);
      out.writeObject(link);
      out.writeInt(Tiefe);
    }

    private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException {
      linkname = (String) in.readObject();
      link = (String) in.readObject();
      Tiefe = in.readInt();
    }

Man fügt lediglich die eigenen Variablen mit ein, damit sie ebenfalls abgespeichert werden können. Die Klasse selbst wurde wie folgt deklariert:

private class Item extends DefaultMutableTreeNode implements Serializable {

Damit "erbt" die Klasse Item sozusagen, sowohl von DefaultMutableTreeNode und Serializable. Bitte nicht verwechseln! Es gibt bei Java keine doppelte Vererbung. Über Implementierungen, können Objekte dennoch auch andere Methoden benutzen, die in der Klasse von denen sie direkt erben nicht definiert sind. Mehr dazu in der Java-Dokumentation von Sun. Sollten Sie Probleme mit dem Verständnis haben, können Sie mich auch anmailen.

Viel Spaß beim Ausprobieren!

zurück


Sven Alisch
Last modified: Thu Apr 4 15:18:14 CEST 2002