How to rendering fraction in Swing JComponents

Solution 1:

On reflection, Unicode fractions among the Latin-1 Supplement and Number Forms offer limited coverage, and fancy equations may be overkill. This example uses HTML in Swing Components.

Addendum: The approach shown lends itself fairly well to rendering mixed numbers. For editing, key bindings to + and / could be added for calculator-style input in a text component. I've used org.jscience.mathematics.number.Rational to model rational numbers, and this parser could be adapted to evaluating rational expressions.

HTMLFractions

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/** @see https://stackoverflow.com/questions/7448216 */
public class HTMLFractions extends JPanel {

    private static int N = 8;

    public HTMLFractions() {
        this.setLayout(new GridLayout(N, N, N, N));
        this.setBorder(BorderFactory.createEmptyBorder(N, N, N, N));
        for (int r = 0; r < N; r++) {
            for (int c = 0; c < N; c++) {
                this.add(create(r + N, r + 1, c + 2));
            }
        }
    }

    private JLabel create(int w, int n, int d) {
        StringBuilder sb = new StringBuilder();
        sb.append("<html><body>");
        sb.append(w);
        sb.append("<sup>");
        sb.append(n);
        sb.append("</sup>");
        sb.append("<font size=+1>/<font size=-1>");
        sb.append("<sub>");
        sb.append(d);
        sb.append("</sub>");
        sb.append("</html></body>");
        JLabel label = new JLabel(sb.toString(), JLabel.CENTER);
        label.setBorder(BorderFactory.createLineBorder(Color.lightGray));
        return label;
    }

    private void display() {
        JFrame f = new JFrame("HTMLFractions");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new HTMLFractions().display();
            }
        });
    }
}

Solution 2:

Use the Java2D API. The is an excellent book on it from O'Reilly.

1- Use the font you like. 2- Convert the Glyphs you need (e.g. "2" "/" and "3") into Java2D shapes. 3- Use the Java@d method to scales and place the shapes together

4- This part depends on the component. I think a lot of components take some kind of image instead of text. Convert your shapes into whatever fits into the components you w ant.

5- This should look really professional if you do a good job :)

Come on give me 50!!!

=============

Thanks so much for the points. Here is an example of how to do the first step. It'll show how to get an instance of enter code here Shape from a character in the font of your choice.

Once you have your Shape You can use Graphics2D to create the image you want (scale, compose, etc). All the swing components are different but all have a graphics context. Using the graphics content you can draw on any Swing Component. You can also make transparent layers and stick a transport JPanel over anything you want. If you just want to display a fraction on a label that's easy. If you had some sort of word processor in mind that's hard.

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

public class Utils {

  public static Shape generateShapeFromText(Font font, char ch) {
    return generateShapeFromText(font, String.valueOf(ch));
  }

  public static Shape generateShapeFromText(Font font, String string) {
    BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = img.createGraphics();

    try {
      GlyphVector vect = font.createGlyphVector(g2.getFontRenderContext(), string);
      Shape shape = vect.getOutline(0f, (float) -vect.getVisualBounds().getY());

      return shape;
    } finally {
      g2.dispose();
    }
  }
}

Solution 3:

You can use the approach based on this http://java-sl.com/fraction_view.html

The only difference is positioning subviews for numerator and denominator.

Solution 4:

Unicode has a set of characters that will let you produce fractions without having to do special formatting, e.g., ⁴⁄₉ or ⁵⁶⁄₁₀₀.

You could set up an array of superscript digits, and an array of subscript digits, and convert your numbers to strings of these digits, and then combine them with the fraction slash in between.

Advantages are that it's more general (you can use the code in other contexts), and the result will tend to look better than if you tried to reproduce it using HTML formatting. Of course, you need to have Unicode fonts on your system, but most systems do these days.

A possible implementation in code:

    public String diagonalFraction(int numerator, int denominator) {
    char numeratorDigits[] = new char[]{
            '\u2070','\u00B9','\u00B2','\u00B3','\u2074',
            '\u2075','\u2076','\u2077','\u2078','\u2079'};
    char denominatorDigits[] = new char[]{
            '\u2080','\u2081','\u2082','\u2083','\u2084',
            '\u2085','\u2086','\u2087','\u2088','\u2089'};
    char fractionSlash = '\u2044';

    String numeratorStr = new String();
    while(numerator > 0){
        numeratorStr = numeratorDigits[numerator % 10] + numeratorStr;
        numerator = numerator / 10;
    }
    String denominatorStr = new String();
    while(denominator > 0){
        denominatorStr = denominatorDigits[denominator % 10] + denominatorStr;
        denominator = denominator / 10;
    }   
    return numeratorStr + fractionSlash + denominatorStr;
}

Solution 5:

You would have to find a font that prints fractions in what you're calling nicest form, then write a method to convert the character string of your fraction into the character code of the corresponding nicest form fraction.