Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / August 2006

Tip: Looking for answers? Try searching our database.

Why does AffineTransform not work on JTextPane?

Thread view: 
fiziwig - 10 Aug 2006 18:20 GMT
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);
   }
}
Oliver Wong - 10 Aug 2006 19:29 GMT
>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
[quoted text clipped - 12 lines]
> 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
fiziwig - 10 Aug 2006 19:44 GMT
> "fiziwig" <fiziwig@yahoo.com> 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
[quoted text clipped - 6 lines]
>
>     - 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
Oliver Wong - 10 Aug 2006 19:54 GMT
>> "fiziwig" <fiziwig@yahoo.com> wrote in message
>
[quoted text clipped - 16 lines]
> 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
fiziwig - 10 Aug 2006 20:04 GMT
> >> "fiziwig" <fiziwig@yahoo.com> 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
Oliver Wong - 10 Aug 2006 20:58 GMT
> 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
fiziwig - 10 Aug 2006 21:52 GMT
> > I'll look into the screen cap approach. If I can figure out how to do a
> > screen cap, that is. ;-)
[quoted text clipped - 3 lines]
>
>     - 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
Thomas Weidenfeller - 11 Aug 2006 09:42 GMT
>     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.

/Thomas
Signature

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/

Alex Hunsley - 12 Aug 2006 03:14 GMT
>>     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?
jmcgill - 12 Aug 2006 15:25 GMT
>>>     public void paintComponent(Graphics g) {
>>
[quoted text clipped - 3 lines]
>
> 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/
Thomas Weidenfeller - 14 Aug 2006 09:51 GMT
>>>     public void paintComponent(Graphics g) {
>>
[quoted text clipped - 3 lines]
>
> 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
Signature

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/



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.