概要
AffineTransform
を使用してPath2D
を変換、組み合わせて7
セグメントデジタル時計用の数字を作成します。
Screenshot
Advertisement
サンプルコード
class DigitalNumber {
private final double isosceles;
private final double dx;
private final double dy;
private final double width;
private final double height;
private final Rectangle rect = new Rectangle();
public static final Color OFF = new Color(0xCC_CC_CC);
public static final Color ON = Color.DARK_GRAY;
public static final Color BGC = Color.LIGHT_GRAY;
private final List<Set<Seg>> numbers = Arrays.asList(
EnumSet.of(Seg.A, Seg.B, Seg.C, Seg.D, Seg.E, Seg.F),
EnumSet.of(Seg.B, Seg.C),
EnumSet.of(Seg.A, Seg.B, Seg.D, Seg.E, Seg.G),
EnumSet.of(Seg.A, Seg.B, Seg.C, Seg.D, Seg.G),
EnumSet.of(Seg.B, Seg.C, Seg.F, Seg.G),
EnumSet.of(Seg.A, Seg.C, Seg.D, Seg.F, Seg.G),
EnumSet.of(Seg.A, Seg.C, Seg.D, Seg.E, Seg.F, Seg.G),
EnumSet.of(Seg.A, Seg.B, Seg.C),
EnumSet.of(Seg.A, Seg.B, Seg.C, Seg.D, Seg.E, Seg.F, Seg.G),
EnumSet.of(Seg.A, Seg.B, Seg.C, Seg.D, Seg.F, Seg.G));
private Set<Seg> led = EnumSet.noneOf(Seg.class);
protected DigitalNumber(double dx, double dy, double isosceles) {
this.isosceles = isosceles;
this.dx = dx;
this.dy = dy;
this.width = 2d * isosceles;
this.height = width + isosceles;
rect.setLocation((int) dx, (int) dy);
rect.setSize((int) (width + 3 * isosceles), (int) (height * 2));
}
public Rectangle getBounds() {
return rect;
}
public void setNumber(int num) {
led = numbers.get(num);
}
public void turnOffNumber() {
led.clear();
}
public void drawNumber(Graphics2D g2) {
EnumSet.allOf(Seg.class).forEach(s -> {
g2.setColor(led.contains(s) ? ON : OFF);
Shape seg = s.getShape(dx, dy, width, height, isosceles);
g2.fill(seg);
g2.setColor(BGC);
g2.draw(seg);
});
}
}
View in GitHub: Java, Kotlin解説
- Seven-segment display - Wikipediaのセグメント配置を参考にセグメント
A..G
をenum
で作成enum Seg { A, B, C, D, E, F, G }
EnumSet
を使用して数字に対してどのセグメントが点灯しているかを定義- 例えば数字の
2
はEnumSet.of(Seg.A, Seg.B, Seg.D, Seg.E, Seg.G)
で表現する
- 例えば数字の
- セグメント
F
の下頂点(底辺と高さが2 * isosceles
となる二等辺三角形の頂点)を原点として、Path2D.Double()
で五角形の縦長セグメントを作成private static Path2D vert(double height, double isosceles) { Path2D path = new Path2D.Double(); path.moveTo(0d, 0d); path.lineTo(isosceles, -isosceles); path.lineTo(isosceles, -isosceles - height); path.lineTo(-isosceles, -isosceles - height - isosceles * 2); path.lineTo(-isosceles, -isosceles); path.closePath(); return path; }
- セグメント
E
はセグメントF
を原点の下頂点で上下反転して作成AffineTransform at = AffineTransform.getTranslateInstance(x, y); at.scale(1, -1);
で作成したAffineTransform
を使用しat.createTransformedShape(shapeF)
で変換
- セグメント
B
は、セグメントF
を原点の下頂点で左右反転してセグメントG
の幅だけx
軸方向に移動してを作成AffineTransform at = AffineTransform.getTranslateInstance(x + widthG, y); at.scale(-1, 1);
で作成したAffineTransform
を使用しat.createTransformedShape(shapeF)
で変換
- セグメント
C
は、セグメントF
を原点の下頂点で上下左右を反転してセグメントG
の幅だけx
軸方向に移動してを作成AffineTransform at = AffineTransform.getTranslateInstance(x + widthG, y); at.scale(-1, -1);
で作成したAffineTransform
を使用しat.createTransformedShape(shapeF)
で変換
- セグメント
G
はその左頂点(底辺と高さが2 * isosceles
となる二等辺三角形の頂点)を原点としてPath2D.Double()
で六角形の横長セグメントを作成private static Path2D horiz1(double width, double isosceles) { Path2D path = new Path2D.Double(); path.moveTo(0, 0); path.lineTo(isosceles, isosceles); path.lineTo(isosceles + width, isosceles); path.lineTo(isosceles + width + isosceles, 0); path.lineTo(isosceles + width, -isosceles); path.lineTo(isosceles, -isosceles); path.closePath(); return path; }
- セグメント
A
は上辺が下辺より3 * isosceles
長くなる等脚台形をPath2D.Double()
で作成し、セグメントF
の高さだけy
軸方向に移動、原点は左右の辺の中心に設定private static Path2D horiz2(double width, double isosceles) { Path2D path = new Path2D.Double(); path.moveTo(isosceles, isosceles); path.lineTo(isosceles + width, isosceles); path.lineTo(3 * isosceles + width, -isosceles); path.lineTo(-isosceles, -isosceles); path.closePath(); return path; }
- セグメント
D
はセグメントA
を上下反転してセグメントF
の高さだけy
軸方向に移動して作成AffineTransform at = AffineTransform.getTranslateInstance(x, y + heightF); at.scale(1, -1);
で作成したAffineTransform
を使用しat.createTransformedShape(shapeA)
で変換
DigitalNumber
を6
個配置して24
時間表記のデジタル時計を作成- 時間と分の区切りドットは
250
ミリ秒で点滅するようTimer
で設定 - 各セグメント間の隙間は
BasicStroke
を設定してPath2D
を線描することで表現 - 時計全体を
g2.shear(-.1, 0d);
でシャーリング変換してイタリック風に表示 - 時計全体が
JPanel
に収まるよう以下のようなスケールを設定double sv = getWidth() / (h1.getBounds().width * 8d); g2.scale(sv, sv);
参考リンク
- Seven-segment display - Wikipedia
- Java Digital Clock - YouTube
- Seven Segments Display in Java | Java Programming
- Swing Apollo space program mission timer | Java User Group Münster
- Shapeの反転
- AffineTransformを使用してアナログ時計の文字盤に数字を配置する
- JListでドットマトリクスLEDデジタル時計を作成する