tags:

views:

1462

answers:

2

I am currently trying to implement a Swing component, inheriting from JLabel which should simply represent a label that can be oriented vertically.

Beginning with this:

public class RotatedLabel extends JLabel {

  public enum Direction {
    HORIZONTAL,
    VERTICAL_UP,
    VERTICAL_DOWN
  }

  private Direction direction;

I thought it's be a nice idea to just alter the results from getPreferredSize():

  @Override
  public Dimension getPreferredSize() {
    // swap size for vertical alignments
    switch (getDirection()) {
    case VERTICAL_UP:
    case VERTICAL_DOWN:
      return new Dimension(super.getPreferredSize().height, super
          .getPreferredSize().width);
    default:
      return super.getPreferredSize();
    }
  }

and then simply transform the Graphics object before I offload painting to the original JLabel:

  @Override
  protected void paintComponent(Graphics g) {
    Graphics2D gr = (Graphics2D) g.create();

    switch (getDirection()) {
    case VERTICAL_UP:
      gr.translate0, getPreferredSize().getHeight());
      gr.transform(AffineTransform.getQuadrantRotateInstance(-1));
      break;
    case VERTICAL_DOWN:
      // TODO
      break;
    default:
    }

    super.paintComponent(gr);
  }
}

It seems to work—somehow—in that the text is now displayed vertically. However, placement and size are off:

Actually, the width of the background (orange in this case) is identical with the height of the surrounding JFrame which is ... not quite what I had in mind.

Any ideas how to solve that in a proper way? Is delegating rendering to superclasses even encouraged?

A: 

I think it is off because you are translating about the wrong point.

the size of the object depends on what container you have this in, so while your preferred size might be what you want, your actual size isn't?

if you have this label in the CENTER of a BorderLayout, the size is always the full size of the container (minus north+south height, minus east+west width)

so don't you have to translate about the actual size, not preferred size?

John Gardner
Hmm ... not ... quite. Placement is a little off because the label's vertical (now horizontal) alignment is centered, but the size is now exactly square. Could it be that the superclass doesn't care about my overridden getPreferredSize method and thus draws itself not in respect to my boundaries?
Joey
+1  A: 

I got it to work now with a little help of a coworker. Basically I now have a field that indicates whether to swap height/width which is only active for the time when the original JLabel does its painting.

private boolean needsRotate;

@Override
public Dimension getSize() {
  if (!needsRotate) {
    return super.getSize();
  }

  Dimension size = super.getSize();

  switch (getDirection()) {
  case VERTICAL_DOWN:
  case VERTICAL_UP:
      return new Dimension(size.height, size.width);
  default:
    return super.getSize();
  }
}

@Override
public int getHeight() {
  return getSize().height;
}

@Override
public int getWidth() {
  return getSize().width;
}

@Override
protected void paintComponent(Graphics g) {
  Graphics2D gr = (Graphics2D) g.create();

  switch (getDirection()) {
  case VERTICAL_UP:
    gr.translate(0, getSize().getHeight());
    gr.transform(AffineTransform.getQuadrantRotateInstance(-1));
    break;
  case VERTICAL_DOWN:
    gr.transform(AffineTransform.getQuadrantRotateInstance(1));
    gr.translate(0, -getSize().getWidth());
    break;
  default:
  }

  needsRotate = true;
  super.paintComponent(gr);
  needsRotate = false;
}
Joey
Could you provide the full class?
Mike Caron
See http://hypftier.de/dump/RotatedLabel.java – the license mentioned is a pretty liberal one, modeled after the BSD (though the license text is only available in German so far).
Joey