Use of JTextPane in Chatting Application

Discussion in 'Java' started by Sameer, Sep 4, 2005.

  1. Sameer

    Sameer Guest

    A JTextPane is a text component that can be marked up with
    attributes that are represented graphically.

    In the process of writing a chatting application, i am going to use
    JTextPane for accepting the text from user on a client (So that
    underline can also be displayed which can not be displayed using
    JTextField).

    Can i get different format for each character (This feature is not
    available in Yahoo Messenger) ?
    I want to send this information to another machine.
    How to pack all the formatting of the text with different attribute of
    each character in a single class so that i can send this object by
    serializing it? Is it possible that JTextPane can be represented by a
    single class with all the formatting information available with it?
    What are the related 'returning' methods of JTextPane

    Any idea about implementing Emoticons (Emotion Icons)? JTextPane let us
    insert icons, but can we wrap this information in a class to transfer
    it over the socket?
    Please help me if you have any idea about it.
    -Sameer
     
    Sameer, Sep 4, 2005
    #1
    1. Advertising

  2. On 4 Sep 2005 00:51:32 -0700, Sameer wrote:

    > What are the related 'returning' methods of JTextPane..


    You can probably ascertain that by examining the JavaDocs.
    <http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTextPane.html>
    ...or would you like me to read them out to you?

    Note: X-Post
    comp.lang.java.programmer,
    comp.lang.java.gui,
    comp.lang.java.help

    Please do not cross posst to more than two groups, and direct
    Follow-Ups to a *single* group. It is usually not a good idea
    to X-Post between c.l.j.help and any other Java group.

    Follow-Ups to *this* post set to c.l.j.gui only.

    --
    Andrew Thompson
    physci.org 1point1c.org javasaver.com lensescapes.com athompson.info
    "Come on boys, let's push it hard.."
    P.J. Harvey 'Victory'
     
    Andrew Thompson, Sep 4, 2005
    #2
    1. Advertising

  3. Sameer

    Roedy Green Guest

    On 4 Sep 2005 00:51:32 -0700, "Sameer" <> wrote or
    quoted :

    >Can i get different format for each character


    You need some code like this:

    // window where other people's chat appears
    JEditorPane output;

    output = new JEditorPane();
    output.setContentType( "text/html" );
    output.setEditable( false );
    output.setBackground( lemonChiffon );
    // Serif has best chance of supporting Unicode.
    output.setFont( new Font( "Serif", Font.PLAIN, 13 ) );
    output.setForeground( black );

    Now you fill the pane with primitive html to get your colours, e.g.

    output.setText( "<html><body><font
    color="red">cherry</font></body></html>");


    See http://mindprod.com/jgloss/htmcheat.html
    for a crash course in HTML.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 5, 2005
    #3
  4. Sameer

    Roedy Green Guest

    On 4 Sep 2005 00:51:32 -0700, "Sameer" <> wrote or
    quoted :

    >Can i get different format for each character (This feature is not
    >available in Yahoo Messenger) ?
    >I want to send this information to another machine.
    >How to pack all the formatting of the text with different attribute of
    >each character in a single class so that i can send this object by
    >serializing it? Is it possible that JTextPane can be represented by a
    >single class with all the formatting information available with it?
    >What are the related 'returning' methods of JTextPane


    I am not sure of this but I think internally JTextField (and its child
    JTextPane) uses either RTF or HTML internally, whichever you set with
    setContentType. I would expect style changes you make either by
    feeding it HTML or by using the style setting commands would be
    reflected in any of the getText methods. You can find out pretty
    quickly with a simple experiment. Do a getText and see what it gives
    you.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 5, 2005
    #4
  5. Sameer

    Roedy Green Guest

    On 4 Sep 2005 00:51:32 -0700, "Sameer" <> wrote or
    quoted :

    >Any idea about implementing Emoticons (Emotion Icons)? JTextPane let us
    >insert icons, but can we wrap this information in a class to transfer
    >it over the socket?


    JTextPanes so far as I know do not display embedded images. So the
    only way you could get emoticons is as a font.

    You need a free font of emoticons your users can install independently
    of Java, or you need to use the relatively recent tools for bundling a
    font in a resource file. For frequent players, you would get better
    speed by intalling the font once and for all than downloading it each
    game play as an Applet resource.

    You have to find a free font with emoticons.

    to start your search see http://mindprod.com/jgloss/font.html

    There is another approach, probably too slow, generating HTML and
    handing it off to the browser to render with showDocument. Then you
    could display anything, even hyperlinks.

    There is yet another approach, the hairy chested approach where you
    render everything yourself on a Canvas. Have a look at
    http://mindprod.com/projects/javapresenter.html

    What I have effectively done is create tokenized form of HTML that I
    render myself with colours and fonts. This is very fast. I could
    potentially display images too.

    Here is the key class. Most of the code is concerned with rendering no
    more than the narrow band requested, and rapidly finding the data for
    that band to render. The lines of text are not evenly spaced
    vertically. That is why it is so complicated.


    package com.mindprod.jdisplay;

    import java.awt.Canvas;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.RenderingHints;
    import java.util.Arrays;

    import com.mindprod.jtokens.NL;
    import com.mindprod.jtokens.Token;

    /**
    * Renders a string of tokens, usually representing Java source code.
    Does not
    * handle its own scrolling.
    *
    * @author Roedy Green
    * @version 1.0
    */
    public class PrettyCanvas extends Canvas {

    /**
    * true if want extra debug output
    */
    private static final boolean DEBUGGING = false;

    /**
    * has the accelerator to render only necessary tokens kicked in
    yet?
    */
    private boolean accelerated = false;

    /**
    * counts how many bands we have. If there were no blank lines,
    would be
    * same as number of lines. Normally the value is a little less
    that the
    * number of lines since a strip of vertical white space counts as
    one
    * bandCount.
    */
    private int bandCount;

    /**
    * baseline in pixels down from top of canvas that bandCount
    renders on.
    * indexed by bandCount. There will be one entry per non-blank
    line here.
    */
    private int[] baselines;

    /**
    * Dimensions of the scrollable footprint. Start with dummy in
    case we get
    * queried before set called.
    */
    private Dimension dimension = new Dimension( 10, 10 );

    /**
    * first line number to render in a given band.
    */
    private int[] firstLineNumbersInBand;

    /**
    * first token to render in a given band.
    */
    private int[] firstTokensInBand;

    /**
    * true if want lineNumbers
    */
    private boolean hasLineNumbers;

    /**
    * how many pixels wide line numbers are
    */
    private int lineNumberWidth;

    /**
    * top most baseline where we start rendering a bandCount.
    */
    private int startAtBaseline;

    /**
    * 1-based line number to start rendering the current bandCount.
    */
    private int startAtLineNumber;

    /**
    * Array of tokens to render
    */
    private Token[] tokens;

    /**
    * Total lines of text in the entire array of Tokens, which is
    considerably
    * smaller than the total number of tokens.
    */
    private int totalLines;

    /**
    * accelerate rendering by computing just which tokens need to be
    rendered
    * for a given bandCount. Get the index of the first Token
    *
    * @param r
    * clip region to be rendered.
    * @return first token index that needs to be rendered.
    */
    private int firstTokenNeedToRender ( Rectangle r )
    {
    int topOfBand = r.y;
    // pick a baseline just prior to the band for safety.
    int firstBaseline = topOfBand - Geometry.LEADING_IN_PIXELS;
    // home in on a unique 0-based band
    int band = Arrays.binarySearch( baselines, firstBaseline );
    if ( band < 0 )
    {
    // convert insertion point to the band below.
    int insert = -band - 1;
    band = insert - 1;
    band = Math.min( Math.max( 0, band ), bandCount - 1 );
    }
    // As side benefit, we get the startAtBaseline and
    starAtLineNumber
    startAtBaseline = baselines[ band ];
    // startAtLineNumber is 1-based.
    startAtLineNumber = firstLineNumbersInBand[ band ];
    return firstTokensInBand[ band ];
    }

    /**
    * accelerate rendering by computing just which tokens need to be
    rendered
    * for a given bandCount.
    *
    * @param r
    * clip region to be rendered.
    * @return last token index that needs to be rendered.
    */
    private int lastTokenNeedToRender ( Rectangle r )
    {
    int bottomOfBand = r.y + r.height; /* y increases down the
    screen */
    // pick a baseline just after the band for safety.
    // With multiple nls it could be part way through the band,
    but with
    // nothing
    // to render after it.
    int lastBaseline = bottomOfBand + Geometry.LEADING_IN_PIXELS;

    // home in on a unique 0-based band
    int band = Arrays.binarySearch( baselines, lastBaseline );
    if ( band < 0 )
    {
    int insert = -band - 1;
    // with an inexact hit we want the conservative choice the
    band
    // after
    // the insert point.
    band = insert;
    band = Math.min( Math.max( 0, band ), bandCount - 1 );
    }
    if ( band == bandCount - 1 )
    {
    // we are on the last band, render even the very last
    token.
    return tokens.length - 1;
    }
    else
    {
    /*
    * the last token of the band is the token just before the
    token on
    * the start of the next band.
    */
    return firstTokensInBand[ band + 1 ] - 1;
    }
    }

    /**
    * Record where on page we started rendering a given band i.e.
    line with
    * text on it.
    *
    * @param baseline
    * y in of baseline in pixels from the top of canvas.
    * @param lineNumber
    * one-based line number being rendered
    * @param tokenIndex
    * index of first token on the line, including possibly NL
    though
    * normally it would be the last token of the previous
    line.
    */
    private void lineRenderedAt ( int baseline, int lineNumber, int
    tokenIndex )
    {

    baselines[ bandCount ] = baseline;
    firstTokensInBand[ bandCount ] = tokenIndex;
    firstLineNumbersInBand[ bandCount ] = lineNumber;
    bandCount++ ;
    }

    /**
    * Clear binary search arrays used to accelerate rendering by
    finding only
    * those tokens we need to render.
    */
    private void prepareAccelerator1 ()
    {
    if ( tokens == null || tokens.length == 0 ) { return; }
    // these are a little bigger than we need.
    bandCount = 0;
    baselines = new int[ totalLines ];
    firstTokensInBand = new int[ totalLines ];
    firstLineNumbersInBand = new int[ totalLines ];
    // debugging, fill with easy to spot invalid values.
    for ( int i = 0; i < totalLines; i++ )
    {
    baselines[ i ] = -10;
    firstTokensInBand[ i ] = -20;
    firstLineNumbersInBand[ i ] = -30;
    }
    }

    /**
    * Prepare to use the accelerator by trimming its arrays back to
    perfect
    * size. We have collected data on where each band is rendering.
    */
    private void prepareAccelerator2 ()
    {
    // trim arrays back precisely to size so that binary search
    will work.
    int[] old = baselines;
    baselines = new int[ bandCount ];
    System.arraycopy( old, 0, baselines, 0, bandCount );

    old = firstTokensInBand;
    firstTokensInBand = new int[ bandCount ];
    System.arraycopy( old, 0, firstTokensInBand, 0, bandCount );

    old = firstLineNumbersInBand;
    firstLineNumbersInBand = new int[ bandCount ];
    System.arraycopy( old, 0, firstLineNumbersInBand, 0, bandCount
    );

    }

    /**
    * called whenever system has a slice to render
    *
    * @param g
    * Graphics defining where and region to paint.
    */
    public void paint ( Graphics g )
    {
    // No need to call super.paint(); update has already cleared
    the screen.
    Graphics2D g2d = (Graphics2D)g;
    g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
    g2d.setRenderingHint( RenderingHints.KEY_RENDERING,
    RenderingHints.VALUE_RENDER_QUALITY );
    // if wanted to smooth geometric shapes too
    // g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING,
    // RenderingHints.VALUE_ANTIALIAS_ON );

    render( g2d );
    }

    /**
    * does drawing. simiar to logic in Footprint.calcPayloadFootprint
    *
    * @param g
    * where to paint
    */
    public void render ( Graphics2D g )
    {
    // We avoid rendering before or after the clip region.
    // Normally we only render a 4 pixel high band at a time.
    Rectangle r = g.getClipBounds();

    // No need to clear the background of just the clip region
    // because update handles.
    // g.setColor( this.getBackground() );
    // g.fillRect ( r.x, r.y, r.width, r.height );

    // render all the tokens, some may be offscreen, but no
    matter.
    if ( tokens == null || tokens.length == 0 ) { return; }

    // use rendering hints

    // locals
    boolean firstTokenOnLine;
    int firstToRender;
    int lastToRender;
    int x;
    int y;
    int lineNumber;

    if ( accelerated )
    {
    firstToRender = firstTokenNeedToRender( r );
    lastToRender = lastTokenNeedToRender( r );
    x = Geometry.LEFT_MARGIN_IN_PIXELS;
    y = startAtBaseline;
    lineNumber = startAtLineNumber;
    firstTokenOnLine = true;
    }
    else
    {
    prepareAccelerator1();
    firstToRender = 0;
    lastToRender = tokens.length - 1;
    x = Geometry.LEFT_MARGIN_IN_PIXELS;
    y = Geometry.TOP_MARGIN_IN_PIXELS +
    Geometry.LEADING_IN_PIXELS;
    lineNumber = 1;
    firstTokenOnLine = true;
    }
    if ( DEBUGGING )
    {
    System.out.println( "first:"
    + firstToRender
    + " last:"
    + lastToRender
    + " x:"
    + x
    + " ybaseline:"
    + y
    + " r.y:"
    + r.y
    + " r.height:"
    + r.height
    + " ln:"
    + lineNumber );
    }
    for ( int i = firstToRender; i <= lastToRender; i++ )
    {
    Token t = tokens[ i ];
    if ( !accelerated && firstTokenOnLine )
    {
    // capture base line info of this line for the
    accelerator.
    lineRenderedAt( y, lineNumber, i );
    }

    if ( t instanceof NL )
    {
    // render blank lines compressed.
    int lines = ( (NL)t ).getCount();
    switch ( lines )
    {
    case 1 :
    // single space
    y += Geometry.LEADING_IN_PIXELS;
    break;
    case 2 :
    // 1.5 spacing
    y += ( Geometry.LEADING_IN_PIXELS * 15 / 10 );
    break;
    case 3 :
    default :
    // anything bigger, just double space.
    y += ( Geometry.LEADING_IN_PIXELS * 2 );
    break;
    }
    lineNumber += lines; // leave off line numbers, to
    avoid
    // scrunching
    x = Geometry.LEFT_MARGIN_IN_PIXELS;
    firstTokenOnLine = true;
    }
    else
    {
    // text-rendering or space token
    if ( hasLineNumbers && firstTokenOnLine )
    {
    // draw the line number
    g.setColor( Token.getLineNumberForeground() );
    g.setFont( Token.getLineNumberFont() );
    String digits = Integer.toString( lineNumber );
    // right justify
    int width = g.getFontMetrics().stringWidth( digits
    );
    g.drawString( digits, x + lineNumberWidth - width,
    y );
    x += lineNumberWidth
    + Geometry.LINE_NUMBER_MARGIN_IN_PIXELS;
    }
    g.setColor( t.getForeground() );
    g.setFont( t.getFont() );
    String text = t.getText();
    g.drawString( text, x, y );
    x += g.getFontMetrics().stringWidth( text );
    firstTokenOnLine = false;
    } // end else
    } // end for
    // we now have captured all token baselines, even if bandCount
    was tiny.
    if ( !accelerated )
    {
    prepareAccelerator2();
    accelerated = true;
    }

    } // end paint

    /**
    * @param width
    * in pixels of the scrollable region including room for
    line numbers
    * and margins, but not scrollbars.
    * @param height
    * in pixell of the srollable region including room for
    margins, but
    * not scrollbars.
    * @param hasLineNumbers
    * true if want line numbers applied down the left hand
    side.
    * @param lineNumberWidth
    * with of the line number column
    */
    public void set ( int width, int height, boolean hasLineNumbers,
    int lineNumberWidth )

    {
    this.dimension = new Dimension( width, height );
    this.setMinimumSize( dimension );
    this.setPreferredSize( dimension );
    this.setMaximumSize( dimension );
    this.hasLineNumbers = hasLineNumbers;
    this.lineNumberWidth = lineNumberWidth;

    // adding or removing line numbers means new size.
    // caller must setPreferred size
    accelerated = false;
    /*
    * my canvas size has changed, even if only virtual. Warn
    parent
    * container.
    */
    getParent().invalidate();
    }

    /**
    * Set tokens to display
    *
    * @param tokens
    * array of tokens, without lead or trailing NL()
    * @param totalLines
    * number of lines of text to render.
    */
    public void setTokens ( Token[] tokens, int totalLines )
    {
    this.tokens = tokens;
    this.totalLines = totalLines;
    this.accelerated = false;
    }

    /**
    * Constructor
    */
    public PrettyCanvas()
    {
    }

    } // end class PrettyCanvas




    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 5, 2005
    #5
  6. Sameer

    Roedy Green Guest

    On 4 Sep 2005 00:51:32 -0700, "Sameer" <> wrote or
    quoted :

    >A JTextPane is a text component that can be marked up with
    >attributes that are represented graphically.


    check out http://mindprod.com/jgloss/newsgroups.html
    for how to figure out which group to post a given question to.

    You posted everywhere but where I expected to find it,
    comp.lang.java.gui
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Again taking new Java programming contracts.
     
    Roedy Green, Sep 5, 2005
    #6
  7. On Mon, 05 Sep 2005 10:31:56 GMT, Roedy Green wrote:

    > You posted everywhere but where I expected to find it,
    > comp.lang.java.gui


    Ummmm.. no. The OP X-posted (possibly at my prompting
    on an earlier thread[3]) to..
    comp.lang.java.programmer,comp.lang.java.gui,comp.lang.java.help

    Note the middle one - comp.lang.java.gui.

    After the initial post[1], I also asked[2] if they might be
    so kind (and clever) as to figure how to both X-post *and*
    set a 'Follow-Up To' a single group.

    [1]
    <http://groups.google.com/group/comp.lang.java.programmer/browse_frm/thread/7a97a60daeb5803d/542bc4680c7417ea#542bc4680c7417ea>
    [2]
    <http://groups.google.com/groups?selm=190phl1lwcdn3.852opn0ru7i3$>

    [3] It is an effort to cut down on the multi-posting.

    Note Follow-Ups to this post set to c.l.j.gui only..

    --
    Andrew Thompson
    physci.org 1point1c.org javasaver.com lensescapes.com athompson.info
    "We're gonna' fuss and fight till daylight."
    Koko Taylor 'Wang Dang Doodle'
     
    Andrew Thompson, Sep 5, 2005
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sunil
    Replies:
    1
    Views:
    344
    John O'Conner
    Feb 9, 2004
  2. Sameer
    Replies:
    0
    Views:
    500
    Sameer
    Feb 13, 2005
  3. Reny
    Replies:
    2
    Views:
    1,276
    vMike
    Jun 14, 2006
  4. Replies:
    3
    Views:
    375
    Andrew Thompson
    Aug 20, 2007
  5. Replies:
    1
    Views:
    326
    Andrew Thompson
    Aug 20, 2007
Loading...

Share This Page