How to rendering fraction in Swing JComponents
Asked Answered
C

6

16

Basically Swing JComponents are able to display numbers in fractions in this form 2 2/3. How can I paint fraction in the nicest form, for example 2⅔?

.

EDIT

.

as see I have only one way JTable inside JSpinner with one TableColumn and TableRow (that could simulated plain JtextField too), where TableRenderer could be some of JTextComponent formatted by using Html and on TableCellEdit event the TableEditor to swith to the plain JFormattedTextField,

is there another way, could it be possible with plain J(Formatted)TextField too ???

Cattleya answered 16/9, 2011 at 17:14 Comment(9)
Can you elaborate on what additional details would be helpful?Dimaggio
??? I'm sure ??? that must be possible to set the Format to the JSpinner or JFormattedTextField, because I saw Java GUI with bigger blue and bolder numbers before decimal separator, as on red and smaler on another decimal possitions, that look very nice, same as I asked in my questionCattleya
Ah, perhaps a custom component used in market trading. Thanks for clarifying. Sorry, I don't have much experience in that regard.Dimaggio
Do you want the fractional part displayed as a Unicode fraction character exactly like in your post, or was that just an example of what you want it to look like? Using fraction characters it would be difficult to make the JFormattedTextField editable with a keyboard, although a JSpinner would work pretty much as expected. Fraction characters would also limit you to a small set of predefined fractions. The alternative would be to draw the solidus (fraction bar) and various bits of text manually in a custom-painted component.Decoupage
@Sam Hanes answer is what I want it to look like, sure there is idea with Font size > 28, I can't problem split that to the two JFormattedTextField chained together by DocumentListener, but in my question I trying to avoid that :-)Cattleya
Do you specifically need a JFormattedTextField, or do you just need a text input component that's compatible with JSpinner and standalone display and editing? It's very difficult to do with a JFormattedTextField, but it should be achievable with a custom JTextComponent.Decoupage
yes that's about idea, fortuna or solved that beforeCattleya
@Cattleya Sorry, does that mean you do or do not require a JFormattedTextField?Decoupage
I think that doesn't matter, because if your idea works for plain vanilla JTextComponent by using Caret + HighLighter + Formatter, then must be customizable for JTextField or JFormattedTextField same wayCattleya
D
23

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();
            }
        });
    }
}
Dimaggio answered 17/9, 2011 at 2:40 Comment(8)
now I really no idea how to solve, nothing just bothering how to swith/split input mask and formatting display for plain TextComponents..., +1Cattleya
I haven't seen a light-weight, open-source solution, but I've suggested an approach above.Dimaggio
hmmm open-source solution I have aroung me a few solutions for reall MarketTrading & Margining, any from them non-open-source solution and non-solving for Trades InputMasks, for built-in view is situations little bit different (including formulas), but not is so nice as I copied from your post 2⅔Cattleya
One problem you may have, from using HTML in JLabel is the loss of baseline alignment on LayoutManager that support it (OTOH, GroupLayout, MigLayout, DesignGridLayout there are probably others...) Not sure if that would be that important in your use case though.Normandnormandy
@jfpoilpret: I would encourage you to expand on this aspect of the problem in a new answer.Dimaggio
@Dimaggio can't post another answer because I don't have any better answer ;-) I just wanted to point out this issue, that occurs whenever one uses HTML in Swing components, but I've got nothing better to propose.Normandnormandy
@Dimaggio thank you for your post, this one was best one, but I'm going to the JTable way, TableRenderer to display/contains the different JComponents as TableEditorCattleya
@mKorbel: I agree. There are several good options for rendering, but editing remains difficult. JTable supports both, and JSpinner is an archetypal composite component with its own layout manager.Dimaggio
F
5

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();
    }
  }
}
Francyne answered 10/10, 2011 at 5:2 Comment(7)
"Come on give me 50!!!" Bounties can be awarded once, in whole. It is 'all or nothing'. But I'll toss you 10. ;)Weston
@Andrew Thompson :-) why not, I gave 250, good joke, isn't itCattleya
@Glen P this non-sence deserves my Bounty in 250Cattleya
Looks like Glen P. lucked out on this one. ;)Weston
@Andrew Thompson not s/he goings around for give me 50, and I hope that then I never see her/him here (positive negativism), and looks like what's miracleCattleya
+1 for Graphics2D, which affords the greatest control over rendering. For editing, I'd look at a composite of existing components with a custom layout manager.Dimaggio
@Glen P: Now that you can vote, I urge you to examine the poster's many contributions. They are occasionally malapropos but always insightful.Dimaggio
A
5

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.

Arlettaarlette answered 11/10, 2011 at 5:35 Comment(0)
D
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;
}
Disseminate answered 12/10, 2011 at 12:21 Comment(1)
See also Superscripts and Subscripts.Dimaggio
H
3

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.

Harmonize answered 16/9, 2011 at 17:24 Comment(3)
+1 for a good rendering idea. I'm less sanguine about installing special fonts. Can you elaborate on the practicality?Dimaggio
@trashgod: I started Microsoft Word, and looked at the symbol table for the Times New Roman font. The fractions 1/3 (character code x'2153'), 2/3 (x'2154'), 1/8 (x'215B'), 3/8 (x'215C'), 5/8 (x'215D'), and 7/8 (x'215E') have character codes. 1/4 (x'00BC'), 1/2 (x'00BD'), and 3/4 (x'00BE') have character codes. If you just need fractions of an eighth, than this method could work.Harmonize
Ah, I can see glyphs for these code-points on Mac using the FontBook application.Dimaggio
F
2

Special fonts method:

The special fonts method might be a really good solution too.

You are going to need a good font editor.

Create ten numbers just for the top number of the fraction, a special slash or line symbol for the middle, and ten numbers just for bottom digits.

The only problem is that it's got to look good and that requires that the spacing of the top/slash/and button all close to together, actually overlapping horizontally. The good news is fonts support this, and a good font editor will. The swing text components probably don't. You need to write your own text component of find a component that already lets you fine position the fonts. This is the different between test editing/ word processing and text typography.

But I also have another idea :)

You could do fractions with a horizontal bar instead of a diagonal slash.

123
---
456

This way font need not overlap and can be laid out by the editor in the standard way. The trick is to have the above be three characters next to each other.

1 2 3
- - -
4 5 6

So that's one hundred different characters you need for all combinations.

The only problem with this (in addition to having to create 100 characters) is if you have and odd number of digits in the top and even in the bottom or vise verse it will look like this:

 12
---
456
Francyne answered 11/10, 2011 at 7:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.