Graphics2D transformation

Hi, friends,

I have to realize such a “styled” label that we could make its text bold, widened or/and heightened. I thought it possible by utilizing Graphics2D transformation, however I have really little knowledge about G2D programming. Below pasted is my source code. I found that the “widened” property works as my expection while the “heightened” property acts strangely. Please take some look at it and tell me: Am I on the right way? If not, what’s the best solution?

Thanks!

Earl


package cn.com.szaoto.aq.util.ticket.ui;

import javax.swing.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

public class StyledLabel
    extends JLabel {
  private static final Color NORMAL_BG = Color.WHITE;
  private static final Color NORMAL_FG = Color.BLACK;
  private static final Color HIGHLIGHT_BG = Color.BLUE;
  private static final Color HIGHLIGHT_FG = Color.WHITE;

  private boolean widened, heightened;

  public StyledLabel(String text) {
    super(text);
    setOpaque(true);
  }

  public boolean isBold() {
    return getFont().isBold();
  }

  public void setBold(boolean bold) {
    Font f1 = getFont();
    Font f2 = new Font(f1.getFamily(), bold ? Font.BOLD : Font.PLAIN,
                       f1.getSize());
    setFont(f2);
  }

  public boolean isHighlighted() {
    return getBackground().equals(HIGHLIGHT_BG) &&
        getForeground().equals(HIGHLIGHT_FG);
  }
  
  public void setHighlighted(boolean highlighted)
  {
    Color bg= highlighted? HIGHLIGHT_BG: NORMAL_BG;
    Color fg= highlighted? HIGHLIGHT_FG: NORMAL_FG;
    setBackground(bg);
    setForeground(fg);
  }
  
  public boolean isWidened()
  {
    return widened;
  }
  
  public void setWidened(boolean widened)
  {
    this.widened= widened;
  }
  
  public boolean isHeightened()
  {
    return heightened;
  }
  
  public void setHeightened(boolean heightened)
  {
    this.heightened= heightened;
  }

  public Dimension getPreferredSize() {
    Dimension dim= super.getPreferredSize();
    if(widened)
    {
      dim.width= dim.width * 2;
    }
    
    if(heightened)
    {
      dim.height= dim.height  *2;
    }
    
    return dim;
  }

  protected void paintComponent(Graphics g) {
    Graphics2D g2d= (Graphics2D) g;
    double scaleX= widened? 2 : 1;
    double scaleY = heightened? 2 : 1;
    
    g2d.scale(scaleX, scaleY);
    super.paintComponent(g2d);
  }
}

The reason that the label in heightened renders wrong is because all the coordinates are
multiplied by 2 as well :slight_smile: So to compensate you need to translate half the height up, then
scale, then render the component internals, scale back and translate back. The last two are
needed if you want to properly render borders and other decorators of the swing component.


      protected void paintComponent(Graphics g) {
        Graphics2D g2d= (Graphics2D) g;
        double scaleX= widened? 2 : 1;
        double scaleY = heightened? 2 : 1;
        //
        if (heightened) g2d.translate(0,-getHeight()/2);
        g2d.scale(scaleX, scaleY);
        //
        super.paintComponent(g2d);
        //
        g2d.scale(1/scaleX, 1/scaleY);      
        if (heightened) g2d.translate(0,getHeight()/2);
      }

This is quite a hackish solution on top of a JLabel (but, it works! :slight_smile:
Maybe a better solution is do your own custom rendering using a JPanel or JComponent.

Have fun !

Erik