Why does AffineTransform not work on JTextPane?

Discussion in 'Java' started by fiziwig, Aug 10, 2006.

  1. fiziwig

    fiziwig Guest

    I can rotate every other type of component I've tried, but when I
    rotate a JTextPane by 90 or 180 degrees (which I REALLY need for my
    customer's application) The clipping and bordering get all messed up
    and I'm at my wit's end trying to make it work.

    Am I doing something wrong, or is there a Java bug in applying a
    transform to a JTextPane? The same basic code works on a JLabel, why
    won't it work on a JTextPane?

    Any ideas or suggestions would be deeply appreciated.

    OR any ideas for a different way to display STYLED text (font, size,
    color, bold, italic on a character-by-character basis) at a 90 or 180
    degree rotation. It doesn't have to be editable when rotated, but it
    does need to be editable when upright, otherwise I'd just use HTML in a
    JLabel.

    Thanks,

    --gary

    Compilable example:


    import javax.swing.*;
    import javax.swing.text.*;
    import javax.swing.border.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import java.awt.image.*;

    public class Rotate extends JPanel {

    private TextPanel textPane;
    private JLayeredPane parent;

    public Rotate() {

    setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
    JToolBar toolBar = buildToolbar();
    add(toolBar);

    parent = new JLayeredPane();
    add(parent);
    parent.setBackground( Color.gray);
    parent.setPreferredSize(new Dimension(640, 480));

    // Create a text pane.

    textPane = new TextPanel();
    StyledDocument doc = textPane.getStyledDocument();
    try {
    doc.insertString(doc.getLength(), "This is some sample
    text.\nIt can be Rotated.", null);
    }
    catch (BadLocationException ble) {
    System.err.println("Couldn't insert initial text into text
    pane.");
    }
    Border myBorder = BorderFactory.createLineBorder( Color.red );
    textPane.setBorder(myBorder);
    parent.setOpaque(true);
    parent.add(textPane);
    textPane.setDefaultBounds(120, 120, 240, 120);
    }
    private JToolBar buildToolbar() {

    JToolBar toolBar = new JToolBar();
    toolBar.setRollover( true );
    toolBar.setFloatable( false );
    JButton rotateButton = new JButton("Rotate");
    rotateButton.setToolTipText( "Rotate text editing pane" );
    rotateButton.addActionListener( new ActionListener() {
    public void actionPerformed( ActionEvent e ) {
    textPane.setRotation(textPane.getRotation()+1);
    }
    });
    toolBar.add( rotateButton );
    return toolBar;
    }
    private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);

    //Create and set up the window.
    JFrame frame = new JFrame("Rotate");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Create and set up the content pane.
    JComponent newContentPane = new Rotate();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
    }

    public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
    public void run() {
    createAndShowGUI();
    }
    });
    }

    }

    class TextPanel extends JTextPane {

    // implements rotation for a JTextPane

    private int rotation;
    private int tx, ty;
    private int wide, high;

    // valid rotation values are:
    // 0 = no rotation
    // 1 = rotation 90 degree clockwise
    // 2 = rotation 180 degrees
    // 3 = rotation 90 degrees counterclockwise

    TextPanel() {
    super();
    rotation = 0;
    tx = 0;
    ty = 0;
    }
    public void setDefaultBounds( int x, int y, int width, int height)
    {
    high = height;
    wide = width;
    super.setBounds(x,y,width,height);
    }
    public void setRotation( int newRotation ) {
    rotation = newRotation % 4;

    if ((rotation%2)==0) {
    setSize(wide,high);
    } else {
    setSize(high,wide);
    }
    switch (rotation) {
    case 0 : tx = 0; ty = 0; break;
    case 1 : tx = 1; ty = 0; break;
    case 2 : tx = 1; ty = 1; break;
    case 3 : tx = 0; ty = 1; break;
    }
    repaint();
    }
    public int getRotation() { return rotation; }

    public void paintComponent(Graphics g) {

    Graphics2D g2 = (Graphics2D) g;
    double angle = rotation * Math.PI/2;
    AffineTransform tr = g2.getTransform();
    int h,w;
    if ((rotation%2) == 0) {
    w = wide;
    h = high;
    } else {
    h = wide;
    w = high;
    }

    tr.setToTranslation(getWidth()*tx,getHeight()*ty);
    tr.rotate(angle);
    g2.setTransform(tr); // <----- comment this line out to see
    correct borders
    super.paintComponent(g2);
    }
    }
     
    fiziwig, Aug 10, 2006
    #1
    1. Advertising

  2. fiziwig

    Oliver Wong Guest

    "fiziwig" <> wrote in message
    news:...
    >I can rotate every other type of component I've tried, but when I
    > rotate a JTextPane by 90 or 180 degrees (which I REALLY need for my
    > customer's application) The clipping and bordering get all messed up
    > and I'm at my wit's end trying to make it work.
    >
    > Am I doing something wrong, or is there a Java bug in applying a
    > transform to a JTextPane? The same basic code works on a JLabel, why
    > won't it work on a JTextPane?
    >
    > Any ideas or suggestions would be deeply appreciated.
    >
    > OR any ideas for a different way to display STYLED text (font, size,
    > color, bold, italic on a character-by-character basis) at a 90 or 180
    > degree rotation. It doesn't have to be editable when rotated, but it
    > does need to be editable when upright, otherwise I'd just use HTML in a
    > JLabel.


    How about using a JTextPane for editing, and when editing is done, copy
    the contents and put it into a JLabel, and rotate the JLabel?

    - Oliver
     
    Oliver Wong, Aug 10, 2006
    #2
    1. Advertising

  3. fiziwig

    fiziwig Guest

    Oliver Wong wrote:
    > "fiziwig" <> wrote in message


    <snip>

    > > OR any ideas for a different way to display STYLED text (font, size,
    > > color, bold, italic on a character-by-character basis) at a 90 or 180
    > > degree rotation. It doesn't have to be editable when rotated, but it
    > > does need to be editable when upright, otherwise I'd just use HTML in a
    > > JLabel.

    >
    > How about using a JTextPane for editing, and when editing is done, copy
    > the contents and put it into a JLabel, and rotate the JLabel?
    >
    > - Oliver


    That might work. The problem is then I have to go through the text
    character by character pulling out the attributes (font, size, color,
    bold, italic,...) and turning those into HTML tags so that they will
    display properly in the JLabel. Then when the user selects the text for
    editing again I have to turn around and parse out all the HTML tags and
    build it back into a styled document.

    This would be soooo easy in C++/Windows, but Java makes the hard things
    easy by making the easy things hard, by keeping some very important
    things hidden and inaccessable. That's great most of the time, but it's
    a major pain in the neck at other times. It's like trying to build a
    geodesic dome with Lincoln logs. The Java Lincoln logs are great as
    long as you're building their kind of rectalinear log-cabin-type stuff,
    but to build anything unconventional, like round or octagonal, you're
    flat out of luck.

    --gary
     
    fiziwig, Aug 10, 2006
    #3
  4. fiziwig

    Oliver Wong Guest

    "fiziwig" <> wrote in message
    news:...
    >
    > Oliver Wong wrote:
    >> "fiziwig" <> wrote in message

    >
    > <snip>
    >
    >> > OR any ideas for a different way to display STYLED text (font, size,
    >> > color, bold, italic on a character-by-character basis) at a 90 or 180
    >> > degree rotation. It doesn't have to be editable when rotated, but it
    >> > does need to be editable when upright, otherwise I'd just use HTML in a
    >> > JLabel.

    >>
    >> How about using a JTextPane for editing, and when editing is done,
    >> copy
    >> the contents and put it into a JLabel, and rotate the JLabel?
    >>

    >
    > That might work. The problem is then I have to go through the text
    > character by character pulling out the attributes (font, size, color,
    > bold, italic,...) and turning those into HTML tags so that they will
    > display properly in the JLabel. Then when the user selects the text for
    > editing again I have to turn around and parse out all the HTML tags and
    > build it back into a styled document.


    Or you could have a central "model" object which semantically preserves
    all the information you need in your document, and generate HTML like views
    for the Label, and the character-style like view and editor for the
    JTextPane.

    Another thing you could try is, once the user has finished editing
    everything, taking a screen capture of the JTextPane, and then rotating that
    image, and displaying it.

    - Oliver
     
    Oliver Wong, Aug 10, 2006
    #4
  5. fiziwig

    fiziwig Guest

    Oliver Wong wrote:
    > "fiziwig" <> wrote in message
    > news:...
    > >
    > > Oliver Wong wrote:
    > >> "fiziwig" <> wrote in message

    > >


    <snip>

    >
    > Another thing you could try is, once the user has finished editing
    > everything, taking a screen capture of the JTextPane, and then rotating that
    > image, and displaying it.
    >
    > - Oliver


    The screen cap idea is a good one. That would be perfectly suitable.
    This is a page layout program for a customer who is a printer and he
    needs to be able to turn blocks of text on their side or upside down in
    doing multi-page layouts on a single very large sheet of paper. There
    can be literally dozens of separate JTextPanes in a single document.

    I'll look into the screen cap approach. If I can figure out how to do a
    screen cap, that is. ;-)

    Thanks,

    --gary
     
    fiziwig, Aug 10, 2006
    #5
  6. fiziwig

    Oliver Wong Guest

    Oliver Wong, Aug 10, 2006
    #6
  7. fiziwig

    fiziwig Guest

    Oliver Wong wrote:
    > "fiziwig" <> wrote in message
    > news:...
    > >
    > > I'll look into the screen cap approach. If I can figure out how to do a
    > > screen cap, that is. ;-)

    >
    > See
    > http://java.sun.com/products/java-media/jai/forDevelopers/jaifaq.html#displaybmp
    >
    > - Oliver


    Thanks for all your help. After days and days of pulling my hair out,
    the rotation finally works perfectly. Here's how I ended up doing it:

    class TextPanel extends JTextPane {

    // implements rotation for a JTextPane

    private int rotation;
    private int tx, ty;
    private int wide, high;
    private BufferedImage renderedText = null;

    // valid rotation values are:
    // 0 = no rotation
    // 1 = rotation 90 degree clockwise
    // 2 = rotation 180 degrees
    // 3 = rotation 90 degrees counterclockwise

    TextPanel() {
    super();
    rotation = 0;
    tx = 0;
    ty = 0;
    }
    public void setDefaultBounds( int x, int y, int width, int height)
    {
    high = height;
    wide = width;
    super.setBounds(x,y,width,height);
    }
    public void setRotation( int newRotation ) {

    newRotation = newRotation % 4;
    if ( rotation != newRotation ) {
    switch (newRotation) {
    case 0 : tx = 0; ty = 0; break;
    case 1 : tx = 1; ty = 0; break;
    case 2 : tx = 1; ty = 1; break;
    case 3 : tx = 0; ty = 1; break;
    }
    if ( newRotation != 0 ) {
    if ( renderedText==null) {
    rotation = 0; // so that text is actually rendered
    renderedText = new BufferedImage(wide, high,
    BufferedImage.TYPE_INT_RGB);
    Graphics2D g2D = renderedText.createGraphics();
    paint( g2D );
    }
    }
    rotation = newRotation; // so the repaint will paint the
    rendered image
    if ((rotation%2)==0) {
    setSize(wide,high);
    } else {
    setSize(high,wide);
    }

    repaint();
    }
    }
    public int getRotation() { return rotation; }

    public void paintComponent(Graphics g) {

    if ( rotation == 0 ) {
    super.paintComponent(g);
    return;
    }
    Graphics2D g2 = (Graphics2D) g;
    double angle = rotation * Math.PI/2;
    AffineTransform tr = g2.getTransform();
    if (rotation==2) {
    tr.setToTranslation(wide*tx,high*ty);
    } else {
    tr.setToTranslation(high*tx,wide*ty);
    }
    tr.rotate(angle);
    g2.drawImage(renderedText, tr, this);
    }
    }

    --gary
     
    fiziwig, Aug 10, 2006
    #7
  8. Thomas Weidenfeller, Aug 11, 2006
    #8
  9. fiziwig

    Alex Hunsley Guest

    Thomas Weidenfeller wrote:
    > fiziwig wrote:
    >
    >> public void paintComponent(Graphics g) {

    >
    > Override paint(), not paintComponent() but before you do so, familiarize
    > yourself with the way paint() in Swing works. There is a TSC painting
    > article about this.


    Why do you suggest doing this?
     
    Alex Hunsley, Aug 12, 2006
    #9
  10. fiziwig

    jmcgill Guest

    Alex Hunsley wrote:
    > Thomas Weidenfeller wrote:
    >> fiziwig wrote:
    >>
    >>> public void paintComponent(Graphics g) {

    >>
    >> Override paint(), not paintComponent() but before you do so,
    >> familiarize yourself with the way paint() in Swing works. There is a
    >> TSC painting article about this.

    >
    > Why do you suggest doing this?
    >


    I'm not convinced that's exactly what this article is saying. Maybe the
    OP has another TSC painting article in mind, or maybe I'm not reading
    this well.

    http://java.sun.com/products/jfc/tsc/articles/painting/
     
    jmcgill, Aug 12, 2006
    #10
  11. Alex Hunsley wrote:
    > Thomas Weidenfeller wrote:
    >> fiziwig wrote:
    >>
    >>> public void paintComponent(Graphics g) {

    >>
    >> Override paint(), not paintComponent() but before you do so,
    >> familiarize yourself with the way paint() in Swing works. There is a
    >> TSC painting article about this.

    >
    > Why do you suggest doing this?
    >


    Reading the documentation? Because it helps to know how things work.

    Overriding paint()? Because it makes sense in this particular case.

    paint() calls paintComponent(), paintBorder() and paintChildren(). If
    you want to rotate a component it makes sense to also rotate its border
    and potential children. Manipulating the Graphics context in paint()
    would mean you can affect all three activities in a controlled way:
    Change it and then call super.paint(g).

    On the other hand, manipulating the Graphics context in
    paintComponent(), and not reseting it at the end of the method, means
    you are relying on a particular sequence of method invocations in
    paint(). You are betting on an implementation detail.

    /Thomas
    --
    The comp.lang.java.gui FAQ:
    ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq
    http://www.uni-giessen.de/faq/archiv/computer-lang.java.gui.faq/
     
    Thomas Weidenfeller, Aug 14, 2006
    #11
    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. Rick
    Replies:
    2
    Views:
    764
    Thomas Weidenfeller
    Oct 8, 2003
  2. Adam
    Replies:
    0
    Views:
    453
  3. hilz
    Replies:
    2
    Views:
    1,304
  4. SPG
    Replies:
    0
    Views:
    373
  5. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,071
    Smokey Grindel
    Dec 2, 2006
Loading...

Share This Page