'Fill' caractères Unicode dans les étiquettes

Comment 'remplir' les caractères Unicode dans les étiquettes en Swing?

j'essaie de faire une interface utilisateur pour le programme d'Échecs que j'ai récemment programmé (avec des pièces d'Échecs quelque chose comme vu ci-dessus). J'utilise des caractères unicode pour représenter mes pièces d'Échecs ( u2654 à u265F ).

le problème est le suivant:

quand j'ai placé le fond de mon pièce d'Échecs JLabel pour quelque chose comme blanc, l'étiquette entière est remplie (dans mon cas, c'est un carré de 50*50px de blanc avec le caractère sur le dessus). Cela conduit à mes pièces qui ressemblent à des tuiles au lieu de seulement leurs photos.

quand je mets l'étiquette à opaque, je reçois juste une version de mon jeu d'Échecs, pas une avec ses entrailles remplies. E. G.

Actual result

est-il un moyen de remplir seulement le personnage?

si ce n'est pas le cas je pense que je vais faire une feuille de sprite mais j'aime cela parce que je peux utiliser les pièces d'Échecs' toString() méthodes pour les étiquettes.

Code

import java.awt.*;
import javax.swing.*;
import java.util.Random;

class ChessBoard {

    static Font font = new Font("Sans-Serif", Font.PLAIN, 50);
    static Random rnd = new Random();

    public static void addUnicodeCharToContainer(
        String s, Container c, boolean randomColor) {

        JLabel l = new JLabel(s);
        l.setFont(font);
        if (randomColor) {
            int r = rnd.nextInt(255);
            int g = rnd.nextInt(255);
            int b = rnd.nextInt(255);

            l.setForeground(new Color(r,g,b));
            l.setBackground(new Color(255-r,255-g,255-b));
            l.setOpaque(true);
        }
        c.add(l);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new GridLayout(0,6,4,4));

                String[] pieces = {
                    "u2654","u2655","u2656","u2657","u2658","u2659",
                    "u265A","u265B","u265C","u265D","u265E","u265F"
                };

                for (String piece : pieces) {
                    addUnicodeCharToContainer(piece,gui,false);
                }
                for (String piece : pieces) {
                    addUnicodeCharToContainer(piece,gui,true);
                }

                JOptionPane.showMessageDialog(null, gui);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
11
demandé sur Andrew Thompson 2013-09-08 20:48:57

3 réponses

Chess Pieces

les deux lignes sont générées par la sorcellerie de Java-2D. L'astuce est de:

  • ignorez les pièces d'Échecs "noires" sur la base que notre couleur provient en fait des "espaces contenus par la forme". Ceux-là sont plus grands dans les pièces d'Échecs blanches.
  • Créer un GlyphVector qui représente la forme du personnage. Ceci est important pour les opérations futures dans Java-2D.
  • Créer un Rectangle la taille de l'image.
  • subtract() la forme du caractère à partir de la forme de l'image.
  • cassez cette forme altérée en régions.
  • remplir les régions avec la couleur de fond, mais passer la région unique qui commence à 0,0, 0,0 (représentant la région ultrapériphérique que nous besoin de transparence).
  • enfin, remplissez la forme du caractère lui-même en utilisant la couleur de contour.

Code

import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.util.*;

class ChessBoard {

    static Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 50);
    static Random rnd = new Random();

    public static ArrayList<Shape> separateShapeIntoRegions(Shape shape) {
        ArrayList<Shape> regions = new ArrayList<Shape>();

        PathIterator pi = shape.getPathIterator(null);
        int ii = 0;
        GeneralPath gp = new GeneralPath();
        while (!pi.isDone()) {
            double[] coords = new double[6];
            int pathSegmentType = pi.currentSegment(coords);
            int windingRule = pi.getWindingRule();
            gp.setWindingRule(windingRule);
            if (pathSegmentType == PathIterator.SEG_MOVETO) {
                gp = new GeneralPath();
                gp.setWindingRule(windingRule);
                gp.moveTo(coords[0], coords[1]);
                System.out.println(ii++ + " \t" + coords[0] + "," + coords[1]);
            } else if (pathSegmentType == PathIterator.SEG_LINETO) {
                gp.lineTo(coords[0], coords[1]);
            } else if (pathSegmentType == PathIterator.SEG_QUADTO) {
                gp.quadTo(coords[0], coords[1], coords[2], coords[3]);
            } else if (pathSegmentType == PathIterator.SEG_CUBICTO) {
                gp.curveTo(
                        coords[0], coords[1],
                        coords[2], coords[3],
                        coords[4], coords[5]);
            } else if (pathSegmentType == PathIterator.SEG_CLOSE) {
                gp.closePath();
                regions.add(new Area(gp));
            } else {
                System.err.println("Unexpected value! " + pathSegmentType);
            }

            pi.next();
        }

        return regions;
    }

    public static void addColoredUnicodeCharToContainer(
            String s, Container c,
            Color bgColor, Color outlineColor, boolean blackSquare) {

        int sz = font.getSize();
        BufferedImage bi = new BufferedImage(
                sz, sz, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bi.createGraphics();
        g.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(
                RenderingHints.KEY_DITHERING,
                RenderingHints.VALUE_DITHER_ENABLE);
        g.setRenderingHint(
                RenderingHints.KEY_ALPHA_INTERPOLATION,
                RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

        FontRenderContext frc = g.getFontRenderContext();
        GlyphVector gv = font.createGlyphVector(frc, s);
        Rectangle2D box1 = gv.getVisualBounds();

        Shape shape1 = gv.getOutline();
        Rectangle r = shape1.getBounds();
        System.out.println("shape rect: " + r);
        int spaceX = sz - r.width;
        int spaceY = sz - r.height;
        AffineTransform trans = AffineTransform.getTranslateInstance(
                -r.x + (spaceX / 2), -r.y + (spaceY / 2));
        System.out.println("Box2D " + trans);

        Shape shapeCentered = trans.createTransformedShape(shape1);

        Shape imageShape = new Rectangle2D.Double(0, 0, sz, sz);
        Area imageShapeArea = new Area(imageShape);
        Area shapeArea = new Area(shapeCentered);
        imageShapeArea.subtract(shapeArea);
        ArrayList<Shape> regions = separateShapeIntoRegions(imageShapeArea);
        g.setStroke(new BasicStroke(1));
        for (Shape region : regions) {
            Rectangle r1 = region.getBounds();
            if (r1.getX() < 0.001 && r1.getY() < 0.001) {
            } else {
                g.setColor(bgColor);
                g.fill(region);
            }
        }
        g.setColor(outlineColor);
        g.fill(shapeArea);
        g.dispose();

        JLabel l = new JLabel(new ImageIcon(bi), JLabel.CENTER);
        Color bg = (blackSquare ? Color.BLACK : Color.WHITE);
        l.setBackground(bg);
        l.setOpaque(true);
        c.add(l);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new GridLayout(0, 6, 4, 4));

                String[] pieces = {
                    "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659"
                };

                boolean blackSquare = false;
                for (String piece : pieces) {
                    addColoredUnicodeCharToContainer(
                            piece, gui,
                            new Color(203,203,197),
                            Color.DARK_GRAY,
                            blackSquare);
                            blackSquare = !blackSquare;
                }
                            blackSquare = !blackSquare;
                for (String piece : pieces) {
                    addColoredUnicodeCharToContainer(
                            piece, gui,
                            new Color(192,142,60),
                            Color.DARK_GRAY,
                            blackSquare);
                            blackSquare = !blackSquare;
                }

                JOptionPane.showMessageDialog(null, gui);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

Échiquier

C'est ce à quoi il pourrait ressembler comme un échiquier (22.81 Kb).

Chess Board Unadorned

ensembles de Sprite

Jeux Sprite de pièces d'Échecs (64x64 pixels) rendus à partir de caractères Unicode - comme un PNG avec BG transparent. Chacune a 6 colonnes pour les pièces x 2 lignes pour les adversaires (taille totale 384x128 pixels).

pièces D'échecs à remplissage plein (bronze/étain) (11.64 Kb).

Chess Piece Tile Set

pièces D'échecs avec remplissage de gradient (or / argent) (13.61 Ko).

Chess Piece Tile Set with Gradient Fill Color

pièces d'Échecs avec remplissage en dégradé (plus foncé cyan/magenta) (13.44 Ko).

Chess Piece Tile Set with Gradient Fill Color

Code pour échiquier et jeu de Sprite

import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;

import java.io.*;
import javax.imageio.ImageIO;
import java.util.*;
import java.util.logging.*;

class ChessBoard {

    /**
     * Unicodes for chess pieces.
     */
    static final String[] pieces = {
        "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659"
    };
    static final int KING = 0, QUEEN = 1, CASTLE = 2,
            BISHOP = 3, KNIGHT = 4, PAWN = 5;
    public static final int[] order = new int[]{
        CASTLE, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, CASTLE
    };

    /*
     * Colors..
     */
    public static final Color outlineColor = Color.DARK_GRAY;
    public static final Color[] pieceColors = {
        new Color(203, 203, 197), new Color(192, 142, 60)
    };
    static final int WHITE = 0, BLACK = 1;

    /*
     * Font. The images use the font sizeXsize.
     */
    static Font font = new Font("Sans-Serif", Font.PLAIN, 64);

    public static ArrayList<Shape> separateShapeIntoRegions(Shape shape) {
        ArrayList<Shape> regions = new ArrayList<Shape>();

        PathIterator pi = shape.getPathIterator(null);
        int ii = 0;
        GeneralPath gp = new GeneralPath();
        while (!pi.isDone()) {
            double[] coords = new double[6];
            int pathSegmentType = pi.currentSegment(coords);
            int windingRule = pi.getWindingRule();
            gp.setWindingRule(windingRule);
            if (pathSegmentType == PathIterator.SEG_MOVETO) {
                gp = new GeneralPath();
                gp.setWindingRule(windingRule);
                gp.moveTo(coords[0], coords[1]);
            } else if (pathSegmentType == PathIterator.SEG_LINETO) {
                gp.lineTo(coords[0], coords[1]);
            } else if (pathSegmentType == PathIterator.SEG_QUADTO) {
                gp.quadTo(coords[0], coords[1], coords[2], coords[3]);
            } else if (pathSegmentType == PathIterator.SEG_CUBICTO) {
                gp.curveTo(
                        coords[0], coords[1],
                        coords[2], coords[3],
                        coords[4], coords[5]);
            } else if (pathSegmentType == PathIterator.SEG_CLOSE) {
                gp.closePath();
                regions.add(new Area(gp));
            } else {
                System.err.println("Unexpected value! " + pathSegmentType);
            }

            pi.next();
        }

        return regions;
    }

    public static BufferedImage getImageForChessPiece(
            int piece, int side, boolean gradient) {
        int sz = font.getSize();
        BufferedImage bi = new BufferedImage(
                sz, sz, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bi.createGraphics();
        g.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(
                RenderingHints.KEY_DITHERING,
                RenderingHints.VALUE_DITHER_ENABLE);
        g.setRenderingHint(
                RenderingHints.KEY_ALPHA_INTERPOLATION,
                RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

        FontRenderContext frc = g.getFontRenderContext();
        GlyphVector gv = font.createGlyphVector(frc, pieces[piece]);
        Rectangle2D box1 = gv.getVisualBounds();

        Shape shape1 = gv.getOutline();
        Rectangle r = shape1.getBounds();
        int spaceX = sz - r.width;
        int spaceY = sz - r.height;
        AffineTransform trans = AffineTransform.getTranslateInstance(
                -r.x + (spaceX / 2), -r.y + (spaceY / 2));

        Shape shapeCentered = trans.createTransformedShape(shape1);

        Shape imageShape = new Rectangle2D.Double(0, 0, sz, sz);
        Area imageShapeArea = new Area(imageShape);
        Area shapeArea = new Area(shapeCentered);
        imageShapeArea.subtract(shapeArea);
        ArrayList<Shape> regions = separateShapeIntoRegions(imageShapeArea);
        g.setStroke(new BasicStroke(1));
        g.setColor(pieceColors[side]);
        Color baseColor = pieceColors[side];
        if (gradient) {
            Color c1 = baseColor.brighter();
            Color c2 = baseColor;
            GradientPaint gp = new GradientPaint(
                    sz/2-(r.width/4), sz/2-(r.height/4), c1, 
                    sz/2+(r.width/4), sz/2+(r.height/4), c2, 
                    false);
            g.setPaint(gp);
        } else {
            g.setColor(baseColor);
        }

        for (Shape region : regions) {
            Rectangle r1 = region.getBounds();
            if (r1.getX() < 0.001 && r1.getY() < 0.001) {
            } else {
                g.fill(region);
            }
        }
        g.setColor(outlineColor);
        g.fill(shapeArea);
        g.dispose();

        return bi;
    }

    public static void addColoredUnicodeCharToContainer(
            Container c,
            int piece,
            int side,
            Color bg,
            boolean gradient) {

        JLabel l = new JLabel(
                new ImageIcon(getImageForChessPiece(piece, side, gradient)),
                JLabel.CENTER);
        l.setBackground(bg);
        l.setOpaque(true);
        c.add(l);
    }

    public static void addPiecesToContainer(
            Container c,
            int intialSquareColor,
            int side,
            int[] pieces,
            boolean gradient) {

        for (int piece : pieces) {
            addColoredUnicodeCharToContainer(
                    c, piece, side,
                    intialSquareColor++%2 == BLACK ? Color.BLACK : Color.WHITE,
                    gradient);
        }
    }

    public static void addPiecesToContainer(
            Container c,
            Color bg,
            int side,
            int[] pieces,
            boolean gradient) {

        for (int piece : pieces) {
            addColoredUnicodeCharToContainer(
                    c, piece, side, bg, gradient);
        }
    }

    public static void addBlankLabelRow(Container c, int initialSquareColor) {
        for (int ii = 0; ii < 8; ii++) {
            JLabel l = new JLabel();
            Color bg = (initialSquareColor++ % 2 == BLACK
                    ? Color.BLACK : Color.WHITE);
            l.setBackground(bg);
            l.setOpaque(true);
            c.add(l);
        }
    }

    public static void main(String[] args) {
        final int[] pawnRow = new int[]{
            PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN
        };
        Runnable r = new Runnable() {

            @Override
            public void run() {
                int gradient = JOptionPane.showConfirmDialog(
                        null, "Use gradient fille color?");
                boolean gradientFill = gradient == JOptionPane.OK_OPTION;
                JPanel gui = new JPanel(new GridLayout(0, 8, 0, 0));
                gui.setBorder(new BevelBorder(
                        BevelBorder.LOWERED,
                        Color.GRAY.brighter(), Color.GRAY,
                        Color.GRAY.darker(), Color.GRAY));
                // set up a chess board
                addPiecesToContainer(gui, WHITE, BLACK, order, gradientFill);
                addPiecesToContainer(gui, BLACK, BLACK, pawnRow, gradientFill);

                addBlankLabelRow(gui, WHITE);
                addBlankLabelRow(gui, BLACK);
                addBlankLabelRow(gui, WHITE);
                addBlankLabelRow(gui, BLACK);

                addPiecesToContainer(gui, WHITE, WHITE, pawnRow, gradientFill);
                addPiecesToContainer(gui, BLACK, WHITE, order, gradientFill);

                JOptionPane.showMessageDialog(
                        null,
                        gui,
                        "Chessboard",
                        JOptionPane.INFORMATION_MESSAGE);

                JPanel tileSet = new JPanel(new GridLayout(0, 6, 0, 0));
                tileSet.setOpaque(false);
                int[] tileSetOrder = new int[]{
                    KING, QUEEN, CASTLE, KNIGHT, BISHOP, PAWN
                };
                addPiecesToContainer(
                        tileSet,
                        new Color(0, 0, 0, 0),
                        BLACK,
                        tileSetOrder, 
                        gradientFill);
                addPiecesToContainer(
                        tileSet,
                        new Color(0, 0, 0, 0),
                        WHITE,
                        tileSetOrder, 
                        gradientFill);
                int result = JOptionPane.showConfirmDialog(
                        null,
                        tileSet,
                        "Save this tileset?",
                        JOptionPane.OK_CANCEL_OPTION,
                        JOptionPane.QUESTION_MESSAGE);
                if (result == JOptionPane.OK_OPTION) {
                    BufferedImage bi = new BufferedImage(
                            tileSet.getWidth(),
                            tileSet.getHeight(),
                            BufferedImage.TYPE_INT_ARGB);
                    Graphics g = bi.createGraphics();
                    tileSet.paint(g);
                    g.dispose();

                    String gradientString = gradientFill ? "gradient" : "solid";
                    File f = new File(
                            "chess-pieces-tileset-" + gradientString + ".png");
                    try {
                        ImageIO.write(bi, "png", f);
                        Desktop.getDesktop().open(f);
                    } catch (IOException ex) {
                        Logger.getLogger(
                                ChessBoard.class.getName()).log(
                                Level.SEVERE, null, ex);
                    }
                }
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

voir aussi

  • développé à partir de la GlyphVector code comme on le voit dans cette réponse .

14
répondu Andrew Thompson 2018-06-30 02:04:31

le problème que je vois est que les glyphes ont été conçus pour distinguer facilement les pièces d'Échecs traditionnelles en noir et blanc. Notez également la variation de la police. Vous pouvez être en mesure de créer des pièces sur le thème de teinte qui préservent la distinction noir et blanc en utilisant le HSB espace de couleur . Green et cyan sont représentés ci-dessous.

HSB image

Addendum: Pour référence, voici un Mac OS X capture d'écran de @André la forme du glyphe approche . Remarque l'avantage de @Andrew utilisation de RenderingHints que l'image est redimensionnée.

shape image

import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.Random;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/** @see https://stackoverflow.com/a/18691662/230513 */

class ChessBoard {

    static Font font = new Font("Sans-Serif", Font.PLAIN, 64);
    static Random rnd = new Random();

    public static void addUnicodeCharToContainer(String s, Container c) {
        JLabel l = new JLabel(s);
        l.setFont(font);
        l.setOpaque(true);
        c.add(l);
    }

    public static void addWhite(String s, Container c, Float h) {
        JLabel l = new JLabel(s);
        l.setFont(font);
        l.setOpaque(true);
        l.setForeground(Color.getHSBColor(h, 1, 1));
        l.setBackground(Color.getHSBColor(h, 3 / 8f, 5 / 8f));
        c.add(l);
    }

    public static void addBlack(String s, Container c, Float h) {
        JLabel l = new JLabel(s);
        l.setFont(font);
        l.setOpaque(true);
        l.setForeground(Color.getHSBColor(h, 5 / 8f, 3 / 8f));
        l.setBackground(Color.getHSBColor(h, 7 / 8f, 7 / 8f));
        c.add(l);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                JPanel gui = new JPanel(new GridLayout(0, 6, 4, 4));
                String[] white = {
                    "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659"
                };
                String[] black = {
                    "\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F"
                };
                for (String piece : white) {
                    addUnicodeCharToContainer(piece, gui);
                }
                for (String piece : white) {
                    addWhite(piece, gui, 2 / 6f);
                }
                for (String piece : black) {
                    addUnicodeCharToContainer(piece, gui);
                }
                for (String piece : black) {
                    addBlack(piece, gui, 3 / 6f);
                }
                JOptionPane.showMessageDialog(null, gui);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
4
répondu trashgod 2017-05-23 12:10:53

à la fin, j'ai trouvé faire un spritesheet pour être la façon la plus facile et la plus simple de résoudre le problème. Chaque pièce correspond désormais à un graphique dans la feuille d'érable au lieu d'un caractère/glyphe. Pour cette raison, les pièces ne peuvent pas être redimensionnées aussi bien, mais ce n'est pas la plus grosse affaire.

l'idée de @Andrew Thompson avec le GlyphVector semblait prometteuse, mais la question de séparer l'espace blanc intérieur de l'espace blanc extérieur reste difficile.

une idée (inefficace) que j'ai encore est de faire une tonne de glyphes pièce d'échecs à partir d'une très petite taille de police et avec une couleur de blanc de l'avant:

for (int i = 1; i < BOARD_WIDTH/8) { 
JLabel chessPiece =new JLabel("\u2654");
chessPiece.setForeground(Color.white);
chessPiece.setFont(new Font("Sans-Serif", Font.PLAIN, i));
add(chessPiece);
}

puis Ajouter une dernière pièce d'échecs avec un avant-plan noir:

JLabel chessPiece =new JLabel("\u2654");
chessPiece.setForeground(Color.black);
chessPiece.setFont(new Font("Sans-Serif", Font.PLAIN, BOARD_WIDTH/8)));
add(chessPiece);

notez que je ne l'ai pas testé.

1
répondu PearSquirrel 2013-09-09 05:26:40