I am writing a program to generate labels and to print the labels on a standard printed using label sheets. I can create an image and save it but, I am having problems getting the image to print on the label sheet. It is blank. I can write the image to disk and open the image, it appears to be a valid image. However, no matter what I do I cannot get it to print. I have written a test program to try and print it to no avail. I downloaded an image from the net and was able to print that.
The created label will need to be printed on a label sheet (contains 6 labels from top to bottom). I need to create a label and have it print starting at the desired label on the sheet.
The LabelImage class creates the image for the label. The image has up to 4 digits printed on the left side of the label (rotated 90 degrees clockwise), then some string values. I had to create the digits in a separate image as I could not get them properly rotated in a single image.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
public class LabelImage {
public static final Map <String, Color> ColorMap = new HashMap <> ();
// Define label size
public static final int LABEL_WIDTH = 830;
public static final int LABEL_HALF_WIDTH = LABEL_WIDTH / 2;
public static final int LABEL_HEIGHT = 190;
public static final int LABEL_HALF_HEIGHT = LABEL_HEIGHT / 2;
// Define rectangle to print out digits in for the label
public static final int LEFT_DIGIT_RECT_TLX = 15;
public static final int LEFT_DIGIT_RECT_TLY = 30;
public static final int LEFT_DIGIT_RECT_WIDTH = 80;
public static final int LEFT_DIGIT_RECT_HEIGHT = (LABEL_HEIGHT - (LEFT_DIGIT_RECT_TLY * 2));
public static final int LEFT_DIGIT_TLX_OFFSET = -10;
public static final int LEFT_DIGIT_TLY_OFFSET = 15;
public static final int LEFT_DIGIT_ROTATE_X = LEFT_DIGIT_RECT_WIDTH / 2;
public static final int LEFT_DIGIT_ROTATE_Y = LEFT_DIGIT_RECT_TLY + (LEFT_DIGIT_RECT_HEIGHT / 4);
public static final int LEFT_DIGIT_ROTATE_Y2 = LEFT_DIGIT_ROTATE_Y + (LEFT_DIGIT_RECT_HEIGHT / 2);
// Create a separate image of the digits, then rotate the image
public static final int LEFT_DIGIT_TLX = 20;
public static final int LEFT_DIGIT_TLX2 = (LEFT_DIGIT_RECT_HEIGHT / 2) + LEFT_DIGIT_TLX;
public static final int LEFT_DIGIT_TLY = (LEFT_DIGIT_RECT_WIDTH - 25);
public static final int ROTATE_X = 0;
public static final int ROTATE_Y = 0;
public static final float DIGIT_FRAME_THICKNESS = 5;
public static final int CLIENT_ID_X = 380;
public static final int CLIENT_ID_Y = 30;
public static final int CLIENT_ID_Y2 = LABEL_HALF_HEIGHT + CLIENT_ID_Y;
public static final int CLIENT_NAME_X = 450;
public static final int CLIENT_NAME_Y = 30;
public static final int CLIENT_NAME_Y2 = LABEL_HALF_HEIGHT + CLIENT_NAME_Y;
public static final int PROJECT_NAME_X = CLIENT_NAME_X;
public static final int PROJECT_NAME_Y = 50;
public static final int PROJECT_NAME_Y2 = LABEL_HALF_HEIGHT + PROJECT_NAME_Y;
public static final int OTHER_X = CLIENT_ID_X;
public static final int OTHER_Y = 70;
public static final int OTHER_Y2 = LABEL_HALF_HEIGHT + OTHER_Y;
Font normalFont = new Font("TimesRoman", Font.BOLD, 14);
Font leftDigitFont = new Font("TimesRoman", Font.BOLD, 42);
static {
ColorMap.put("0", new Color(255, 120, 130, 100));
ColorMap.put("1", new Color(252, 0, 105, 100));
ColorMap.put("2", new Color(255, 165, 10, 100));
ColorMap.put("3", new Color(255, 85, 10, 100));
ColorMap.put("4", new Color(122, 252, 12, 100));
ColorMap.put("5", new Color(0, 145, 0, 100));
ColorMap.put("6", new Color(60, 255, 255, 100));
ColorMap.put("7", new Color(40, 0, 120, 100));
ColorMap.put("8", new Color(222, 182, 245, 100));
ColorMap.put("9", new Color(145, 55, 0, 100));
ColorMap.put("0", new Color(196, 23, 27, 100));
ColorMap.put("1", new Color(232, 85, 66, 100));
ColorMap.put("2", new Color(236, 131, 101, 100));
ColorMap.put("3", new Color(230, 229, 48, 100));
ColorMap.put("4", new Color(184, 224, 101, 100));
ColorMap.put("5", new Color(53, 161, 19, 100));
ColorMap.put("6", new Color(66, 142, 232, 100));
ColorMap.put("7", new Color(98, 83, 234, 100));
ColorMap.put("8", new Color(26, 15, 126, 100));
ColorMap.put("9", new Color(95, 17, 143, 100));
}
/**
* Prints a digit on the left hand side of the label, rotated 90 degrees
* clockwise. At the specified digit location.
* #param digit the digit to print
* #param ndx the index location to print at
*/
private void printLeftDigit(Graphics2D g2, String digit, int ndx) {
// find the top-left coordinate of the rectangle
int tlx = LEFT_DIGIT_RECT_TLX + (LEFT_DIGIT_RECT_WIDTH * ndx);
int tly = LEFT_DIGIT_RECT_TLY;
// Draw the colored rectangle
Color origColor = g2.getColor();
g2.setColor(ColorMap.get(digit));
g2.fillRect(tlx, tly, LEFT_DIGIT_RECT_WIDTH, LEFT_DIGIT_RECT_HEIGHT);
g2.setColor(origColor);
// Draw a black outline for the box over the rectangle
Stroke oldStroke = g2.getStroke();
g2.setStroke(new BasicStroke(DIGIT_FRAME_THICKNESS));
g2.drawRect(tlx, tly, LEFT_DIGIT_RECT_WIDTH-1, LEFT_DIGIT_RECT_HEIGHT);
g2.setStroke(oldStroke);
// Center of digit to rotate around
int cdx = tlx + LEFT_DIGIT_ROTATE_X;
// Write the digit in the rectangle
AffineTransform origTransform = g2.getTransform();
g2.setFont(leftDigitFont);
//g2.rotate(Math.PI/25);
double angle = Math.toRadians(90.0);
g2.setColor(Color.BLACK);
g2.rotate(angle, cdx, LEFT_DIGIT_ROTATE_Y);
g2.drawString(digit, cdx + LEFT_DIGIT_TLX_OFFSET, LEFT_DIGIT_ROTATE_Y + LEFT_DIGIT_TLY_OFFSET);
g2.setTransform(origTransform);
//g2.setColor(Color.GREEN);
g2.rotate(angle, cdx, LEFT_DIGIT_ROTATE_Y2);
g2.drawString(digit, cdx + LEFT_DIGIT_TLX_OFFSET, LEFT_DIGIT_ROTATE_Y2 + LEFT_DIGIT_TLY_OFFSET);
g2.setTransform(origTransform);
}
/**
* This method creates a 2nd image for the digits, then rotates the image and puts it
* over the label image.
*
* #param g2
* #param digit
* #param ndx
*/
private void printLeftDigit2(Graphics2D g2, String digit, int ndx) {
// Width is the top to bottom rectangle size
// height is the left to right rectangle width (because it will be rotated)
//BufferedImage image = new BufferedImage(LEFT_DIGIT_RECT_HEIGHT, LEFT_DIGIT_RECT_WIDTH, BufferedImage.TYPE_INT_ARGB);
BufferedImage image = new BufferedImage(LEFT_DIGIT_RECT_HEIGHT, LEFT_DIGIT_RECT_WIDTH, BufferedImage.TYPE_INT_RGB);
Graphics2D imageGraphics = image.createGraphics();
// Fill the rectangle with the expected color
imageGraphics.setColor(ColorMap.get(digit));
imageGraphics.fillRect(0, 0, LEFT_DIGIT_RECT_HEIGHT, LEFT_DIGIT_RECT_WIDTH);
// Draw a black outline for the box over the rectangle
imageGraphics.setColor(Color.BLACK);
Stroke oldStroke = imageGraphics.getStroke();
imageGraphics.setStroke(new BasicStroke(DIGIT_FRAME_THICKNESS));
imageGraphics.drawRect(0, 0, LEFT_DIGIT_RECT_HEIGHT, LEFT_DIGIT_RECT_WIDTH);
imageGraphics.setStroke(oldStroke);
// Draw the Digits in the rectangle (top-left of digit)
imageGraphics.setFont(leftDigitFont);
imageGraphics.drawString(digit, LEFT_DIGIT_TLX, LEFT_DIGIT_TLY);
imageGraphics.drawString(digit, LEFT_DIGIT_TLX2, LEFT_DIGIT_TLY);
imageGraphics.dispose();
// Put the image on the current graphic
AffineTransform aff = g2.getTransform();
double theta = Math.toRadians(90.0);
//AffineTransform rotate = AffineTransform.getRotateInstance(theta, rotx, roty);
//(x,y) = middle of rectangle
AffineTransform rotate = AffineTransform.getRotateInstance(theta, 40, 65);
//x >0 moves down; <0 moves up
//y >0: moves left; <0: moves right
int moveright = 15 - (ndx * LEFT_DIGIT_RECT_WIDTH);
rotate.translate(10, moveright);
//g2.drawImage(image, rotate, this);
}
public BufferedImage createImageWithText(ClientProject clientProject){
//ARGB = transparent
BufferedImage bufferedImage = new BufferedImage(830, 190,BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.setColor(Color.YELLOW);
g.fillRoundRect(0, 0, LABEL_WIDTH, LABEL_HEIGHT, 10, 10);
String clientId = String.valueOf(clientProject.getClientId());
String clientName = clientProject.getClientName();
String projectName = clientProject.getProjectName();
String created = "DFC: " + DateUtil.format(clientProject.getCreated(), DateUtil.LABEL_DATE_PATTERN);
// Setup for drawing to screen
g.setColor(Color.BLACK);
g.setFont(normalFont);
g.drawLine(0, LABEL_HALF_HEIGHT, LABEL_WIDTH, LABEL_HALF_HEIGHT);
// write client id on tabs
String tmp = clientId;
if (clientId.length() > 4) {
tmp = tmp.substring(0, 4);
System.out.println("tmp = " + tmp);
}
StringBuilder sb = new StringBuilder(tmp);
sb.reverse();
for (int ndx=0; ndx < sb.length(); ndx++) {
try {
printLeftDigit2((Graphics2D)g, String.valueOf(sb.charAt(ndx)), ndx);
} catch (NumberFormatException e) {
}
}
// Write client id
g.setFont(normalFont);
g.drawString(clientId, CLIENT_ID_X, CLIENT_ID_Y);
g.drawString(clientId, CLIENT_ID_X, CLIENT_ID_Y2);
// Write Client Name
g.drawString(clientName, CLIENT_NAME_X, CLIENT_NAME_Y);
g.drawString(clientName, CLIENT_NAME_X, CLIENT_NAME_Y2);
// Write Project Name
g.drawString(projectName, PROJECT_NAME_X, PROJECT_NAME_Y);
g.drawString(projectName, PROJECT_NAME_X, PROJECT_NAME_Y2);
// Write created
g.drawString(created, OTHER_X, OTHER_Y);
g.drawString(created, OTHER_X, OTHER_Y2);
return bufferedImage;
}
}
The PrintLabel program is supposed to print the image to the label sheet, but I cannot get it to print the image created by the code above. I had taken this class from somewhere else on the net, and tried to modify it for my purposes.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import static java.awt.print.Printable.NO_SUCH_PAGE;
import static java.awt.print.Printable.PAGE_EXISTS;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
public class PrintLabel {
protected static double fromCMToPPI(double cm) {
return toPPI(cm * 0.393700787);
}
protected static double toPPI(double inch) {
return inch * 72d;
}
protected static String dump(Paper paper) {
StringBuilder sb = new StringBuilder(64);
sb.append(paper.getWidth()).append("x").append(paper.getHeight())
.append("/").append(paper.getImageableX()).append("x").
append(paper.getImageableY()).append(" - ").append(paper
.getImageableWidth()).append("x").append(paper.getImageableHeight());
return sb.toString();
}
protected static String dump(PageFormat pf) {
Paper paper = pf.getPaper();
return dump(paper);
}
public void process() {
PrinterJob pj = PrinterJob.getPrinterJob();
if (pj.printDialog()) {
PageFormat pf = pj.defaultPage();
Paper paper = pf.getPaper();
double width = fromCMToPPI(20.3);
double height = fromCMToPPI(25.4);
paper.setSize(width, height);
paper.setImageableArea(
fromCMToPPI(0.25),
fromCMToPPI(0.5),
width - fromCMToPPI(0.35),
height - fromCMToPPI(1));
System.out.println("Before- " + dump(paper));
pf.setOrientation(PageFormat.PORTRAIT);
pf.setPaper(paper);
System.out.println("After- " + dump(paper));
System.out.println("After- " + dump(pf));
//dump(pf);
PageFormat validatePage = pj.validatePage(pf);
System.out.println("Valid- " + dump(validatePage));
MyPrintable printable = new MyPrintable();
printable.labels.add(new ClientProject(112, 208, "Taxes", "Tax Refund"));
printable.determinePageCount();
pj.setPrintable(printable, pf);
try {
pj.print();
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args) {
PrintLabel pl = new PrintLabel();
pl.process();
}
public class MyPrintable implements Printable {
public int startAtLabel = 0;
public int totalPages = 0;
public List <ClientProject> labels = new ArrayList <> ();
private List <ClientProject> printed = new ArrayList <> ();
/**
* Determines how many pages to print, there are 6 labels per page. If we
* start at index 5 (the last one) and there are 2 labels, there are 2
* pages to print.
*/
public void determinePageCount() {
int max = this.startAtLabel + this.labels.size();
this.totalPages = max / 6;
if ((max % 6) != 0) {
this.totalPages++;
}
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
System.out.println(pageIndex);
int result = NO_SUCH_PAGE;
// first page is index 0, if 1 page max index is 0
if (pageIndex < this.totalPages) {
Graphics2D g2d = (Graphics2D) graphics;
System.out.println("[Print] " + dump(pageFormat));
double width = pageFormat.getImageableWidth();
double height = pageFormat.getImageableHeight();
g2d.translate((int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY());
System.out.printf("wxh = (%fx%f)", width,height);
// Max of 6 labels per page
int maxLabelsOnPage = 6;
if (pageIndex == 0) {
maxLabelsOnPage = 6 - startAtLabel;
}
// Loop for up to the max number of labels or until we run out
// of labels
for (int labelCnt=0; labelCnt < maxLabelsOnPage; labelCnt++) {
// We have run out of labels and there is nothing left to print
if (this.labels.isEmpty()) {
break;
}
// Remove the label from the list and add it to the printed list
ClientProject cp = this.labels.remove(0);
this.printed.add(cp);
// Create the image for the label
BufferedImage image = null;
try {
// Create the image for the label
LabelImage li = new LabelImage();
BufferedImage bi = li.createImageWithText(cp);
// Load the label image
//image = ImageIO.read(new File("C:\\Consulting\\Development\\JJCPA\\finland.png"));
System.out.printf("image %d x %d%n", bi.getWidth(), bi.getHeight());
// Draw the image at the label offset
graphics.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null);
// Write to a file to verify the image is valid
File outputfile = new File("image.png");
ImageIO.write(bi, "png", outputfile);
} catch (IOException e) {
}
}
result = PAGE_EXISTS;
}
return result;
}
}
}
ClientProject is a simple data structure.
public class ClientProject {
private final SimpleIntegerProperty projectId;
private final SimpleIntegerProperty clientId;
private final SimpleStringProperty category;
private final SimpleStringProperty type;
private final SimpleStringProperty projectDesc;
private final SimpleStringProperty projectName;
private final SimpleStringProperty projectName2;
private final SimpleStringProperty fileOrBinder;
private final ObjectProperty <LocalDate> created;
private final ObjectProperty <LocalDate> destroyed;
There is an error with the logic. I thought I could render a single page easy h time the method was called, until I was done creating an image for each label. 0thus, I tracked which labels I printed. this was wrong. I needed to print a through b labels for index 1 for as many times as index 1 was called, then print the next group of labels each time index 2 was passed, rewriting for this logic solved the problem.
Related
I'm attempting to draw these smiley faces out on a GUI and for their parts (eyes, smile, etc.) to be all random colors. However, when I use the setColor method for my variables, they all blend in with each other and I can't see the eyes, etc. Here is my code:
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class Smiley extends JPanel {
//declare required variable
//set the width of window
public static final int w = 400;
//set the height of window
public static final int h = 400;
//assign face diameter
public static final int fd = 180;
//initializes the face of x position
public static final int xp = 10;
//initializes the face of y position
public static final int yp = 10;
//initializes the width of eye
public static final int we = 20;
//initializes the height of eye
public static final int he = 20;
//set the Right eye's position on the x and y
public static final int xre = xp + 40;
public static final int yre = yp + 60;
//set the left eye's position on the x and y
public static final int xle = xp + 120;
public static final int yle = yp + 60;
//initialzes the width and height of the mouth
public static final int mw = 80;
public static final int mh = 50;
//initializes the x and y position of mouth on the face
public static final int xm = xp + 50;
public static final int ym = yp + 90;
//define the class variables of type Color
public Color profile, nface, fsmile, eye;
// Smiley constructor takes parameters for 4 colors that will be
public Smiley(Color profile, Color nface, Color fsmile, Color eye) {
//set the layout
setLayout(new BorderLayout());
//initialize the parameters
this.profile = profile;
this.nface = nface;
this.fsmile = fsmile;
this.eye = eye;
//call paint() method
repaint();
}
public void paintComponent(Graphics gr) {
super.paintComponent(gr);
Random random = new Random();
Color color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
gr.setColor(color);
profile = color;
nface = color;
fsmile = color;
eye = color;
//set the color of profile of the face
gr.setColor(profile);
//draw the face
gr.fillOval(xp, yp, fd + 7, fd + 7);
//fill the color of face
gr.setColor(nface);
gr.fillOval(xp + 3, yp + 3, fd, fd);
//fill the eye color
gr.setColor(eye);
//for draw right eye
gr.fillOval(xre, yre, we, he);
gr.setColor(eye);
//for draw left eye
gr.fillOval(xle, yle, we, he);
//for smile color
gr.setColor(fsmile);
gr.drawArc(xm, ym, mw, mh, 180, 180);
}
}
What I expect is something like this:
https://imgur.com/a/7hFGzw1
How would I go about achieving this?
And this is the code where I will implement the smileys:
import java.awt.*;
import java.awt.event.*; //determined to be useless and got rid of
actionPerformed method
import javax.swing.*;
public class SmileyGrid extends JFrame {
//object for SmileGrid class
static SmileyGrid gs = new SmileyGrid();
public static void main(String[] args) {
gs.setSize(800, 800);
gs.setLayout(new GridLayout(3, 3));
//call createFace function()
gs.createGUI();
gs.setVisible(true);
}
public SmileyGrid() {
}
private void createGUI() {
for (int a = 0; a < 9; a++) {
Smiley sp = new Smiley(Color.BLUE, Color.YELLOW, Color.RED, Color.black);
gs.add(sp);
}
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
Here:
profile = color;
nface = color;
fsmile = color;
These are supposed to be your 3 different colors. But you initialize all three to the same value! Instead, you would have to call the random function 3 times. Or to be precise: you should invoke that function repeatedly until your 3 colors are really different.
Alternatively: you could define 3 sets, each with 5, 10 different colors manually upfront. And then your code picks a random color from each set. Meaning: instead of using totally random colors, you could select sets of colors that always work together when mixed.
Welcome to SO. You are assigning the same Color object to all your variables so naturally they have the same color. You'll need to generate new random colors for each of them rather than assigning color to all of them.
profile = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
...
Stack Trace Hi i'm working on a GUI for monopoly and i've reached a stage where i need to get user input that would ask for a specific number of players and would provide a certain number of tokens (monopoly pieces) based on the number of players specified. I've currently hit a problem i feel really shouldn't be as serious as it is where if i do try to specify the number of players for the game i'm hit with a an ArrayIndexOutOfBoundsException and i can't seem to identify where or what is wrong and how to fix it. Thanks for the help in advance and any edits or tips for my code to make it more efficient are also welcome. I will attach all necessary program files.
P.s i posted the full source code as i felt it was necessary as a shortened version wouldn't make things as clear. Thanks again. P.p.s the code does work when i specify the number of players in the source code without asking for user input but stops working when i do specify user input. Monopoly Board Image
package sprint_One;
/*
* Code written by: lagosBoys A layered pane was used to place all components on the frame at the
* desired locations
*/
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
public class UI_Monopoly_Board extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
// Array of coordinates for the position of each square on the board
Point[] locations = {new Point(630, 643), new Point(570, 643), new Point(510, 643),
new Point(450, 643), new Point(390, 643), new Point(330, 643), new Point(270, 643),
new Point(210, 643), new Point(150, 643), new Point(95, 643), new Point(60, 643),
new Point(60, 573), new Point(60, 503), new Point(60, 433), new Point(60, 383),
new Point(60, 323), new Point(60, 273), new Point(60, 213), new Point(60, 153),
new Point(60, 93), new Point(60, 33),
new Point(120, 13), new Point(180, 13), new Point(230, 13), new Point(280, 13),
new Point(340, 13), new Point(400, 13), new Point(460, 13), new Point(520, 13),
new Point(580, 13), new Point(660, 60), new Point(660, 120), new Point(660, 160),
new Point(660, 220), new Point(660, 280), new Point(660, 340), new Point(660, 400),
new Point(660, 460), new Point(660, 520), new Point(660, 580), new Point(660, 640)};
// The default position or starting point which is go
Point defaultPosition = new Point(600, 603);
private int players;
private Token[] token;
private static JPanel infoPanel;
private static JPanel commandPanel;
// creates a fixed length for the text field used by the command field
final static int field_Width = 20;
private static JTextField commandField = new JTextField(field_Width);
private static JLabel commandLabel = new JLabel("Enter Command: ");
private Border blackLineBorder;
private final int ROWS = 35;
private final int COLUMNS = 40;
private JTextArea textArea = new JTextArea(ROWS, COLUMNS);
private static JLabel echoed_Text_Label = new JLabel();
private JLayeredPane layeredPane = getLayeredPane(); // The use of a JLayeredPane allows easier
// and more flexible specification of
// component positions
private static JLabel monopolyImageLabel;
public UI_Monopoly_Board() {
String playerNumber = JOptionPane.showInputDialog("Please enter the number of players");
// int tokenNumber = Integer.parseInt(playerNumber);
// players = 6;
players = Integer.parseInt(playerNumber);
int offset = 10;
// Initialise tokens depending on number of players and spaces them out with offset
if(players >= 2 || players <= 6)
{
token = new Token[players];
switch (players) {
case 2:
token[0] = new Token();
token[0].setBounds(10, 10, 700, 700);
token[0].setPosition(600, 603);
token[1] = new Token(Color.red, null);
token[1].setBounds(10, 10, 700, 700);
token[1].setPosition(600 + offset, 603 + offset);
break;
case 3:
token[0] = new Token();
token[0].setBounds(10, 10, 700, 700);
token[0].setPosition(600, 603);
token[1] = new Token(Color.red, null);
token[1].setBounds(10, 10, 700, 700);
token[1].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[2] = new Token(Color.blue, null);
token[2].setBounds(10, 10, 700, 700);
token[2].setPosition(600 + offset, 603 + offset);
break;
case 4:
token[0] = new Token();
token[0].setBounds(10, 10, 700, 700);
token[0].setPosition(600, 603);
token[1] = new Token(Color.red, null);
token[1].setBounds(10, 10, 700, 700);
token[1].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[2] = new Token(Color.blue, null);
token[2].setBounds(10, 10, 700, 700);
token[2].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[3] = new Token(Color.green, null);
token[3].setBounds(10, 10, 700, 700);
token[3].setPosition(600 + offset, 603 + offset);
break;
case 5:
token[0] = new Token();
token[0].setBounds(10, 10, 700, 700);
token[0].setPosition(600, 603);
token[1] = new Token(Color.red, null);
token[1].setBounds(10, 10, 700, 700);
token[1].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[2] = new Token(Color.blue, null);
token[2].setBounds(10, 10, 700, 700);
token[2].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[3] = new Token(Color.green, null);
token[3].setBounds(10, 10, 700, 700);
token[3].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[4] = new Token(Color.yellow, null);
token[4].setBounds(10, 10, 700, 700);
token[4].setPosition(600 + offset, 603 + offset);
break;
case 6:
token[0] = new Token();
token[0].setBounds(10, 10, 700, 700);
token[0].setPosition(600, 603);
token[1] = new Token(Color.red, null);
token[1].setBounds(10, 10, 700, 700);
token[1].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[2] = new Token(Color.blue, null);
token[2].setBounds(10, 10, 700, 700);
token[2].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[3] = new Token(Color.green, null);
token[3].setBounds(10, 10, 700, 700);
token[3].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[4] = new Token(Color.yellow, null);
token[4].setBounds(10, 10, 700, 700);
token[4].setPosition(600 + offset, 603 + offset);
offset = offset + 10;
token[5] = new Token(Color.cyan, null);
token[5].setBounds(10, 10, 700, 700);
token[5].setPosition(600 + offset, 603 + offset);
break;
default:
System.out.println("Invalid number of players");
}
}
// The location of the image should be specified here
monopolyImageLabel =
new JLabel(new ImageIcon(this.getClass().getResource("Monopoly_board.jpg")));
monopolyImageLabel.setBounds(-50, -30, 800, 750);
// The image and the tokens are added to the pane at different levels allowing them to overlap
layeredPane.add(monopolyImageLabel);
layeredPane.add(token[0], new Integer(1));
layeredPane.add(token[1], new Integer(2));
layeredPane.add(token[2], new Integer(3));
layeredPane.add(token[3], new Integer(4));
layeredPane.add(token[4], new Integer(5));
layeredPane.add(token[5], new Integer(6));
setSize(1500, 750);
setExtendedState(JFrame.MAXIMIZED_BOTH); // Sets the default window for the JFrame as a
// maximised
this.setResizable(false);
setTitle("Welcome to Monopoly");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Ensures the JFrame operation ends completely
// upon exiting the window
setVisible(true);
}
// This method displays the information panel and adds it to the pane
public void information_Panel() {
infoPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(textArea);
blackLineBorder = BorderFactory.createLineBorder(Color.BLACK);
TitledBorder title = BorderFactory.createTitledBorder(blackLineBorder, "Information Panel");
infoPanel.setBorder(title);
infoPanel.add(echoed_Text_Label, BorderLayout.NORTH);
// prevents any information from being added or deleted from the information panel.
textArea.setEditable(false);
infoPanel.add(scrollPane);
infoPanel.setBounds(750, 0, 600, 600); // specifies the desired coordinates of the panel being
// added to the layered pane
layeredPane.add(infoPanel);
}
// This method displays the command panel and adds it to the pane
public void command_Panel() {
commandPanel = new JPanel();
blackLineBorder = BorderFactory.createLineBorder(Color.BLACK);
JButton button = new JButton("Enter");
/*
* implements the actionlistener interface on the button to help execute a command when the
* button is clicked
*/
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (commandField.getText().isEmpty()) {
String command = null;
textArea.append(command);
}
else {
String command = commandField.getText();
textArea.append(command + "\n");
commandField.setText("");
}
}
});
// This invokes the actionListeners interface for actionPerformed (quick way to implement a key
// listener on the keyboards Enter button)
getRootPane().setDefaultButton(button);
commandPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
button.setPreferredSize(new Dimension(65, 20));
commandPanel.add(commandLabel);
commandPanel.add(commandField);
commandPanel.add(button);
commandPanel.setBounds(800, 630, 500, 50); // specifies the desired coordinates of the panel
// being added to the layered pane
layeredPane.add(commandPanel);
}
// Method which moves the tokens round the board one at a time
public void moveTokens() throws InterruptedException {
int i, j, offset;
offset = 0;
for (i = 0; i < token.length; i++) {
for (j = 0; j < locations.length; j++) {
token[i].setPosition(locations[j].x, locations[j].y);
repaint();
// controls the movement speed of the tokens across the board allowing for easy detection of
// their movement
Thread.sleep(300);
}
token[i].setPosition(defaultPosition.x + offset, defaultPosition.y + offset);
offset = offset + 15;
}
}
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
UI_Monopoly_Board obj = new UI_Monopoly_Board();
obj.information_Panel();
obj.command_Panel();
obj.moveTokens();
[enter image description here][1]
}
}
package sprint_One;
import java.awt.*;
import javax.swing.JComponent;
/*
* Each token has variables for location, dimension and shape, there's a constructor that allows the
* user to specify the colour of the shape the necessary accessor and mutator functions are provided
*/
public class Token extends JComponent {
/**
*
*/
private static final long serialVersionUID = 1L;
private int length;
private int breadth;
private int x;
private int y;
private Shape shape;
private Color color;
private String name;
private int balance;
public Token() {
super();
setVisible(true);
this.length = 15;
this.breadth = 15;
this.x = 5;
this.y = 5;
this.shape = new Rectangle(this.x, this.y, this.length, this.breadth);
this.color = Color.BLACK;
this.name = "";
this.balance = 20;
}
public Token(Color color, String name) {
this();
this.color = color;
this.name = name;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
// Method which specifies the x and y coordinates of the tokens
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
g2.setColor(color);
g2.fill(shape); // fills the shape with the colour specified
g2.draw(this.shape);
}
public Shape getShape() {
// TODO Auto-generated method stub
return this.shape;
}
}
Ok, you should learn how to use a debugger...
This is the line that causes your error:
layeredPane.add(token[2], new Integer(3));
And you initialise tokenlike this:
if(players >= 2 || players <= 6)
{
token = new Token[players];
So, what if players is 2? You will get an ArrayIndexOutOfBoundsException.
Another tip:
layeredPane.add(token[0], new Integer(1));
is not as readable as
layeredPane.add(token[0], 1);
I have a class MenuScreen on which I paint a lot of images to. (4 at the moment [that may not be a lot to you but it is to me])
only one renders no matter what, sometimes they some half-render, and other times they completely render,
and sometimes they don't render at all (The main one still renders)
Here is my code
public List<BufferedImage> im;
public MenuScreen() {
setTitle("ALevelUp 0.0.1 Alpha");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initImages();
JPanel p = new JPanel(new GridLayout(1, 1));
p.add(new JLabel(new ImageIcon(im.get(0))));
add(p);
setSize(766, 500);
setLocationRelativeTo(null);
setVisible(true);
System.err.println(getHeight() + "," + getWidth());
Graphics2D g = (Graphics2D) im.get(0).getGraphics();
draw(g);
}
public final void initImages() {
im = a.init();
}
public final void draw(Graphics2D g) {
BufferedImage s1 = im.get(1);
Graphics2D s1g = (Graphics2D) s1.getGraphics();
s1g.setFont(scale(a.getFont(), s1g, "Slot 1", s1));
s1g.setColor(Color.black);
s1g.drawString("Slot 1", s1.getWidth() / 2 - 23, s1.getHeight() / 2 + 7);
g.drawImage(s1, (getWidth() / 2) - (s1.getWidth() / 2) - 21,
47, rootPane);
s1g.setColor(new Color(253, 198, 147));
s1g.fillRect(106, 20, 100, 20);
s1g.setColor(Color.black);
s1g.drawString("Slot 2", s1.getWidth() / 2 - 23, s1.getHeight() / 2 + 7);
g.drawImage(s1, getWidth() / 2 - s1.getWidth() / 2 - 21, 179, rootPane);
s1g.setColor(new Color(253, 198, 147));
s1g.fillRect(106, 20, 100, 20);
s1g.setColor(Color.black);
s1g.drawString("Slot 3", s1.getWidth() / 2 - 23, s1.getHeight() / 2 + 7);
g.drawImage(s1, getWidth() / 2 - s1.getWidth() / 2 - 21, 311, rootPane);
}
public Font scale(Font f, Graphics g, String text, BufferedImage img) {
float ntry = 20.0f;
Font font = null;
while (2 < 3) {
font = f.deriveFont(ntry);
FontMetrics fm = g.getFontMetrics(font);
int width = fm.stringWidth(text);
if (width < img.getWidth()) {
return font;
}
}
}
Can anyone help me to understand why this happens and what I can do to fix it?
Edit: Here Are the image resources, if you need them:
The Main Screen
The Slot Panels
How it looks when it works
I had to modify most of the code to get something to work. I'm assuming that this is what you want.
Here are the changes I made.
I added a main method that called SwingUtilities invokeLater to put the Swing components on the Event Dispatch thread.
I split the code into 3 classes, DrawImage, DrawingPanel, and Snippet. DrawImage creates the four images. DrawingPanel draws the four images onto a JPanel. Snippet creates the JFrame and adds the drawing panel to the JFrame.
I defined the size of the drawing panel to hold 4 slots. I packed the JFrame so that
the JFrame would be the correct size to hold the drawing panel.
I overrode the paintComponent method to draw the four images from the image list. These images were already created in the DrawImage class. I called super.paintComponent to make sure all of the Swing children components were drawn correctly.
I created the images before I created the Swing GUI.
I used a method I created, centerString, to center the text in the images. I left the scale method alone.
Here's the modified code. Unlike yours, it's runnable.
package snippet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Snippet implements Runnable {
private JFrame frame;
private List<BufferedImage> imageList;
public Snippet() {
imageList = new ArrayList<BufferedImage>();
new DrawImage().createImages();
}
#Override
public void run() {
frame = new JFrame();
frame.setTitle("ALevelUp 0.0.1 Alpha");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel p = new DrawingPanel();
frame.add(p);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.out.println(frame.getHeight() + "," + frame.getWidth());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Snippet());
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID =
2535522354552193273L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(550, 350));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 50;
int y = 50;
for (int i = 0; i < 2; i++) {
BufferedImage image = null;
for (int j = 0; j < 2; j++) {
image = imageList.get(i * 2 + j);
g.drawImage(image, x, y, this);
x += image.getWidth() + 50;
}
x = 50;
y += image.getHeight() + 50;
}
}
}
public class DrawImage {
public void createImages() {
imageList.add(createImage("Slot 1"));
imageList.add(createImage("Slot 2"));
imageList.add(createImage("Slot 3"));
imageList.add(createImage("Slot 4"));
}
private BufferedImage createImage(String text) {
Rectangle r = new Rectangle(0, 0, 200, 100);
BufferedImage image = new BufferedImage(r.width, r.height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
Font font = g.getFont();
g.setFont(scale(font, g, text, image));
g.setColor(Color.BLACK);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.setColor(Color.YELLOW);
centerString(g, r, text, font);
g.dispose();
return image;
}
private Font scale(Font f, Graphics g, String text,
BufferedImage img) {
float ntry = 20.0f;
Font font = null;
while (2 < 3) {
font = f.deriveFont(ntry);
FontMetrics fm = g.getFontMetrics(font);
int width = fm.stringWidth(text);
if (width < img.getWidth()) {
return font;
}
}
}
/**
* This method centers a <code>String</code> in
* a bounding <code>Rectangle</code>.
* #param g - The <code>Graphics</code> instance.
* #param r - The bounding <code>Rectangle</code>.
* #param s - The <code>String</code> to center in the
* bounding rectangle.
* #param font - The display font of the <code>String</code>
*
* #see java.awt.Graphics
* #see java.awt.Rectangle
* #see java.lang.String
*/
private void centerString(Graphics g, Rectangle r, String s,
Font font) {
FontRenderContext frc =
new FontRenderContext(null, true, true);
Rectangle2D r2D = font.getStringBounds(s, frc);
int rWidth = (int) Math.round(r2D.getWidth());
int rHeight = (int) Math.round(r2D.getHeight());
int rX = (int) Math.round(r2D.getX());
int rY = (int) Math.round(r2D.getY());
int a = (r.width / 2) - (rWidth / 2) - rX;
int b = (r.height / 2) - (rHeight / 2) - rY;
g.setFont(font);
g.drawString(s, r.x + a, r.y + b);
}
}
}
How to 'fill' Unicode characters in labels in Swing?
I'm trying to make a user interface for the chess program I've recently programmed
(with chess pieces something like seen above). In it I'm using unicode characters to represent my chess pieces (\u2654 through \u265F).
The problem is as follows:
When I set the background of my chess piece JLabel to something like white, the entire label is filled (in my case it's a 50*50px square of white with the character on top). This leads to my pieces looking like tiles instead of just their pictures.
When I set the label to opaque, I just get a cookie cutter version of my chess piece, not one with its insides filled. E.G.
Is there a way to fill only the character?
If not I guess I'll make a sprite sheet but I like this because I can use the chess pieces' toString() methods for the labels.
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);
}
}
The two rows are generated through the sorcery of Java-2D. The trick is to:
Ignore the 'black' chess pieces on the basis that our color is actually coming from 'the spaces contained by the shape'. Those are larger in the white chess pieces.
Create a GlyphVector that represents the shape of the character. This is important for further operations in Java-2D.
Create a Rectangle the size of the image.
subtract() the shape of the character from the shape of the image.
Break that altered shape into regions.
Fill the regions with the background color, but skip the single region that starts at 0.0,0.0 (representing the outermost region which we need transparent).
Finally, fill the shape of the character itself using the outline color.
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);
}
}
Chess Board
This is what it might look like as a Chess Board (22.81 Kb).
Sprite sets
Sprite sets of chess pieces (64x64 pixel) rendered from Unicode characters - as a PNG with transparent BG. Each has 6 columns for the pieces x 2 rows for the opponents (total size 384x128 pixels).
Chess pieces with solid fill (bronze/pewter) (11.64Kb).
Chess pieces with gradient fill (gold/silver) (13.61Kb).
Chess pieces with gradient fill (darker cyan/magenta) (13.44Kb).
Code for Chess Board & Sprite Set
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);
}
}
See also
Developed out of the GlyphVector code as seen in this answer.
Resulted in UGlys - Unicode Glyphs at GitHub.
The problem I see is that the glyphs were designed to easily distinguish traditional black and white chess pieces. Note also the variation in font design. You may be able to create hue-themed pieces that preserve the black and white distinction using the HSB color space. Green and cyan are pictured below.
Addendum: For reference, here's a Mac OS X screenshot of #Andrew's glyph shape approach. Note the benefit of #Andrew's use of RenderingHints as the image is scaled.
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);
}
}
In the end, I found making a spritesheet to be the easier and simpler way to go about the problem. Each piece now corresponds to a graphic within the spritesheet instead of a character/glyph. Because of this, the pieces can't be resized as nicely but that's not the biggest deal.
#Andrew Thompson's idea with the GlyphVector seemed promising, but the matter of separating inner white space from outer white space remains difficult.
One (inefficient) idea I still have is to make a ton of chess piece glyphs starting from a very small font size and with a foregound color of white:
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);
}
then add one last chess piece with a black foreground:
JLabel chessPiece =new JLabel("\u2654");
chessPiece.setForeground(Color.black);
chessPiece.setFont(new Font("Sans-Serif", Font.PLAIN, BOARD_WIDTH/8)));
add(chessPiece);
Note that I haven't tested this out.
My Image declaration:
ImageIcon imageIcon1 = new ImageIcon(main.class.getResource("image1.png"));
Image image1 = imageIcon1.getImage();
How do I take image1, flip it along it's vertical axis and save it as another image?
I have googled and every solution I have found has come with some type of casting error.
Also, if there is a more efficient way to declare my image please let me know.
You state:
I have googled and every solution I have found has come with some type of casting error.
Which only tells us that you're doing something wrong but doesn't tell us what, limiting how we can help you. I can only tell you some steps that have worked for me:
Create another BufferedImage the same size as the first,
get its Graphics2D context via createGraphics(),
flip the graphics via an AffineTransform.getScaleInstance(-1, 1) for a horizontal flip
Don't forget to then translate the transform to bring the flipped image to where you want it.
draw the old image into the new image,
dispose the Graphics2D object.
If you need more help, then please show us what you've tried and include any and all error messages.
For instance, I played with this when playing with mirror sprite images a while back. Compile and run this to see what I mean:
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class FlipViaTransform {
private static final String SPRITE_SHEET_SPEC = "http://www.funorb.com/img/images/game/"
+ "central/dev_diary/sprite_sheet_full.gif";
private static final int TIMER_DELAY = 200;
private static final int SPRITE_ROWS = 8; // an 8 x 8 sprite sheet
public static void main(String[] args) {
try {
URL spriteSheetUrl = new URL(SPRITE_SHEET_SPEC);
BufferedImage spriteSheet = ImageIO.read(spriteSheetUrl);
final ImageIcon[] iconsA = new ImageIcon[64];
final ImageIcon[] iconsB = new ImageIcon[64];
double wD = (double) spriteSheet.getWidth() / SPRITE_ROWS;
double hD = (double) spriteSheet.getHeight() / SPRITE_ROWS;
int w = (int) wD;
int h = (int) hD;
// *** here's what I used to flip
AffineTransform at = AffineTransform.getScaleInstance(-1, 1); // *** flip
at.translate(-wD, 0); // *** translate so that flipped image is visible
for (int i = 0; i < SPRITE_ROWS; i++) {
for (int j = 0; j < SPRITE_ROWS; j++) {
int x = (int) (i * wD);
int y = (int) (j * hD);
BufferedImage imgA = spriteSheet.getSubimage(x, y, w, h);
BufferedImage imgB = new BufferedImage(imgA.getWidth(),
imgA.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = imgB.createGraphics();
g2.setTransform(at); // *** transform
g2.drawImage(imgA, 0, 0, null); // *** draw old image into new
g2.dispose(); // *** get rid of graphics2d object
iconsA[j * SPRITE_ROWS + i] = new ImageIcon(imgA);
iconsB[j * SPRITE_ROWS + i] = new ImageIcon(imgB);
}
}
final JLabel labelA = new JLabel("Image");
final JLabel labelB = new JLabel("Mirror Image");
labelA.setVerticalTextPosition(JLabel.BOTTOM);
labelB.setVerticalTextPosition(JLabel.BOTTOM);
labelA.setHorizontalTextPosition(JLabel.CENTER);
labelB.setHorizontalTextPosition(JLabel.CENTER);
labelA.setIcon(iconsA[0]);
labelB.setIcon(iconsB[0]);
final JPanel panel = new JPanel(new GridLayout(1, 0));
panel.add(labelA);
panel.add(labelB);
Timer spriteTimer = new Timer(TIMER_DELAY, new ActionListener() {
int spriteIndex = 0;
#Override
public void actionPerformed(ActionEvent arg0) {
labelA.setIcon(iconsA[spriteIndex]);
labelB.setIcon(iconsB[spriteIndex]);
spriteIndex++;
spriteIndex %= iconsA.length;
}
});
spriteTimer.start();
JOptionPane.showMessageDialog(null, panel, "AffineTransform Example", JOptionPane.PLAIN_MESSAGE);
spriteTimer.stop();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
which displays as:
I have never done this, but you can try to research if you can use a 3d party library such as ImageMagick or GraphicsMagic with Java. Those libraries can read PNG images and perform graphics operation on them.