© 1999-2003, Flemming Koch Jensen
Alle rettigheder forbeholdt
Træstrukturer
Vejledende løsninger

 

 

1 Først har vi JTree-klassen med opbygning af træet:
import javax.swing.*;
import javax.swing.tree.*;

public class DK_JTree extends JTree {
  
  public DK_JTree() {
    DefaultMutableTreeNode dk = new DefaultMutableTreeNode( "Danmark" );
      
      DefaultMutableTreeNode jylland = new DefaultMutableTreeNode( "Jylland" );
      dk.add( jylland );
      
        jylland.add( new DefaultMutableTreeNode( "Århus" ) );
        jylland.add( new DefaultMutableTreeNode( "Viborg" ) );
        jylland.add( new DefaultMutableTreeNode( "Vejle" ) );
        jylland.add( new DefaultMutableTreeNode( "Ikast" ) );
      
      DefaultMutableTreeNode fyn = new DefaultMutableTreeNode( "Fyn" );
      dk.add( fyn );
      
        fyn.add( new DefaultMutableTreeNode( "Odense" ) );
        fyn.add( new DefaultMutableTreeNode( "Svendborg" ) );
        fyn.add( new DefaultMutableTreeNode( "Middelfart" ) );
      
    DefaultMutableTreeNode sjælland = new DefaultMutableTreeNode( "Sjælland" );
    dk.add( sjælland );
    
      sjælland.add( new DefaultMutableTreeNode( "København" ) );
      sjælland.add( new DefaultMutableTreeNode( "Roskilde" ) );
      sjælland.add( new DefaultMutableTreeNode( "Køge" ) );
      sjælland.add( new DefaultMutableTreeNode( "Holbæk" ) );
    
    DefaultMutableTreeNode bornholm = new DefaultMutableTreeNode( "Bornholm" );
    dk.add( bornholm );
    
      bornholm.add( new DefaultMutableTreeNode( "Rønne" ) );
      bornholm.add( new DefaultMutableTreeNode( "Neksø" ) );
    
    setModel( new DefaultTreeModel( dk ) );
    
    addTreeSelectionListener( new PrintListener() );
  }
}
  Dernæst er der selve frame-klassen:
import javax.swing.*;
import java.awt.event.*;

public class DK_Frame extends JFrame {
  
  public DK_Frame( String title ) {
    super( title );
    
    DK_JTree dkTræ = new DK_JTree();
    
    getContentPane().add( new JScrollPane( dkTræ ) );
    
    setDefaultCloseOperation( EXIT_ON_CLOSE );
    
    pack();
    setVisible( true );
  }
}
  Og endelig en testanvendelse:
public class Test {

  public static void main( String[] argv ) {
    new DK_Frame( "Danske byer" );
  }
}

Kildetekster:

DK_Frame.java
DK_JTree.java
PrintListener.java
Test.java

 

2 Først har vi JTree-klassen: Indholdsfortegnelse.
import javax.swing.*;
import javax.swing.tree.*;
import java.util.*;

public class Indholdsfortegnelse extends JTree {
  private String startAfsnit = "Preventive Intelligence Activities";
  
  private AfsnitNode[] nodes = {
    new AfsnitNode( "Letter of Transmittal", -7 ),
    new AfsnitNode( "Foreword", -9 ),
    new AfsnitNode( "Chapter I. Summary and Conclusion", 1 ),
    new AfsnitNode( "  Narrative of Events", 1 ),
    new AfsnitNode( "  Conclusions", 18 ),
    new AfsnitNode( "  Recommendations", 25 ),
    new AfsnitNode( "Chapter II. The Assassination", 28 ),
    new AfsnitNode( "  Planning the Texas Trip", 28 ),
    new AfsnitNode( "  Advance Preparations for the Dallas Trip", 29 ),
    new AfsnitNode( "    " + startAfsnit, 29 ),
    new AfsnitNode( "    The Luncheon Site", 30 ),
    new AfsnitNode( "    The Motorcade Route", 31 ),
    new AfsnitNode( "  Dallas before the Visit", 40 ),
    new AfsnitNode( "  Visits to Other Texas Cities", 42 ),
    new AfsnitNode( "  Arrival at Love Field", 42 ),
    new AfsnitNode( "  Organization of the Motorcade", 43 ),
    new AfsnitNode( "  The Drive Through Dallas", 46 ),
    new AfsnitNode( "  The Assassination", 48 ),
    new AfsnitNode( "    The Time", 48 ),
    new AfsnitNode( "    Speed of the Limousine", 49 ),
    new AfsnitNode( "    In the Presidential Limousine", 49 ),
    new AfsnitNode( "    Reaction by Secret Service Agents", 50 ),
    new AfsnitNode( "  Parkland Memorial Hospital", 52 ),
    new AfsnitNode( "    The Race to the Hospital", 52 ),
    new AfsnitNode( "    Treatment of President Kennedy", 53 ),
    new AfsnitNode( "    Treatment of Governor Connally", 56 ),
    new AfsnitNode( "    Vice President Johnson at Parkland", 56 ),
    new AfsnitNode( "    Secret Service Emergency Security Arrangements", 57 ),
    new AfsnitNode( "    Removal of the President's Body", 58 ),
    new AfsnitNode( "  The End of the Trip", 59 ),
    new AfsnitNode( "    Swearing in of the New President", 59 ),
    new AfsnitNode( "    Return to Washington D.C.", 59 ),
    new AfsnitNode( "    The Autopsy", 59 ),
    new AfsnitNode( "Chapter III. The Shots from The Texas School Book Depository", 61 ),
    new AfsnitNode( "  The Witnesses", 61 ),
    new AfsnitNode( "    Near the Depositiory", 63 ),
    new AfsnitNode( "    On the Fifth Floor", 68 ),
    new AfsnitNode( "    At the Triple Underpass", 71 ),
    new AfsnitNode( "  The Presidential Automobile", 76 )
  };
  
  private TreePath initialPath;
  
  public Indholdsfortegnelse() {
    Object[] startPath=null;
    
    Stack stack = new Stack();

    DefaultMutableTreeNode root = new DefaultMutableTreeNode( "Contents" );
    stack.push( root );
    
    for ( int current=0; current<nodes.length; current++ ) {
      AfsnitNode currentNode = nodes[current];
      
      while ( stack.size() > currentNode.getIndent() + 1 )
        // Vi får ikke brug for denne node mere
        stack.pop();

      DefaultMutableTreeNode parent = (DefaultMutableTreeNode) stack.peek();
      parent.add( currentNode );
      stack.push( currentNode );
      
      // Fang startAfsnit
      if ( currentNode.toString().equals( startAfsnit ) ) {
        startPath = new Object[ stack.size() ];
        
        for ( int i=0; i<stack.size(); i++ )
          startPath[ i ] = stack.get( i );
        
        initialPath = new TreePath( startPath );
      }
    }
    
    DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
    renderer.setOpenIcon( new ImageIcon( "aaben.gif" ) );
    renderer.setClosedIcon( new ImageIcon( "lukket.gif" ) );
    renderer.setLeafIcon( new ImageIcon( "side.gif" ) );
    setCellRenderer( renderer );
    
    setModel( new DefaultTreeModel( root ) );
  }
  
  public void resetPath() {
    setSelectionPath( initialPath );
  }
}
I virkeligheden ville vi normalt anvende en tekstfile til de mange data, men da denne opgave ikke fordrer kendskab til filer har vi i stedet valgt en intern datastruktur i form af et arrays af objekter. Hvert objekt repræsenterer en indgang i indholdsfortegnelsen, og er en instans af følgende klasse
import javax.swing.tree.*;

public class AfsnitNode extends DefaultMutableTreeNode {
  private String title;
  private int pageNo;
  private int indent;
  
  public AfsnitNode( String title, int pageNo ) {
    this.indent = leadingSpaces( title ) / 2;
    this.title  = title.trim();
    this.pageNo = pageNo;
  }
  
  private int leadingSpaces( String s ) {
    for ( int i=0; i<s.length(); i++ )
      if ( s.charAt( i ) != ' ' )
        return i;
    return s.length();
  }
  
  public int getIndent() {
    return indent;
  }
  
  public int getPageNo() {
    return pageNo;
  }
  
  public String toString() {
    return title;
  }
}
For at lette indtastningen, og læsbarheden, har vi valgt at lade konstruktoren "oversætte" antallet af foranstillede mellemrum til en vis indrykning (indent). Denne værdi bruges senere til at opbygge træet.
Konstruktoren i klassen Indholdsfortegnelse (se igen ovenfor) gennemløber arrayet med indholdsfortegnelsen og opbygger træet, idet den anvender en stak til løbende at holde den sti der fører ned til den nuværende knude i træet.

 

Selve framen der viser indholdsfortegnelsen er følgende:

import javax.swing.*;
import java.awt.event.*;

public class IndholdsFrame extends JFrame {
  
  public IndholdsFrame( String title ) {
    super( title );
    
    Indholdsfortegnelse indhold = new Indholdsfortegnelse();
    indhold.resetPath();
    
    indhold.addTreeSelectionListener( new IndholdsValgListener() );
    
    getContentPane().add( new JScrollPane( indhold ) );
    
    setDefaultCloseOperation( EXIT_ON_CLOSE );
    
    setSize( 400, 300 );
    setVisible( true );
  }
}
Her bliver der sat en TreeSelectionListener til indholdsfortegnelsen, der er en instans af følgende klasse:
import javax.swing.event.*;
import javax.swing.tree.*;

public class IndholdsValgListener implements TreeSelectionListener {
  
  public void valueChanged( TreeSelectionEvent e ) {
    TreePath path = e.getPath();
    AfsnitNode node = (AfsnitNode) path.getLastPathComponent();
    
    System.out.println( node.getPageNo() );
  }
}
Listeneren udskriver sidetallet på den indgang i indholdsfortegnelsen, der vælges.

 

Endelig er der en main, der starter starter det hele.

import javax.swing.*;

public class TestIndholdsfortegnelse {
  
  public static void main( String[] argv ) {
    new IndholdsFrame( "The Warren Commission Report" );
  }
}
Figur 1:
Indholdsfor-tegnelsen

Kildetekster:

Indholdsfortegnelse.java
AfsnitNode.java
IndholdsFrame.java
IndholdsValgListener.java
TestIndholdsfortegnelse.java