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);
Related
I wrote a little Java program for a friend of mine, we have the same resolution ( 1920 * 1080 ), but his Screen in general is smaller than mine. To solve the problem I gave the GUI elements percentual coordinates, which works perfectly until I use fonts. The Font will be the same size, like mine which is like the code expects. The Bounds for a JButton for example says where to start where to end, but a font measured in points, so each inch has 72 points, a Font with 30 will always be half an inch. (Compare to the Images)
How can I fix this, I found nothing that could solve the problem in my eyes?
Image Before:
https://ibb.co/HXf0pt4
Image After:
https://ibb.co/1sbKyts
public class DrawMenu extends JLabel{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int sw = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
int sh = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
g.setFont(new Font("TimesRoman", Font.PLAIN, (int)Math.round(sw * 0.0078)));
g.drawString("Termine die nächsten 0 bis 7 Tage", (int)Math.round(sw * 0.026), (int)Math.round(sh * 0.176));
g.drawString("Termine die nächsten 8 bis 14 Tage", (int)Math.round(sw * 0.182), (int)Math.round(sh * 0.176));
repaint();
}
}
public class Gui {
static JFrame jfCounter, jfMenu, jfTask;
static DrawCounter drawc;
static DrawMenu drawm;
static DrawTask drawt;
static JButton kEnde, kNC, kA, kL, kEsc1, kEsc2, kEsc3, kEsc4, kEsc5, kLG, kLB, kAS, kEnter, kJFsw1, kJFsw2, kJFsw3,
kJFsw4, ko[] = new JButton[6], kSettings, ktw, ktla, ktle, ktlb, ktnt;
static JTextArea taAusgabe, taAusgabedw, taAusgabenw, taze, tabe, tati;
static JFormattedTextField nfTag, nfMonat, nfJahr, nfTagA, nfMonatA, nfJahrA;
static JTextField tfAnlass, tfkLBestimmt, tfAnlassA, tfAnlassAS, tfKonsole, tfKonsoleT, tfsettings[] = new JTextField[12], tftw,
tftis, tftlbs, tftnct, tftnci;
public Gui() {
int sw = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
int sh = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
System.out.println(sw + " " + sh);
// JFrame Settings
jfCounter = new JFrame();
jfCounter.setSize(sw, sh);
jfCounter.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfCounter.setLocationRelativeTo(null);
jfCounter.setExtendedState(JFrame.MAXIMIZED_BOTH);
jfCounter.setTitle("Tageszähler");
jfMenu = new JFrame();
jfMenu.setSize(sw, sh);
jfMenu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfMenu.setLocationRelativeTo(null);
jfMenu.setExtendedState(JFrame.MAXIMIZED_BOTH);
jfMenu.setTitle("Menü");
jfTask = new JFrame();
jfTask.setSize(sw, sh);
jfTask.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfTask.setLocationRelativeTo(null);
jfTask.setExtendedState(JFrame.MAXIMIZED_BOTH);
jfTask.setTitle("Task");
// JButtons
Border bor = BorderFactory.createLineBorder(Color.BLACK, 1);
Border boresc = BorderFactory.createLineBorder(Color.RED, 3);
kEnde = new JButton("Ende");
kEnde.addActionListener(new ActionHandler());
kEnde.setBounds((int) Math.round(sw * 0.026), (int) Math.round(sh * 0.509), (int) Math.round(sw * 0.195),
(int) Math.round(sh * 0.028));
kEnde.setBorder(bor);
jfCounter.add(kEnde);
kNC = new JButton("Neuer Counter");
kNC.addActionListener(new ActionHandler());
kNC.setBounds((int) Math.round(sw * 0.026), (int) Math.round(sh * 0.028), (int) Math.round(sw * 0.078),
(int) Math.round(sh * 0.028));
kNC.setBorder(bor);
jfCounter.add(kNC);
// JLabel / Draw
drawc = new DrawCounter();
drawc.setBounds(0, 0, sw, sh);
drawc.setVisible(true);
jfCounter.add(drawc);
drawm = new DrawMenu();
drawm.setBounds(0, 0, sw, sh);
drawm.setVisible(true);
jfMenu.add(drawm);
drawt = new DrawTask();
drawt.setBounds(0, 0, sw, sh);
drawt.setVisible(true);
jfTask.add(drawt);
// JFrame Final Visible
Gui.getJfMenu().setVisible(true);
}
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.
Id like multicolored changing text, I made a list with all the colors
I have 5 g.drawString(); functions running, each of them should be the next color in the list (one above each other.)
private Color[] colors = new Color[12];
Then in my constructor:
colors[0] = new Color(255, 0, 0);
colors[1] = new Color(255, 127, 0);
colors[2] = new Color(255, 255, 0);
colors[3] = new Color(127, 255, 0);
colors[4] = new Color(0, 255, 0);
colors[5] = new Color(0, 255, 127);
colors[6] = new Color(0, 255, 255);
colors[7] = new Color(0, 127, 255);
colors[8] = new Color(0, 0, 255);
colors[9] = new Color(127, 0, 255);
colors[10] = new Color(255, 0, 255);
colors[11] = new Color(255, 0, 127);
How would I make each each letter a different color?
Set The Color: g.setColor(Color object);
Example: g.setColor(colors[5]);
Write Text: g.drawString(String, x, y);
Example: g.drawString("S", 200, 300);
So, Id like S to be the color, colors[0], I made a table below:
Starting | First | Second | Fifth
S -- 0 11 10 7
N -- 1 0 11 8
A -- 2 1 0 9
K -- 3 2 1 10
E -- 4 3 2 11
So it would loop around though each color:
I tried making a function for this, I deleted the code because I'm an idiot -_-
In my main class, I have a game loop that calls the tick and render methods, tick first then render.
I have an enum called STATE which contains menu and game, then the variable gameState of the type state is set to STATE.menu
public enum state {
Menu,
Game,
}
public state gameState = state.Menu;
When gameState is equal to STATE.menu it will call menu.render(g ( <-- The variable im using for Graphics));
Each class has its own render and tick method.
-Tick method, for setting variables etc, if statements, yada yada yada
-Render method, anything to do with drawing pixels
Because the tick method is called every 0.0000000000000000001 seconds, the color changes every 9 millionth of a second and it looks very derpy.
So ill need a timer of some sorts that I can configure with a variable
I want each of the letters to be a different color, one after another in the list
you can refer to the table above if you don't understand but as an example,
the letter a should be colors[0]
and then b, colors[1]
and c, colors[2]
the colors should alter,
so a would be colors[2]
so b would be colors[0]
so c would be colors[1]
I've probably been unclear on 1001 things, so please shout at me in the comments ^-^
Thanks for reading!
If I understood correctly, there are mainly two issues:
Painting the letters in different colors, cycling through the given array
Updating the colors (but at a fixed time, not with every "tick")
Cycling through the colors can be achieved by introducing a "colorOffset". You can add this color offset to the index that you use to access the color in the array, and take this modulo the array length to obtain a valid array index:
int colorOffset = ... // Counted up or down all the time
// The index of the color for the i'th letter
int colorIndex = (i+colorOffset)%colors.length;
if (colorIndex < 0) colorIndex += colors.length;
g.setColor(colors[colorIndex]);
The second part, regarding the update: I assume that you have a game loop that is run in an own thread. Then, in thisTickMethodThatYouHaveBeenTalkingAbout, you can check the current system time with System.nanoTime(), and compute the time that has passed since the last update. If the time is larger than the desired interval, you perform an update, by increasing the colorOffset and triggering a repaint() (if necessary - you might cover this already with your render() method).
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MulticolorTextAnimation
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MulticolorTextAnimationPanel m = new MulticolorTextAnimationPanel();
f.getContentPane().add(m);
Thread thread = new Thread(new Runnable()
{
#Override
public void run()
{
while (true)
{
m.thisTickMethodThatYouHaveBeenTalkingAbout();
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
}
}
});
thread.setDaemon(true);
thread.start();
f.setSize(500,200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class MulticolorTextAnimationPanel extends JPanel
{
private String string;
private Color colors[];
private int colorOffset = 0;
private long lastUpdateNs = -1;
private final long updateIntervalMs = 250;
public MulticolorTextAnimationPanel()
{
setFont(new Font("Dialog", Font.BOLD, 45));
string = "I am a string!";
colors = new Color[12];
colors[0] = new Color(255, 0, 0);
colors[1] = new Color(255, 127, 0);
colors[2] = new Color(255, 255, 0);
colors[3] = new Color(127, 255, 0);
colors[4] = new Color(0, 255, 0);
colors[5] = new Color(0, 255, 127);
colors[6] = new Color(0, 255, 255);
colors[7] = new Color(0, 127, 255);
colors[8] = new Color(0, 0, 255);
colors[9] = new Color(127, 0, 255);
colors[10] = new Color(255, 0, 255);
colors[11] = new Color(255, 0, 127);
}
public void thisTickMethodThatYouHaveBeenTalkingAbout()
{
long ns = System.nanoTime();
if (lastUpdateNs < 0)
{
lastUpdateNs = ns;
}
long passedNs = (ns - lastUpdateNs);
long passedMs = passedNs / 1000000;
if (passedMs > updateIntervalMs)
{
// Increase or decrease the color offset,
// depending on whether the colors should
// cycle forward or backward
colorOffset--;
repaint();
lastUpdateNs = ns;
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
FontMetrics fontMetrics = g.getFontMetrics();
int x = 100;
int y = 100;
for (int i=0; i<string.length(); i++)
{
char c = string.charAt(i);
int colorIndex = (i+colorOffset)%colors.length;
if (colorIndex < 0)
{
colorIndex += colors.length;
}
g.setColor(colors[colorIndex]);
g.drawString(String.valueOf(c), x, y);
x += fontMetrics.charWidth(c);
}
}
}
Currently i'm trying to create a stimulated annealing algorithm solving the traveling salesman problem as well as creating a gui for it. The initial cities(points) and lines display but I can't get the doSA() method to successfully run. Any ideas, sorta stumped.
class SAPanel extends JPanel implements ActionListener{
private static final long serialVersionUID = 1L;
private City city,city2,city3,city4,city5,city6,city7,city8,city9,city10,city11,city12,city13,city14,city15,city16,city17,city18,city19,city20;
private int temp;
private Tour best, currentSolution;
int delay = 10;
static int POINTWIDTH = 8;
static Color POINTCOLOR = Color.MAGENTA;
static Color LINECOLOR = Color.CYAN;
Timer timer = new Timer(delay, this);
private static double coolingRate = .006;
public void start(){
temp = 10000;
timer.start();
}
public void intiSA(){
city = new City(60, 200);
TourManager.addCity(city);
city2 = new City(180, 200);
TourManager.addCity(city2);
city3 = new City(80, 180);
TourManager.addCity(city3);
city4 = new City(140, 180);
TourManager.addCity(city4);
city5 = new City(20, 160);
TourManager.addCity(city5);
city6 = new City(100, 160);
TourManager.addCity(city6);
city7 = new City(200, 160);
TourManager.addCity(city7);
city8 = new City(140, 140);
TourManager.addCity(city8);
city9 = new City(40, 120);
TourManager.addCity(city9);
city10 = new City(100, 120);
TourManager.addCity(city10);
city11 = new City(180, 100);
TourManager.addCity(city11);
city12 = new City(60, 80);
TourManager.addCity(city12);
city13 = new City(120, 80);
TourManager.addCity(city13);
city14 = new City(180, 60);
TourManager.addCity(city14);
city15 = new City(20, 40);
TourManager.addCity(city15);
city16 = new City(100, 40);
TourManager.addCity(city16);
city17 = new City(200, 40);
TourManager.addCity(city17);
city18 = new City(20, 20);
TourManager.addCity(city18);
city19 = new City(60, 20);
TourManager.addCity(city19);
city20 = new City(160, 20);
TourManager.addCity(city20);
//Initialize initial solution
currentSolution = new Tour();
currentSolution.generateIndividual();
best = currentSolution;
System.out.println("Initial solution distance: " + currentSolution.getDistance());
}
//energy represents the total distance of each tour
public static double acceptanceProbability(int energy, int newEnergy, double temp){
//if currentSolution energy is larger than newEnergy, return 1.0
if(newEnergy < energy){
return 1.0;
}
//as temp decreases, acceptance of the new solution becomes more selective
return Math.exp((energy-newEnergy) / temp);
}
public void doSA(){
//set new solution as the current solution
Tour newSolution = new Tour(currentSolution.getTour());
//get two random points on the solution
int tourPos1 = (int)(newSolution.tourSize() * Math.random());
int tourPos2 = (int)(newSolution.tourSize() * Math.random());
//get two cities depending on the selected points
City citySwap1 = newSolution.getCity(tourPos1);
City citySwap2 = newSolution.getCity(tourPos2);
//swap the cities on the selected points
newSolution.setCity(tourPos1, citySwap2);
newSolution.setCity(tourPos2, citySwap1);
int currentEnergy = currentSolution.getDistance();
int neighborEnergy = currentSolution.getDistance();
//accept new solution as the current solution if greater than random number
if(acceptanceProbability(currentEnergy, neighborEnergy, temp) > Math.random()){
currentSolution = new Tour(newSolution.getTour());
}
//keep the current solution as best if distance is greater
if(currentSolution.getDistance() > newSolution.getDistance()){
best = new Tour(currentSolution.getTour());
}
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2= (Graphics2D)(g);
g2.setStroke(new BasicStroke(3));
for(int x =0;x<19;x++){
//draw lines connecting each city in solution
g2.setColor(LINECOLOR);
g2.drawLine(best.getCity(x).getX(), best.getCity(x).getY(), best.getCity(x+1).getX(), best.getCity(x+1).getY());
g2.setColor(POINTCOLOR);
//draw all points
g2.fillOval(best.getCity(x).getX() - POINTWIDTH/2, best.getCity(x).getY() - POINTWIDTH/2, POINTWIDTH, POINTWIDTH);
}
//draw last reminding line, connecting last city to first city.
g2.setColor(LINECOLOR);
g2.drawLine(best.getCity(19).getX(), best.getCity(19).getY(), best.getCity(0).getX(), best.getCity(0).getY());
g2.setColor(POINTCOLOR);
g2.fillOval(best.getCity(0).getX() - POINTWIDTH/2, best.getCity(0).getY() - POINTWIDTH/2, POINTWIDTH, POINTWIDTH);
}
public void actionPerformed(ActionEvent e){
temp *= coolingRate -1;
if(temp >1){
doSA();
System.out.println("Final solution distance: " + best.getDistance());
System.out.println("Tour: " + best);
}
else{
((Timer)e.getSource()).stop();
}
}
}
Could be your initial parameters: Simulated Annealing is very parameter sensitive and it requires 2 parameters (initial temp and cooldown schedule), which makes it hard to tweak them. In my implementation, I've reduced it to 1 parameter by basing the cooldown on the amount of time still available.
Could also be a bug in your acceptanceProbability method. Write a unit test, which covers the corner cases, to prove it's correct. Here's my test impl.
Normally, I would just create the JLabel using a string as the first parameter and JLabel.CENTER as the second parameter; adding the label to the panel using BorderLayout.CENTER would then cause the text in the label to be aligned in the center of the panel.
However, I'm using the 'RichJLabel' class in order to get a drop shadow on my text. To do this, it overrides Component.paintComponent in such a way that the alignment information is lost, and the label's text is drawn in the top left of the panel no matter what I do.
From what I understand, the workaround for this is to encase the label inside of another panel; that way, I can align the panel itself inside the parent panel, but I'm uncertain of how exactly to do this.
My complete goal is to:
Figure out what font size a given string needs in order to fill up its parent JPanel
Add a drop shadow to that text
Center the text within its JPanel
Here's what I've got so far:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;
public class RichJLabel extends JLabel {
private int tracking;
public RichJLabel(String text, int tracking) {
super(text, JLabel.CENTER);
this.tracking = tracking;
}
private int left_x, left_y, right_x, right_y;
private Color left_color, right_color;
public void setLeftShadow(int x, int y, Color color) {
left_x = x;
left_y = y;
left_color = color;
}
public void setRightShadow(int x, int y, Color color) {
right_x = x;
right_y = y;
right_color = color;
}
public Dimension getPreferredSize() {
String text = getText();
FontMetrics fm = this.getFontMetrics(getFont());
int w = fm.stringWidth(text);
w += (text.length()-1)*tracking;
w += left_x + right_x;
int h = fm.getHeight();
h += left_y + right_y;
return new Dimension(w,h);
}
public void paintComponent(Graphics g) {
((Graphics2D)g).setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
char[] chars = getText().toCharArray();
FontMetrics fm = this.getFontMetrics(getFont());
int h = fm.getAscent();
int x = 0;
for(int i=0; i<chars.length; i++) {
char ch = chars[i];
int w = fm.charWidth(ch) + tracking;
g.setColor(left_color);
g.drawString(""+chars[i],x-left_x,h-left_y);
g.setColor(right_color);
g.drawString(""+chars[i],x+right_x,h+right_y);
g.setColor(getForeground());
g.drawString(""+chars[i],x,h);
x+=w;
}
((Graphics2D)g).setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
} // end paintComponent()
public static void main(String[] args) {
JPanel panel1 = new JPanel( new BorderLayout() );
panel1.setBackground( Color.BLUE );
panel1.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED ));
JPanel interiorPanel = new JPanel( new BorderLayout() );
panel1.add(interiorPanel, BorderLayout.CENTER);
RichJLabel label = new RichJLabel("100", 0);
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setVisible( true );
label.setForeground( Color.YELLOW );
interiorPanel.add(label, BorderLayout.CENTER);
label.setFont(new Font("Arial", Font.BOLD, 140));
label.setFont(label.getFont().deriveFont(140f));
//resize code
Font labelFont = label.getFont();
String labelText = label.getText();
int stringWidth = label.getFontMetrics(labelFont).stringWidth(labelText);
int componentWidth = interiorPanel.getWidth();
// Find out how much the font can grow in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)(labelFont.getSize() * widthRatio);
int componentHeight = interiorPanel.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
// Set the label's font size to the newly determined size.
label.setFont(new Font(labelFont.getName(), Font.BOLD, fontSizeToUse));
label.setLeftShadow(-3,-3,Color.BLACK);
// drop shadow w/ highlight
label.setRightShadow(2,3,Color.black);
label.setForeground(Color.gray);
JFrame frame = new JFrame("Label SSCCEE");
frame.getContentPane().add(panel1);
frame.pack();
frame.setVisible(true);
}
}
What it does right now is this:
The code was checking for the size of the container too soon. Before it is displayed, it has a width/height of 0.
Altered code
import java.awt.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;
public class RichJLabel extends JLabel {
private int tracking;
public RichJLabel(String text, int tracking) {
super(text, JLabel.CENTER);
this.tracking = tracking;
}
private int left_x, left_y, right_x, right_y;
private Color left_color, right_color;
public void setLeftShadow(int x, int y, Color color) {
left_x = x;
left_y = y;
left_color = color;
}
public void setRightShadow(int x, int y, Color color) {
right_x = x;
right_y = y;
right_color = color;
}
public Dimension getPreferredSize() {
String text = getText();
FontMetrics fm = this.getFontMetrics(getFont());
int w = fm.stringWidth(text);
w += (text.length()-1)*tracking;
w += left_x + right_x;
int h = fm.getHeight();
h += left_y + right_y;
return new Dimension(w,h);
}
public void paintComponent(Graphics g) {
((Graphics2D)g).setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
char[] chars = getText().toCharArray();
FontMetrics fm = this.getFontMetrics(getFont());
int h = fm.getAscent();
int x = 0;
for(int i=0; i<chars.length; i++) {
char ch = chars[i];
int w = fm.charWidth(ch) + tracking;
g.setColor(left_color);
g.drawString(""+chars[i],x-left_x,h-left_y);
g.setColor(right_color);
g.drawString(""+chars[i],x+right_x,h+right_y);
g.setColor(getForeground());
g.drawString(""+chars[i],x,h);
x+=w;
}
((Graphics2D)g).setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
} // end paintComponent()
public static void main(String[] args) {
JPanel panel1 = new JPanel( new BorderLayout() );
panel1.setBackground( Color.BLUE );
panel1.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED ));
JPanel interiorPanel = new JPanel( new BorderLayout() );
panel1.add(interiorPanel, BorderLayout.CENTER);
RichJLabel label = new RichJLabel("100", 0);
label.setLeftShadow(-3,-3,Color.BLACK);
// drop shadow w/ highlight
label.setRightShadow(2,3,Color.black);
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setVisible( true );
label.setForeground( Color.YELLOW );
interiorPanel.add(label, BorderLayout.CENTER);
label.setFont(new Font("Arial", Font.BOLD, 140));
label.setFont(label.getFont().deriveFont(140f));
//resize code
Font labelFont = label.getFont();
JFrame frame = new JFrame("Label SSCCEE");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setContentPane(panel1);
frame.pack();
frame.setVisible(true);
int componentWidth = interiorPanel.getWidth();
String labelText = label.getText();
int stringWidth = label.getFontMetrics(labelFont).stringWidth(labelText);
// Find out how much the font can grow in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)(labelFont.getSize() * widthRatio);
int componentHeight = interiorPanel.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
System.out.println("fontSizeToUse: " + fontSizeToUse);
if (fontSizeToUse<1) {
System.err.println("Font size less than 1!");
System.exit(1);
}
// Set the label's font size to the newly determined size.
label.setFont(new Font(labelFont.getName(), Font.BOLD, fontSizeToUse));
label.setForeground(Color.gray);
}
}
If it is this RichJLabel, then take a look at paintComponent. I would sugges making your own shadowed label, maybe consisting out of two shadow labels and one foreground label. I did not expect to see a 3 times drawing of every character. Problematic: inefficient and cannot do scripting languages like arabic or combining diacritic characters (one char letter, another accent).
At some points hacking around isn't worth it. If you had seen the sources, who knows.
I am not sure that I have the right code. It certainly might be of a very early version.
RichJLabel has a getPreferredSize() suitable for layouting. JPanel.setBounds(int, int, int, int) is the single method by which resizing is done. Hence you can use absolute layouting in a JPanel (null layout).
public class EPanel2 extends JPanel {
private RichJLabel label = new RichJLabel("", 0);
public EPanel2(String text) {
super(null);
setBackground(Color.GREEN.brighter().brighter());
label.setFont(new Font("Univers", Font.BOLD, 48));
label.setText(text);
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setForeground(Color.BLUE);
label.setLeftShadow(2, 2, Color.RED);
label.setRightShadow(2, 2, Color.ORANGE);
label.setVisible(true);
add(label);
}
#Override
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
Dimension labelSize = label.getPreferredSize();
int labelX = (width - labelSize.width) / 2;
int labelY = (height - labelSize.height) / 2;
label.setBounds(labelX, labelY, labelSize.width, labelSize.height);
}
}