Einfacher Baum visualisieren.

Marco13

Top Contributor
Womit nochmal der Unterschied deutlich geworden wäre, zwischen "einen einfachen Baum visualisieren" und "einen Baum einfach visualisieren". Vielleicht geht das ja mit "yFiles"? :D Mal im ernst: Es gibt Bibliotheken für sowas, JGraph, Jung & Co, die für allgemeine Graphen gedacht sind. Wenn es NUR um einen speziellen, kleinen Baum geht, und nicht 50 verschiedene Renderer, Färbungen, Interaktionen und LayoutManager verwendet werden sollen, könnte die Einarbeitung in so eine Lib aufwändiger sein, als es selbst schnell irgendwie hinzuschreiben.
 

Wildcard

Top Contributor
Mal im ernst: Es gibt Bibliotheken für sowas, JGraph, Jung & Co, die für allgemeine Graphen gedacht sind. Wenn es NUR um einen speziellen, kleinen Baum geht, und nicht 50 verschiedene Renderer, Färbungen, Interaktionen und LayoutManager verwendet werden sollen, könnte die Einarbeitung in so eine Lib aufwändiger sein, als es selbst schnell irgendwie hinzuschreiben.
Deshalb habe ich ja Zest vorgeschlagen. Es sind Snippets dabei und wenn man nicht viel customizen will, sondern nur Knoten visualisieren und layouten möchte, dann ist man für solche Graphen bei Zest mit 20-50 Zeilen Code dabei.
 

André Uhres

Top Contributor
Wie implementiere ich so etwas? Hat jemand ein SampleCode?

Hallo 23,

hier ist ein kleines Beispiel:

Java:
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class TreeDemo extends JFrame {
    public TreeDemo() {
        super("TreeDemo");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(400, 400);
        setLocationRelativeTo(null);
        Tree tree = createDemoTree();
        Node root = tree.getRoot();
        root.moveTo(getSize().width / 2 - root.getBounds().width / 2, 20);
        root.balanceX();
        root.balanceY();
        add(new TreeComponent(tree));
    }
    public static void main(final String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new TreeDemo().setVisible(true);
            }
        });
    }
    private Tree createDemoTree() {
        Node root = new Node(new Person("Peter"));
        Node n2 = new Node(new Person("Andrew"));
        Node n3 = new Node(new Person("Paul"));
        Node n5 = new Node(new Person("Jane"));
        Node n8 = new Node(new Person("Bert"));
        Node n9 = new Node(new Person("Big Blue"));
        n9.setBounds(new Rectangle(0, 0, 100, 100));
        Node n10 = new Node(new Person("Benny"));
        root.addChild(n3);
        root.addChild(n9);
        n3.addChild(n2);
        n3.addChild(n5);
        n9.addChild(n8);
        n9.addChild(n10);
        return new Tree(root);
    }
}
class TreeComponent extends JPanel {
    private Tree tree;
    public TreeComponent(final Tree tree) {
        this.tree = tree;
    }
    @Override
    public void paintComponent(final Graphics g) {
        drawTree(g, tree.getRoot());
    }
    private void drawTree(final Graphics g, final Node node) {
        ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        drawNode(g, node);
        int numberOfChildren = node.numberOfChildren();
        for (int i = 0; i < numberOfChildren; i++) {
            drawTree(g, node.childNr(i));
        }
    }
    private void drawNode(final Graphics g, final Node node) {
        g.setColor(Color.BLACK);
        g.drawRect(node.getBounds().x, node.getBounds().y,
                node.getBounds().width, node.getBounds().height);
        FontMetrics fm = getFontMetrics(getFont());
        int i = fm.stringWidth(node.getElement().toString());
        g.drawString(node.getElement().toString(), (node.getBounds().x
                + node.getBounds().width / 2) - (i / 2), node.getBounds().y
                + node.getBounds().height / 2);
        g.setColor(Color.BLUE);
        for (int j = 0; j < node.numberOfChildren(); j++) {
            Node child = node.childNr(j);
            g.drawLine(node.getBounds().x
                    + node.getBounds().width / 2, node.getBounds().y
                    + node.getBounds().height,
                    child.getBounds().x
                    + child.getBounds().width / 2, child.getBounds().y);
        }
    }
}

class Node{
    private Object data;
    private List<Node> children;
    private Rectangle bounds;

    public Node(final Object o) {
        data = o;
        children = new ArrayList();
        bounds = new Rectangle(0, 0, 50, 50);
    }
    public void addChild(final Node child) {
        children.add(child);
    }
    public Object getElement() {
        return data;
    }
    //
    public Rectangle getBounds() {
        return bounds;
    }
    public void setBounds(final Rectangle bounds) {
        this.bounds = bounds;
    }
    public Node childNr(final int nr) {
        return children.get(nr);
    }
    public int numberOfChildren() {
        return children.size();
    }
    private int childrenWidth() {
        int width = 0;
        for (int i = 0; i < numberOfChildren(); i++) {
            width += childNr(i).maxWidth();
            if (i != numberOfChildren() - 1) {
                width += 10;
            }
        }
        return width;
    }
    private int maxWidth() {
        int cWidth = childrenWidth();
        if (cWidth > getBounds().width) {
            return cWidth;
        } else {
            return getBounds().width;
        }
    }
    public void balanceX() {
        if (numberOfChildren() > 0) {
            int cWidth = childrenWidth();
            int middleX = getBounds().x + getBounds().width / 2;
            int startX = middleX - cWidth / 2;
            for (int i = 0; i < numberOfChildren(); i++) {
                Node child = childNr(i);
                int maxWidth = child.maxWidth();
                int newX = (startX + maxWidth / 2) - child.getBounds().width / 2;
                child.moveTo(newX, child.getBounds().y);
                child.balanceX();
                startX = startX + maxWidth + 10;
            }
        }
    }
    private void balanceY(final int height) {
        int childHeight = 0;
        int newY = getBounds().y + height + 20;
        for (int i = 0; i < numberOfChildren(); i++) {
            Node child = childNr(i);
            if (child.getBounds().height > childHeight) {
                childHeight = child.getBounds().height;
            }
        }
        for (int i = 0; i < numberOfChildren(); i++) {
            Node child = childNr(i);
            child.moveTo(child.getBounds().x, newY);
            child.balanceY(childHeight);
        }
    }
    public void balanceY() {
        balanceY(getBounds().height);
    }
    public void moveTo(final int newX, final int newY) {
        getBounds().x = newX;
        getBounds().y = newY;
    }
}

class Tree {
    private Node root;
    public Tree(final Node root) {
        this.root = root;
    }
    public Node getRoot() {
        return root;
    }
}
class Person{
    private final String name;
    public Person(final String name){
        this.name = name;
    }
    @Override
    public String toString(){
        return name;
    }
}

Gruß,
André
 

23

Bekanntes Mitglied
Vielen Dank ich werde, sobald ich in der Lage bin mir alles anschauen :)

ICh brauche wirklich nur eine kleine Idee wie ich so etwas implementieren kann. Der spätere Code wird nicht einmal mit Java geschrieben... trotzdem wollte ich ein einfaches Java Beispiel da ich wußte hier sind einige gute Hacker ;-)

Viele Grüße
 

Marco13

Top Contributor
Deshalb habe ich ja Zest vorgeschlagen. Es sind Snippets dabei und wenn man nicht viel customizen will, sondern nur Knoten visualisieren und layouten möchte, dann ist man für solche Graphen bei Zest mit 20-50 Zeilen Code dabei.

Falls das mißverständlich war: Den Beitrag hatte ich geschrieben, ohne den Hinweis auf Zest gesehen zu haben. Das hattest du schon ein paar mal für solche Sachen empfohlen, aber ich hatte es hier dann vergessen. Es sieht auf Basis der Beispiele wirklich einfach aus, muss ich mir unbedingt mal :rtfm:en
 

23

Bekanntes Mitglied
André Uhres vielen Dank genau so etwas habe ich gebraucht.

Ich konnte aus deinem Sample endlich mal sehen wie man da überhaupt vorgehen kann :)

Wie lange hast du dafür gebraucht und war dies Teil deines Studiums/Ausbildung?

Hat diese Implementierung einen Namen bzw. auf wen geht diese evtl. zurück?

Ist dies der beste Weg? Gibt es noch effizientere Implementierungen?

Ich würde mich auch sehr freuen falls jemand einige seiner FH/Uni Unterlagen und Code bereitstellen würde... wir hatten zu diesem Thema leider nur eine Vorlesung und da ging es nur um Bäume ohne das Zeichnen :-(
 

André Uhres

Top Contributor
Hallo 23,

ich hatte vor Jahren ein entsprechendes Beispiel im Netz gefunden. Das finde ich aber jetzt nicht wieder. Viel Besonderes ist ja eigentlich auch nicht dabei, außer dass ein paar Methoden rekursiv arbeiten, wie "drawTree" und die "balance" Methoden.

Das Prinzip habe ich inzwischen in anderen Projekten verwendet und immer wieder angepasst. Von daher weiß ich auch nicht mehr, wie lange ich dafür gebraucht habe. Man kann es als Teil meines Selbst-Studiums ansehen (kein Hochschulstudium).

Ob es einen besseren oder effizienteren Weg gibt, weiß ich nicht. Ich glaube jedoch, dass die Implementierung ziemlich klar strukturiert und relativ gut verständlich ist. Ich bin auch kein Freund von größerer Effizienz auf Kosten der Klarheit, besonders wenn die "größerer Effizienz" kaum wahrnehmbar oder messbar ist.

Gruß,
André
 

23

Bekanntes Mitglied
Wie würde ihr bei diesem Code eine gesamte Berechnung der Breite und Höhe des Baums einpflegen?

Neue Methoden schreiben?
 

André Uhres

Top Contributor
Hallo 23,

nach eingehender Überlegung ist es meiner Meinung nach besser, die Funktion einfach in eine neue Methode auszulagern. Bei der folgenden Lösung gibt die Methode [c]getBounds(final int BORDER)[/c] in der Klasse [c]Node[/c] die Größe des Knotens (samt aller Unterknoten) zurück, unter Berücksichtugung eines eventuell notwendigen Randes. Die Methode ruft [c]calcSize[/c] auf, eine rekursive Methode, die einfach nur den Teilbaum durchläuft, um den oberen rechten und den unteren linken Punkt einer imaginären "Boundingbox" zu ermitteln:

Java:
...
public class TreeDemo extends JFrame {
    public TreeDemo() {
...
        Rectangle bounds = root.getBounds(10);
        System.out.println("bounds = " + bounds);
    }
...
}
...
class Node{
...
    private Point upperLeftCorner = new Point(0, 0);
    private Point lowerRightCorner = new Point(0, 0);
...
    private void calcSize(final Node node) {
        int numberOfChildren = node.numberOfChildren();
        for (int i = 0; i < numberOfChildren; i++) {
            Node child = node.childNr(i);
            if(child.numberOfChildren() > 0){
                calcSize(child);
            }else{
                int x1 = child.getBounds().x;
                int x2 = x1 + child.getBounds().width;
                int y1 = child.getBounds().y;
                int y2 = y1 + child.getBounds().height;
                if (x1 < upperLeftCorner.x) {
                    upperLeftCorner.x = x1;
                }
                if (x2 > lowerRightCorner.x) {
                    lowerRightCorner.x = x2;
                }
                if (y1 < upperLeftCorner.y) {
                    upperLeftCorner.y = y1;
                }
                if (y2 > lowerRightCorner.y) {
                    lowerRightCorner.y = y2;
                }
            }
        }
    }
    public Rectangle getBounds(final int BORDER) {
        upperLeftCorner.x = getBounds().x;
        upperLeftCorner.y = getBounds().y;
        lowerRightCorner.x = getBounds().x + getBounds().width;
        lowerRightCorner.y = getBounds().y + getBounds().height;
        calcSize(this);
        upperLeftCorner.x -= BORDER;
        upperLeftCorner.y -= BORDER;
        lowerRightCorner.x += BORDER;
        lowerRightCorner.y += BORDER;
        return new Rectangle(upperLeftCorner.x, upperLeftCorner.y, lowerRightCorner.x - upperLeftCorner.x, lowerRightCorner.y - upperLeftCorner.y);
    }
...

Gruß,
André
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
N JavaFX Einfacher Taschenrechner mit Scene Builder und Java FX AWT, Swing, JavaFX & SWT 0
EinNickname9 Einfacher parser funktioniert nicht AWT, Swing, JavaFX & SWT 2
A Swing Vokabeltrainer zeigt in einfacher Ausführung nichts an AWT, Swing, JavaFX & SWT 5
J Progressbar mit einfacher Funktion AWT, Swing, JavaFX & SWT 6
R einfacher mp3 player AWT, Swing, JavaFX & SWT 18
N einfacher ActionListener und NullPointer AWT, Swing, JavaFX & SWT 2
V ButtonGroup einfacher überwachen? AWT, Swing, JavaFX & SWT 7
H einfacher TextEditor AWT, Swing, JavaFX & SWT 4
S Einfacher Klick aber mouseClicked() zweimal aufgerufen AWT, Swing, JavaFX & SWT 3
C einfacher Texteditor in Java AWT, Swing, JavaFX & SWT 3
R JavaFX Baum mit JFXTreeTable AWT, Swing, JavaFX & SWT 0
D SWT TreeViewer: Daten aus Model gelöscht... trotzdem noch im Baum AWT, Swing, JavaFX & SWT 4
H 2D-Grafik Bibliothek um Graph\Baum zu erstellen AWT, Swing, JavaFX & SWT 2
U Baum/Tree nach Benutzer anzeigen AWT, Swing, JavaFX & SWT 3
S Problem mit Baum AWT, Swing, JavaFX & SWT 4
T 2-3-4 Baum Problem AWT, Swing, JavaFX & SWT 2
A Gemeinsames Model für Baum- und Graphdarstellung-wie gehts? AWT, Swing, JavaFX & SWT 9
A Musikkapelle visualisieren AWT, Swing, JavaFX & SWT 6
mrbody234 ArrayList<Message> in eine TableView visualisieren AWT, Swing, JavaFX & SWT 2
Soloeco Swing Straßennetz visualisieren AWT, Swing, JavaFX & SWT 9
GenerationLost Bilder an bestimmten Platz einfügen/Objekte visualisieren AWT, Swing, JavaFX & SWT 1
N GDS II visualisieren AWT, Swing, JavaFX & SWT 2
W Objekt-array als Raster visualisieren AWT, Swing, JavaFX & SWT 3
G BubbleSort mit Hilfe einer Balkengrafik visualisieren AWT, Swing, JavaFX & SWT 9
E Visualisieren von Bäumen? AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben