简体   繁体   中英

How to use relative cell highlighting in SwingX?

I want to highlight cells in a org.jdesktop.swingx.JXTreeTable relative to the value inside like in the SwingX showcase under 'Highlighting (Extended)':

i.imgur.com/iw89kqn.png

There is some code provided in the showcase but I just can't get it to work, it doesn't highlight anything. I can't really comprehend where the highlighter gets bind to the values (maybe the provided code is not complete). Also there is no documentation available.

Here is the code from the showcase:

This is my code:

TreeFrame.java

private void initialize( ProfileThread profileThread )
{
    try
    {
      UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
    }
    catch ( Exception e )
    {
      e.printStackTrace();
    }

    setBounds( 0, 0, 800, 600 );
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

    setTitle( "ProfileLog" );

    NoRootTreeTableModel model = new NoRootTreeTableModel(
        profileThread.getProfileThreadElements(), this );
    JXTreeTable treeTable = new JXTreeTable( model );

    MattePainter painter = new MattePainter( PaintUtils.setAlpha( Color.RED, 125 ) );
    highlighter = new RelativePainterHighlighter( painter );

    highlighter.setHighlightPredicate( HighlightPredicate.ALWAYS );

    treeTable.addHighlighter( highlighter );

    JScrollPane treeView = new JScrollPane( treeTable );
    getContentPane().add( treeView );

    setVisible( true );
  }

  public void setCurrentDuration( long duration )
  {
    DurationRelativizer relativizer = createDurationRelativizer( duration );
    highlighter.setRelativizer( relativizer );
  }

  /**
   * Creates and returns a relativizer with the given intermediate value.
   *
   */
  private DurationRelativizer createDurationRelativizer( long duration )
  {
    return new DurationRelativizer( 0, true, 15000, duration );
  }

  public static class DurationRelativizer extends NumberRelativizer
  {

    public DurationRelativizer( int column, boolean spreadColumns, Number max, Number current )
    {
      super( column, spreadColumns, max, current );
    }

    @Override
    protected Number getNumber( ComponentAdapter adapter )
    {
      if ( !( adapter.getValue( getValueColumn() ) instanceof ProfileThreadElement ) )
      {
        return null;
      }
      return ( (ProfileThreadElement) adapter.getValue( getValueColumn() ) ).getDuration();
    }
  }

I took the relevant pieces of code from the example and changed them for my requirements. My RelativePainterHighlighter class is exactly the same like in the showcase.

This is my ProfileThreadElement class:

ProfileThreadElement.java

import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import javax.swing.tree.TreeNode;

public class ProfileThreadElement implements TreeNode
{
  private Date start;
  private Date end;
  private long duration;
  private String text;
  private String result;

  private ProfileThreadElement parent;
  private List<ProfileThreadElement> children;

  /**
   * Instantiates a new profile thread element.
   *
   * @param timestamp the timestamp
   * @param text the text
   */
  public ProfileThreadElement( Date timestamp, String text )
  {
    super();
    this.start = timestamp;
    this.text = text;
    this.children = new ArrayList<ProfileThreadElement>();
  }

  /**
   * Close.
   *
   * @param timestamp the timestamp
   * @param duration the duration
   * @param result the result
   */
  public void close( Date timestamp, long duration, String result )
  {
    this.end = timestamp;
    this.duration = duration;
    this.result = result;

  }

  /**
   * Adds the children.
   *
   * @param child the child
   */
  public void addChildren( ProfileThreadElement child )
  {
    // if ( children == null )
    // {
    // children = new ArrayList<ProfileThreadElement>();
    // }

    children.add( child );
    child.setParent( this );
  }

  /**
   * @param parent the parent to set
   */
  void setParent( ProfileThreadElement parent )
  {
    this.parent = parent;
  }

  /**
   * Checks if is open.
   *
   * @return true, if is open
   */
  public boolean isOpen()
  {
    return end == null;
  }

  /**
   * @return the start
   */
  public Date getStart()
  {
    return start;
  }

  /**
   * @return the end
   */
  public Date getEnd()
  {
    return end;
  }

  /**
   * @return the duration
   */
  public long getDuration()
  {
    return duration;
  }

  /**
   * @return the text
   */
  public String getText()
  {
    return text;
  }

  /**
   * @return the result
   */
  public String getResult()
  {
    return result;
  }

  /**
   * @return the parent
   */
  public ProfileThreadElement getParent()
  {
    return parent;
  }

  /**
   * @return the children
   */
  public List<ProfileThreadElement> getChildren()
  {
    return children;
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.tree.TreeNode#children()
   */
  @Override
  public Enumeration<ProfileThreadElement> children()
  {
    return new Enumeration<ProfileThreadElement>()
    {
      Iterator<ProfileThreadElement> iterator = children.iterator();

      @Override
      public boolean hasMoreElements()
      {
        return iterator.hasNext();
      }

      @Override
      public ProfileThreadElement nextElement()
      {
        return iterator.next();
      }
    };
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.tree.TreeNode#getAllowsChildren()
   */
  @Override
  public boolean getAllowsChildren()
  {
    return !children.isEmpty();
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.tree.TreeNode#getChildAt(int)
   */
  @Override
  public TreeNode getChildAt( int childIndex )
  {
    return children.get( childIndex );
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.tree.TreeNode#getChildCount()
   */
  @Override
  public int getChildCount()
  {
    return children.size();
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.tree.TreeNode#getIndex(javax.swing.tree.TreeNode)
   */
  @Override
  public int getIndex( TreeNode node )
  {
    return children.indexOf( node );
  }

  /*
   * (non-Javadoc)
   *
   * @see javax.swing.tree.TreeNode#isLeaf()
   */
  @Override
  public boolean isLeaf()
  {
    return children.isEmpty();
  }

  @Override
  public String toString()
  {
    StringBuffer sb = new StringBuffer();

    sb.append( duration );
    sb.append( " ms " );
    sb.append( text );

    return sb.toString();
  }
}

And my tree table model:

NoRootTreeTableModel.java

public class NoRootTreeTableModel extends AbstractTreeTableModel
{
  private final static String[] COLUMN_NAMES = { "Duration (ms)", "Function Call", "Class" };

  private List<ProfileThreadElement> profileThreadElements;
  private TreeFrame frame;

  public NoRootTreeTableModel( List<ProfileThreadElement> profileThreadElements, TreeFrame frame )
  {
    super( new Object() );
    this.profileThreadElements = profileThreadElements;
    this.frame = frame;
  }

  @Override
  public int getColumnCount()
  {
    return COLUMN_NAMES.length;
  }

  @Override
  public String getColumnName( int column )
  {
    return COLUMN_NAMES[column];
  }

  @Override
  public boolean isCellEditable( Object node, int column )
  {
    return false;
  }

  @Override
  public Object getValueAt( Object node, int column )
  {
    if ( node instanceof ProfileThreadElement )
    {
      Matcher matcher;
      Pattern pattern;

      ProfileThreadElement element = (ProfileThreadElement) node;

      switch ( column )
      {
        case 0: // duration
          frame.setCurrentDuration( element.getDuration() );
          return element.getDuration();
        case 1: // function
          pattern = Pattern.compile( "\\.[a-z][a-zA-Z]+\\(.*\\)" );
          matcher = pattern.matcher( element.getText() );
          if ( matcher.find() )
            return matcher.group().substring( 1 );
          else
            return "";
        case 2: // class
          pattern = Pattern.compile( ".+?(?=\\.[a-z][a-zA-Z]+\\(.*\\))" );
          matcher = pattern.matcher( element.getText() );
          if ( matcher.find() )
            return matcher.group().replace( "class ", "" );
          else
            return "";
      }
    }
    return null;
  }

  @Override
  public int getChildCount( Object parent )
  {
    if ( parent instanceof ProfileThreadElement )
    {
      ProfileThreadElement element = (ProfileThreadElement) parent;
      return element.getChildren().size();
    }
    return profileThreadElements.size();
  }

  @Override
  public Object getChild( Object parent, int index )
  {
    if ( parent instanceof ProfileThreadElement )
    {
      ProfileThreadElement element = (ProfileThreadElement) parent;
      return element.getChildren().get( index );
    }
    return profileThreadElements.get( index );
  }

  @Override
  public int getIndexOfChild( Object parent, Object child )
  {
    ProfileThreadElement element = (ProfileThreadElement) parent;
    return element.getChildren().indexOf( (ProfileThreadElement) child );
  }
}

I think the biggest problem is that I have no clue where to call the TreeFrame.setCurrentDuration(...) method. This is missing in the showcase demo. Has anyone got relative highlighting to work?

Any help is appreciated, thanks in advance!

PS: If I missed something or if you need further information, please tell me!

I've cut everything out that I didn't need and noticed that doHighlight(..) was never called. The reason was that canHighlight(..) returned false because my relativizer was null.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM