Related
I want to make an animated numeric counter, like this one:
I want to be able to input the value and have the counter update with animation.
I can find how to do this on Android from Google, but I cannot find any information on how to make it in Java Swing. How would I make something like this in Swing?
This isn't a complete answer, but this is a working example of a sliding JPanel. This code could be modified to create the display in the question.
Here's the complete runnable example.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SlidingDigitGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SlidingDigitGUI());
}
private SlidingPanel secondPanel;
#Override
public void run() {
JFrame frame = new JFrame("Sliding Digit");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createSlidingPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
Animation animation = new Animation();
new Thread(animation).start();
}
public JPanel createSlidingPanel() {
String[] digitValues = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 4, false));
panel.setPreferredSize(new Dimension(300, 100));
Font font = panel.getFont();
Font derivedFont = font.deriveFont(Font.BOLD, 48F);
secondPanel = new SlidingPanel(digitValues, derivedFont);
secondPanel.setPanelValue("0");
panel.add(secondPanel);
return panel;
}
public class SlidingPanel extends JPanel {
private static final long serialVersionUID = 661553022861652947L;
private static final int MARGIN = 4;
private int imageY;
private BufferedImage slidingImage;
private Dimension characterDimension;
private final Font font;
private String currentValue;
private final String[] panelValues;
public SlidingPanel(String[] panelValues, Font font) {
this.panelValues = panelValues;
this.font = font;
this.characterDimension = calculateFontSize();
this.slidingImage = generateSlidingImage();
this.setPreferredSize(characterDimension);
}
private Dimension calculateFontSize() {
int maxWidth = 0;
int maxHeight = 0;
FontRenderContext frc = new FontRenderContext(null, true, true);
for (String s : panelValues) {
Rectangle2D r2D = font.getStringBounds(s, frc);
int rWidth = (int) Math.round(r2D.getWidth());
int rHeight = (int) Math.round(r2D.getHeight());
maxWidth = Math.max(maxWidth, rWidth);
maxHeight = Math.max(maxHeight, rHeight);
}
return new Dimension(maxWidth, maxHeight);
}
private BufferedImage generateSlidingImage() {
int height = calculateStringHeight() * (panelValues.length + 1);
BufferedImage slidingImage = new BufferedImage(characterDimension.width,
height, BufferedImage.TYPE_INT_RGB);
Graphics g = slidingImage.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, characterDimension.width, height);
g.setColor(Color.BLACK);
g.setFont(font);
int y = characterDimension.height - MARGIN;
for (String s : panelValues) {
g.drawString(s, 0, y);
y += calculateStringHeight();
}
g.drawString(panelValues[0], 0, y);
g.dispose();
return slidingImage;
}
public void setPanelValue(String value) {
int index = getValueIndex(value);
this.currentValue = value;
this.imageY = calculateStringHeight() * index;
repaint();
}
public void updatePanelValue(String value) {
if (!currentValue.equals(value)) {
int index = getValueIndex(value);
int finalY = calculateStringHeight() * index;
SliderAnimation sliderAnimation = new SliderAnimation(imageY, finalY);
new Thread(sliderAnimation).start();
this.currentValue = value;
}
}
private int getValueIndex(String value) {
for (int index = 0; index < panelValues.length; index++) {
if (value.equals(panelValues[index])) {
return index;
}
}
return -1;
}
private int calculateStringHeight() {
return characterDimension.height + MARGIN;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage subImage = slidingImage.getSubimage(0, imageY,
characterDimension.width,
characterDimension.height);
g.drawImage(subImage, 0, 0, this);
}
public class SliderAnimation implements Runnable {
private int originalY;
private int finalY;
public SliderAnimation(int originalY, int finalY) {
this.originalY = originalY;
this.finalY = finalY;
}
#Override
public void run() {
int differenceY = finalY - originalY;
if (finalY == 0) {
differenceY = characterDimension.height + MARGIN;
}
int steps = 10;
double difference = (double) differenceY / steps;
for (int index = 1; index <= steps; index++) {
imageY = (int) Math.round(difference * index + originalY);
update();
sleep(120L);
}
if (finalY == 0) {
imageY = 0;
update();
} else {
imageY = finalY;
}
}
private void update() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SlidingPanel.this.repaint();
}
});
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Animation implements Runnable {
#Override
public void run() {
while (true) {
update("3");
sleep(2000L);
update("8");
sleep(2000L);
}
}
private void update(final String value) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
secondPanel.updatePanelValue(value);
}
});
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Animation {
boolean loop=true;//true //loop
static int start=1;//1 //start
static int end=10+1;//20 // end + 1
int delay1=1000;//1s // delay
int delay2=1;//1ms // delay
Font font=new Font("Helvetica",Font.BOLD,25); //Font
Timer timer=new Timer(delay1, e -> move());JPanel panel = new JPanel();int[] size = {50,100};Point point = new Point(210,size[1]);
Timer timer1=null;int value=start-1;int i;
public static void main(String[] args) {if (start!=end) {new Animation();}}
public void move() {
timer.stop();value ++;
if (!loop && value==end) {timer.stop();}i=0;
timer1 = new Timer(delay2, e -> {
if (i==100) {
timer1.stop();
timer.start();
}
point.setLocation(point.getX(), point.getY()-1);
panel.setLocation(point);
panel.revalidate();
i++;
});timer1.start();
if (loop && value==end-1) {point.setLocation(point.getX(),size[1]+size[1]);value = start-1;}else if (value==end-1 && !loop){System.exit(0);}
}
public Animation() {
JFrame frame = new JFrame();frame.setSize(500,300);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.add(panel);frame.setLocationRelativeTo(null);
panel.setLocation(point);frame.setLayout(null);frame.revalidate();panel.setSize(new Dimension(size[0],size[1]*Math.abs(end-(start-1))));
panel.setLayout(new GridLayout(Math.abs(end-start)+start,1));if (!(end-start<0)) {for (int i=start;i!=(end-start)+start;i++) {JLabel la = new JLabel(String.valueOf(i));la.setFont(font);panel.add(la);
}}timer.start();frame.revalidate();frame.setVisible(true);
}
}
When i setSize of a jLabel, normally it grows towards bottom. How can i increase the height in positive y direction ?
After pressing init
Current Result
Expected result
My source code
private void initActionPerformed(java.awt.event.ActionEvent evt) {
int p = Integer.parseInt(abc[0].getText());
int q = Integer.parseInt(abc[1].getText());
int r = Integer.parseInt(abc[2].getText());
int s = Integer.parseInt(abc[3].getText());
int t = Integer.parseInt(abc[4].getText());
one.setSize(20, p*10 );
one.setBackground(Color.decode("#03A9F4"));
two.setSize(20, q*10 );
two.setBackground(Color.decode("#03A9F4"));
three.setSize(20, r*10 );
three.setBackground(Color.decode("#03A9F4"));
four.setSize(20, s*10 );
four.setBackground(Color.decode("#03A9F4"));
five.setSize(20, t*10 );
five.setBackground(Color.decode("#03A9F4"));
}
one,two,three are the label names.
abc is an array containing all the labels
You're finding out that Java considers positive y direction graphics to be down, which is in keeping with how computer monitors see y direction. Solutions include:
Figure out a maximum size, and subtract your y height from it to figure out where to start your JLabel.
Even better, don't use JLabels but draw within a JPanel's paintComponent, using the same calculations as above.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class GraphicsEg extends JPanel {
private static final int DATA_COLUMNS = 5;
private List<JSlider> sliders = new ArrayList<>();
private DrawPanel drawPanel = new DrawPanel(DATA_COLUMNS);
public GraphicsEg() {
JPanel sliderPanel = new JPanel(new GridLayout(1, 0, 5, 5));
SliderListener sliderListener = new SliderListener();
for (int i = 0; i < DATA_COLUMNS; i++) {
JSlider slider = new JSlider(0, 100, 50);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setPaintTrack(true);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(5);
slider.setOrientation(SwingConstants.VERTICAL);
slider.addChangeListener(sliderListener);
sliders.add(slider);
sliderPanel.add(slider);
}
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout(5, 5));
add(drawPanel, BorderLayout.CENTER);
add(sliderPanel, BorderLayout.PAGE_END);
sliderValuesIntoDrawPanel();
}
private void sliderValuesIntoDrawPanel() {
int[] data = new int[DATA_COLUMNS];
for (int i = 0; i < data.length; i++) {
data[i] = sliders.get(i).getValue();
}
drawPanel.setData(data);
}
private class SliderListener implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
sliderValuesIntoDrawPanel();
}
}
private static void createAndShowGui() {
GraphicsEg mainPanel = new GraphicsEg();
JFrame frame = new JFrame("GraphicsEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class DrawPanel extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final int PAD = 20;
private static final Color BORDER_COLOR = Color.BLUE;
private static final Color COLUMN_COLOR = Color.RED;
private static final double RELATIVE_COL_WIDTH = 2.0 / 3.0;
private int dataColumns = 0;
private int[] data;
public DrawPanel(int dataColumns) {
this.dataColumns = dataColumns;
data = new int[dataColumns];
setBorder(BorderFactory.createLineBorder(BORDER_COLOR));
}
public void setData(int[] data) {
this.data = data;
repaint();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < data.length; i++) {
drawColumn(g, i, data[i]);
}
}
private void drawColumn(Graphics g, int index, int columnHeight) {
g.setColor(COLUMN_COLOR);
int width = (int) (RELATIVE_COL_WIDTH * (PREF_W - 2 * PAD) / dataColumns);
int x = PAD + (index * (PREF_W - 2 * PAD)) / dataColumns;
int height = (columnHeight * (PREF_H - 2 * PAD)) / 100;
int y = PREF_H - PAD - height;
g.fillRect(x, y, width, height);
}
}
Ok, so I am making a monopoly game. I so far have a JFrame, with a JPanel acting as a board. I have loaded all necessary images. I create a Player object which extends JLabel, to represent the player on the board.
I am trying to set the location of (in hopes of moving pieces around the board) Player object (which is a JLabel), on the board (which is a JPanel). I tried the .setLocation method, .setBounds method.
For some reason, no matter what i do the Player object only shows up on the top middle of the JPanel. I was wondering how I could move the Player object on my board.
JFrame code (I attempt to move the JLabel in the bottom of the constructor):
package com.Game.Monopoly;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import net.miginfocom.swing.MigLayout;
//a class that represent the board (JFrame) and all of it components
public class GameFrame extends JFrame {
private final double SCALE;
// all the graphical components
private Board board;
private JLabel lblPlayerMoney;
private JLabel lblCurrentPlayer;
private JLabel lblDice1;
private JLabel lblDice2;
private JList lstPropertiesList;
private JButton btnEndTurn;
private JButton btnBuyProperty;
private JButton btnRollDice;
// all images needed
private ImageIcon imgDice1;
private ImageIcon imgDice2;
private ImageIcon imgDice3;
private ImageIcon imgDice4;
private ImageIcon imgDice5;
private ImageIcon imgDice6;
private ImageIcon icnAirplane;
// all players
private Player[] playerList;
// all properties
private Property[] propertiesList;
public GameFrame(double scale) {
// SCALE = scale;
SCALE = 1;
// set up the JFrame
setResizable(true);
setTitle("Monopoly");
// etUndecorated(true);
// set size to a scale of 1080p
setSize((int) (1920 * SCALE), (int) (1080 * SCALE));
setLayout(new MigLayout());
loadImages();
// add the components to the frame
board = new Board(SCALE);
board.setPreferredSize(new Dimension((int) (1024 * SCALE),
(int) (1024 * SCALE)));
board.setBackground(Color.BLACK);
add(board, "east, gapbefore 80");
lblCurrentPlayer = new JLabel("Current Player:" + " Player 1");
add(lblCurrentPlayer, "wrap");
lblPlayerMoney = new JLabel("Player1's money:" + "$14000000");
add(lblPlayerMoney, "wrap");
lstPropertiesList = new JList();
add(new JScrollPane(lstPropertiesList),
"span 2 2, grow, height 70:120:200");
btnRollDice = new JButton("Roll Dice");
add(btnRollDice, "wrap");
lblDice1 = new JLabel(imgDice1);
add(lblDice1);
lblDice2 = new JLabel(imgDice1);
add(lblDice2, "wrap");
btnBuyProperty = new JButton("Buy Property");
add(btnBuyProperty, "wrap, top");
btnEndTurn = new JButton("End Turn");
add(btnEndTurn, "aligny bottom");
setUpEventListeners();
loadProperties();
// load players
playerList = new Player[6];
playerList[0] = new Player("Player 1", icnAirplane);
// add Players to the board
board.add(playerList[0]);
playerList[0].setLocation(new Point(500, 230));
}
public static void main(String[] args) {
GameFrame board = new GameFrame(1);
board.setVisible(true);
}
// method to add event listeners
public void setUpEventListeners() {
// roll dice
btnRollDice.addActionListener(new ActionListener() {
// creates an object with an timers to help with rolling dice
class RollDice implements ActionListener {
private Timer time = new Timer(152, this);
private int count = 0;
public void actionPerformed(ActionEvent e) {
count++;
if (count == 21)
time.stop();
int whatDice1 = (int) (Math.random() * 6) + 1;
int whatDice2 = (int) (Math.random() * 6) + 1;
// set the icons of the labels according to the random
// number
if (whatDice1 == 1)
lblDice1.setIcon(imgDice1);
else if (whatDice1 == 2)
lblDice1.setIcon(imgDice2);
else if (whatDice1 == 3)
lblDice1.setIcon(imgDice3);
else if (whatDice1 == 4)
lblDice1.setIcon(imgDice4);
else if (whatDice1 == 5)
lblDice1.setIcon(imgDice5);
else if (whatDice1 == 6)
lblDice1.setIcon(imgDice6);
if (whatDice2 == 1)
lblDice2.setIcon(imgDice1);
else if (whatDice2 == 2)
lblDice2.setIcon(imgDice2);
else if (whatDice2 == 3)
lblDice2.setIcon(imgDice3);
else if (whatDice2 == 4)
lblDice2.setIcon(imgDice4);
else if (whatDice2 == 5)
lblDice2.setIcon(imgDice5);
else if (whatDice2 == 6)
lblDice2.setIcon(imgDice6);
}
public void roll() {
count = 0;
time.start();
}
}
// create a new dice roll object
RollDice roll = new RollDice();
// if the roll dice button is clicked
public void actionPerformed(ActionEvent arg0) {
roll.roll();
}
});
}
// load all images to memory
public void loadImages() {
BufferedImage i = null;
try {
i = ImageIO.read((getClass().getResource("/resources/Dice 1.png")));
imgDice1 = new ImageIcon(i.getScaledInstance(100, 100,
java.awt.Image.SCALE_SMOOTH));
i = ImageIO.read((getClass().getResource("/resources/Dice 2.png")));
imgDice2 = new ImageIcon(i.getScaledInstance(100, 100,
java.awt.Image.SCALE_SMOOTH));
i = ImageIO.read((getClass().getResource("/resources/Dice 3.png")));
imgDice3 = new ImageIcon(i.getScaledInstance(100, 100,
java.awt.Image.SCALE_SMOOTH));
i = ImageIO.read((getClass().getResource("/resources/Dice 4.png")));
imgDice4 = new ImageIcon(i.getScaledInstance(100, 100,
java.awt.Image.SCALE_SMOOTH));
i = ImageIO.read((getClass().getResource("/resources/Dice 5.png")));
imgDice5 = new ImageIcon(i.getScaledInstance(100, 100,
java.awt.Image.SCALE_SMOOTH));
i = ImageIO.read((getClass().getResource("/resources/Dice 6.png")));
imgDice6 = new ImageIcon(i.getScaledInstance(100, 100,
java.awt.Image.SCALE_SMOOTH));
i = ImageIO.read((getClass()
.getResource("/resources/Airplane Icon.png")));
icnAirplane = new ImageIcon(i.getScaledInstance(40, 40,
java.awt.Image.SCALE_SMOOTH));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// load all properties
public void loadProperties() {
propertiesList = new Property[40];
// set up the properties list
// (name, index, isBuyable, price, initial rent)
propertiesList[0] = new Property("Go", 0, false, 0, 0);
propertiesList[1] = new Property("Jacob's Field", 1, true, 600000,
20000);
propertiesList[2] = new Property("Community Chest", 2, false, 0, 0);
propertiesList[3] = new Property("Texas Stadium", 3, true, 600000,
40000);
propertiesList[4] = new Property("Income Tax", 4, false, 0, 0);
propertiesList[5] = new Property("O'Hare International Airport", 5,
true, 2000000, 250000);
propertiesList[6] = new Property("Grand Ole Opry", 6, true, 1000000,
60000);
propertiesList[7] = new Property("Chance", 7, false, 0, 0);
}
}
JPanel Code:
package com.Game.Monopoly;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Board extends JPanel {
private static final long serialVersionUID = 1L;
private Image board;
public Board(double scale) {
this.setPreferredSize(new Dimension((int) (1024 * scale),
(int) (1024 * scale)));
BufferedImage i = null;
try {
i = ImageIO.read((getClass().getResource("/resources/monopoly-board-web.jpg")));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
board = i.getScaledInstance((int) (1024 * scale), (int) (1024 * scale), java.awt.Image.SCALE_SMOOTH);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(board, 0, 0, this);
}
}
Player Object Code:
package com.Game.Monopoly;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
//a class representing a player with its graphical component
public class Player extends JLabel {
private String playerName;
private int money;
private Property[] propertiesOwned;
public Player(String n, ImageIcon icon) {
playerName = n;
this.setIcon(icon);
}
// changes the amount of money available
public void changeMoney(int amount) {
money = money + amount;
}
public void movePlayer(int x, int y){
this.setLocation(x, y);
}
}
There are a couple of ways you can achieve this, personally, the simplest would be to use custom painting directly and not bother with using Swing based components for the players.
The basic problem you have is JPanel uses a FlowLayout by default, which means that you will always be fighting layout manager. In this case you might consider using a custom layout manager, for example...
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Monopoly {
public static void main(String[] args) {
new Monopoly();
}
public Monopoly() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MonopolyBoard());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MonopolyBoard extends JPanel {
private List<JLabel> players;
public MonopolyBoard() {
setLayout(new MonopolyBoardLayout());
players = new ArrayList<>(2);
try {
players.add(makePlayer("/Dog.png"));
players.add(makePlayer("/Car.png"));
for (JLabel player : players) {
add(player, new Integer(0));
}
} catch (IOException exp) {
exp.printStackTrace();
}
Timer timer = new Timer(1000, new ActionListener() {
private int count = 0;
private Random rnd = new Random();
#Override
public void actionPerformed(ActionEvent e) {
int playerIndex = count % players.size();
JLabel player = players.get(playerIndex);
MonopolyBoardLayout layout = (MonopolyBoardLayout) getLayout();
int position = layout.getPosition(player);
position += rnd.nextInt(5) + 1;
if (position > 35) {
position -= 35;
}
layout.setPosition(player, position);
revalidate();
repaint();
count++;
}
});
timer.start();
}
protected JLabel makePlayer(String path) throws IOException {
JLabel label = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource(path))), JLabel.CENTER);
return label;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
for (int index = 0; index < 36; index++) {
Rectangle bounds = MonopolyBoardLayoutHelper.getCellBounds(index, width, height);
g2d.draw(bounds);
}
g2d.dispose();
}
}
public static class MonopolyBoardLayoutHelper {
private static Map<Integer, Point> mapBoardCells;
static {
mapBoardCells = new HashMap<>(25);
mapBoardCells.put(10, new Point(0, 8));
mapBoardCells.put(11, new Point(0, 7));
mapBoardCells.put(12, new Point(0, 6));
mapBoardCells.put(13, new Point(0, 5));
mapBoardCells.put(14, new Point(0, 4));
mapBoardCells.put(15, new Point(0, 3));
mapBoardCells.put(16, new Point(0, 2));
mapBoardCells.put(17, new Point(0, 1));
mapBoardCells.put(18, new Point(0, 0));
mapBoardCells.put(0, new Point(9, 9));
mapBoardCells.put(1, new Point(8, 9));
mapBoardCells.put(2, new Point(7, 9));
mapBoardCells.put(3, new Point(6, 9));
mapBoardCells.put(4, new Point(5, 9));
mapBoardCells.put(5, new Point(4, 9));
mapBoardCells.put(6, new Point(3, 9));
mapBoardCells.put(7, new Point(2, 9));
mapBoardCells.put(8, new Point(1, 9));
mapBoardCells.put(9, new Point(0, 9));
mapBoardCells.put(19, new Point(1, 0));
mapBoardCells.put(20, new Point(2, 0));
mapBoardCells.put(21, new Point(3, 0));
mapBoardCells.put(22, new Point(4, 0));
mapBoardCells.put(23, new Point(5, 0));
mapBoardCells.put(24, new Point(6, 0));
mapBoardCells.put(25, new Point(7, 0));
mapBoardCells.put(26, new Point(8, 0));
mapBoardCells.put(27, new Point(9, 0));
mapBoardCells.put(28, new Point(9, 1));
mapBoardCells.put(29, new Point(9, 2));
mapBoardCells.put(30, new Point(9, 3));
mapBoardCells.put(31, new Point(9, 4));
mapBoardCells.put(32, new Point(9, 5));
mapBoardCells.put(33, new Point(9, 6));
mapBoardCells.put(34, new Point(9, 7));
mapBoardCells.put(35, new Point(9, 8));
}
public static Rectangle getCellBounds(int index, int width, int height) {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
int size = Math.min(width, height);
int cellSize = size / 10;
int xOffset = (width - size) / 2;
int yOffset = (height - size) / 2;
Point point = mapBoardCells.get(index);
if (point != null) {
int x = xOffset + (point.x * cellSize);
int y = yOffset + (point.y * cellSize);
bounds = new Rectangle(x, y, cellSize, cellSize);
}
return bounds;
}
}
public static class MonopolyBoardLayout implements LayoutManager2 {
public static final int DEFAULT_CELL_SIZE = 64;
private Map<Component, Integer> cellConstraints;
public MonopolyBoardLayout() {
cellConstraints = new HashMap<>(5);
}
public Integer getPosition(Component comp) {
return cellConstraints.get(comp);
}
public void setPosition(Component comp, int position) {
cellConstraints.put(comp, position);
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof Integer) {
int cell = (int) constraints;
if (cell >= 0 && cell <= 35) {
cellConstraints.put(comp, cell);
} else {
throw new IllegalArgumentException(constraints + " is not within the bounds of a valid cell reference (0-35)");
}
} else {
throw new IllegalArgumentException(constraints + " is not a valid cell reference (integer within 0-35)");
}
}
#Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(DEFAULT_CELL_SIZE * 10, DEFAULT_CELL_SIZE * 10);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void invalidateLayout(Container target) {
}
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
cellConstraints.remove(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(DEFAULT_CELL_SIZE * 10, DEFAULT_CELL_SIZE * 10);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(DEFAULT_CELL_SIZE * 10, DEFAULT_CELL_SIZE * 10);
}
#Override
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = parent.getHeight();
Map<Integer, List<Component>> components = new HashMap<>(25);
for (Component child : parent.getComponents()) {
Integer cell = cellConstraints.get(child);
if (cell != null) {
List<Component> children = components.get(cell);
if (children == null) {
children = new ArrayList<>(4);
components.put(cell, children);
}
children.add(child);
} else {
child.setBounds(0, 0, 0, 0);
}
}
for (Map.Entry<Integer, List<Component>> entry : components.entrySet()) {
int index = entry.getKey();
Rectangle bounds = MonopolyBoardLayoutHelper.getCellBounds(index, width, height);
List<Component> comp = entry.getValue();
int xDelta = 0;
int yDelta = 0;
int availableWidth = bounds.width;
int availableHeight = bounds.height;
switch (comp.size()) {
case 2:
availableWidth /= 2;
xDelta = availableWidth;
break;
case 3:
case 4:
availableWidth /= 2;
xDelta = availableWidth;
availableHeight /= 2;
yDelta = availableHeight;
break;
}
int x = bounds.x;
int y = bounds.y;
for (int count = 0; count < comp.size() && count < 4; count++) {
Component child = comp.get(count);
child.setSize(availableWidth, availableHeight);
child.setLocation(x, y);
x += xDelta;
if (x >= bounds.x + bounds.width) {
x = bounds.x;
y += yDelta;
}
}
}
}
}
}
As you can see, this becomes real complicated real quick. This example currently only allows 4 players per cell, so if you want more, then you're going to have to create your own algorithim
I have JTable in that I need to Show Chart but i have tired several Code but not able to achieve waht i wanted to make. here what i have tried so far
http://www.jroller.com/Thierry/entry/swing_barchart_rendering_in_a
and i want to achieve according to this image
but how ever i dont get any Render-er for same.
Please Any suggestion will be welcomed.
I would try 3 columns table. For the middle column I would use a custom renderer - a JPanel with JLabels on it. The labels could have different columns and sizes.
The TableModel should keep datasource for the bars and preparing renderer component means reading the cell value, extracting barchar data from the cell and setting colors/sizes for the JLabels in the JPanel (renderer component)
Okay, here's an idea...
Instead of using a JTable, you could create a layout manager which would calculate the offsets and allow for elements to overlap "columns"
Prototype example - !! DO NOT USE IN PRODUCTION !!
This is an EXAMPLE only and should be used to LEARN from, do not try using this in production, there is a lot that needs to improved, such as a proper event notification API
This example makes use of the JIDE Common Layer API (the JideScrollPane in particular), you can get a copy from here
import com.jidesoft.swing.JideScrollPane;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
public class WorkSheetReport {
public static final Color WORKING_HOURS_COLOR = new Color(93, 89, 88);
public static final Color LUNCH_HOURS_COLOR = new Color(215, 142, 27);
public static final Color OTHER_HOURS_COLOR = new Color(30, 141, 213);
public static void main(String[] args) {
new WorkSheetReport();
}
public WorkSheetReport() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
DefaultTimeSheetReport report = new DefaultTimeSheetReport();
report.add(createTimeSheet(
"NWD/Full"));
report.add(createTimeSheet(
"Present",
new DefaultTimeEntry(WorkType.WORK, 10, 12.5),
new DefaultTimeEntry(WorkType.LUNCH, 12.5, 13.25),
new DefaultTimeEntry(WorkType.WORK, 13.25, 18),
new DefaultTimeEntry(WorkType.OTHER, 18, 18.5),
new DefaultTimeEntry(WorkType.WORK, 18.5, 20.5)));
report.add(createTimeSheet(
"0.5UUPL",
new DefaultTimeEntry(WorkType.WORK, 10, 12.5),
new DefaultTimeEntry(WorkType.LUNCH, 12.5, 17.75),
new DefaultTimeEntry(WorkType.OTHER, 17.75, 18),
new DefaultTimeEntry(WorkType.WORK, 18, 20)));
report.add(createTimeSheet(
"Present",
new DefaultTimeEntry(WorkType.WORK, 11, 13),
new DefaultTimeEntry(WorkType.LUNCH, 13, 13.5),
new DefaultTimeEntry(WorkType.WORK, 13.5, 17.75),
new DefaultTimeEntry(WorkType.OTHER, 17.75, 18),
new DefaultTimeEntry(WorkType.WORK, 18, 20.5)));
report.add(createTimeSheet(
"Present",
new DefaultTimeEntry(WorkType.WORK, 10, 12.75),
new DefaultTimeEntry(WorkType.LUNCH, 12.75, 13.5),
new DefaultTimeEntry(WorkType.WORK, 13.5, 17.5),
new DefaultTimeEntry(WorkType.OTHER, 17.5, 17.75),
new DefaultTimeEntry(WorkType.WORK, 17.75, 20.5)));
report.add(createTimeSheet(
"Present",
new DefaultTimeEntry(WorkType.WORK, 9.75, 12),
new DefaultTimeEntry(WorkType.LUNCH, 12, 12.5),
new DefaultTimeEntry(WorkType.WORK, 12.5, 17.25),
new DefaultTimeEntry(WorkType.OTHER, 17.25, 17.75),
new DefaultTimeEntry(WorkType.WORK, 17.75, 20)));
report.add(createTimeSheet(
"Present",
new DefaultTimeEntry(WorkType.WORK, 10, 11.75),
new DefaultTimeEntry(WorkType.LUNCH, 11.75, 12.25),
new DefaultTimeEntry(WorkType.WORK, 12.25, 17.5),
new DefaultTimeEntry(WorkType.OTHER, 17.5, 18),
new DefaultTimeEntry(WorkType.WORK, 18, 20.25)));
report.add(createTimeSheet(
"NWD/Full"));
report.add(createTimeSheet(
"Present",
new DefaultTimeEntry(WorkType.WORK, 10, 12.5),
new DefaultTimeEntry(WorkType.LUNCH, 12.5, 13.5),
new DefaultTimeEntry(WorkType.WORK, 13.5, 18),
new DefaultTimeEntry(WorkType.OTHER, 18, 18.5),
new DefaultTimeEntry(WorkType.WORK, 18.5, 20.5)));
TimeSheetReportPane pane = new TimeSheetReportPane(report);
JFrame frame = new JFrame("Testing");
frame.getContentPane().setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JideScrollPane sp = new JideScrollPane(pane);
sp.setColumnHeadersHeightUnified(true);
frame.add(sp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected TimeSheet createTimeSheet(String name, TimeEntry... entries) {
DefaultTimeSheet ts = new DefaultTimeSheet(name);
for (TimeEntry entry : entries) {
ts.add(entry);
}
return ts;
}
protected static String format(double time) {
time *= 60 * 60; // to seconds
int hours = (int) Math.floor(time / (60 * 60));
double remainder = time % (60 * 60);
int mins = (int) Math.floor(remainder / 60);
int secs = (int) Math.floor(time % 60);
return hours + ":" + mins + ":" + secs;
}
public class TimeSheetReportPane extends JPanel {
private TimeSheetReport report;
private int columnWidth;
private int rowHeight;
public TimeSheetReportPane(TimeSheetReport report) {
this.report = report;
setLayout(new GridBagLayout());
setBackground(Color.BLACK);
FontMetrics fm = getFontMetrics(UIManager.getFont("Label.font"));
columnWidth = fm.stringWidth("0000");
rowHeight = fm.getHeight() + 8;
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 0, 1, 0);
int count = 0;
for (TimeSheet ts : report) {
Color color = getColorForSheet(count);
TimeSheetPane pane = new TimeSheetPane(this, ts);
pane.setBackground(color);
add(pane, gbc);
count++;
}
gbc.weighty = 1;
JPanel fill = new JPanel();
fill.setOpaque(false);
add(fill, gbc);
}
public Color getColorForSheet(int index) {
Color endColor = Color.GRAY;
Color startColor = Color.DARK_GRAY;
double progress = (double) index / (double) getReport().size();
return blend(startColor, endColor, progress);
}
public TimeSheetReport getReport() {
return report;
}
public int getRowHeight() {
return rowHeight;
}
public int getColumnWidth() {
return columnWidth;
}
#Override
public void addNotify() {
super.addNotify();
configureEnclosingScrollPane();
}
protected void configureEnclosingScrollPane() {
Container parent = getParent();
if (parent instanceof JViewport) {
JViewport viewport = (JViewport) parent;
parent = viewport.getParent();
if (parent instanceof JideScrollPane) {
JideScrollPane sp = (JideScrollPane) parent;
sp.setRowFooterView(new RowFooter(this));
}
if (parent instanceof JScrollPane) {
JScrollPane sp = (JScrollPane) parent;
JLabel leftHeader = new JLabel("Status");
leftHeader.setForeground(Color.WHITE);
leftHeader.setBackground(Color.BLACK);
leftHeader.setOpaque(true);
leftHeader.setHorizontalAlignment(JLabel.CENTER);
leftHeader.setVerticalAlignment(JLabel.TOP);
leftHeader.setBorder(new EdgeBorder(EdgeBorder.Edge.RIGHT, Color.WHITE, Color.BLACK));
sp.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, leftHeader);
JLabel rightHeader = new JLabel("Working Hr");
rightHeader.setForeground(Color.WHITE);
rightHeader.setBackground(Color.BLACK);
rightHeader.setOpaque(true);
rightHeader.setHorizontalAlignment(JLabel.CENTER);
rightHeader.setBorder(new EdgeBorder(EdgeBorder.Edge.LEFT, Color.WHITE, Color.BLACK));
sp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, rightHeader);
sp.setRowHeaderView(new RowHeader(this));
sp.setColumnHeaderView(new ColumnHeader(this));
}
}
}
}
public class ColumnHeader extends JPanel {
private TimeSheetReportPane reportPane;
public ColumnHeader(TimeSheetReportPane tsrp) {
reportPane = tsrp;
setBackground(Color.BLACK);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridheight = GridBagConstraints.REMAINDER;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.ipady = 8;
Border border = new MatteBorder(0, 0, 0, 1, Color.GRAY);
for (int hour = 8; hour < 25; hour++) {
JLabel label = new JLabel(Integer.toString(hour)) {
#Override
public Dimension getPreferredSize() {
Dimension dim = super.getPreferredSize();
dim.width = reportPane.getColumnWidth();
return dim;
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
};
label.setVerticalAlignment(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setForeground(Color.WHITE);
label.setBorder(border);
add(label, gbc);
}
gbc.weightx = 1;
JPanel fill = new JPanel();
fill.setOpaque(false);
add(fill, gbc);
}
}
public class RowHeader extends JPanel {
private TimeSheetReportPane reportPane;
public RowHeader(TimeSheetReportPane tsrp) {
reportPane = tsrp;
setBackground(Color.BLACK);
setLayout(new GridBagLayout());
TimeSheetReport tsr = reportPane.getReport();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.ipadx = 16;
gbc.ipady = 2;
gbc.insets = new Insets(0, 0, 1, 0);
int index = 0;
for (TimeSheet ts : tsr) {
JLabel label = new JLabel(ts.getName()) {
#Override
public Dimension getPreferredSize() {
Dimension dim = super.getPreferredSize();
dim.height = reportPane.getRowHeight();
return dim;
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
};
label.setHorizontalAlignment(JLabel.CENTER);
label.setForeground(Color.WHITE);
label.setBackground(reportPane.getColorForSheet(index));
label.setOpaque(true);
add(label, gbc);
index++;
}
gbc.weighty = 1;
JPanel fill = new JPanel();
fill.setOpaque(false);
add(fill, gbc);
}
}
public class RowFooter extends JPanel {
private TimeSheetReportPane reportPane;
public RowFooter(TimeSheetReportPane tsrp) {
reportPane = tsrp;
setBackground(Color.BLACK);
setLayout(new GridBagLayout());
TimeSheetReport tsr = reportPane.getReport();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.ipadx = 36;
gbc.ipady = 2;
gbc.insets = new Insets(0, 0, 1, 0);
int index = 0;
for (TimeSheet ts : tsr) {
double time = ts.getWorkingHours();
String workHrs = "";
if (time > 0) {
workHrs = format(time);
}
JLabel label = new JLabel(workHrs) {
#Override
public Dimension getPreferredSize() {
Dimension dim = super.getPreferredSize();
dim.height = reportPane.getRowHeight();
return dim;
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
};
label.setHorizontalAlignment(JLabel.CENTER);
label.setForeground(Color.WHITE);
label.setBackground(reportPane.getColorForSheet(index));
label.setOpaque(true);
add(label, gbc);
index++;
}
gbc.weighty = 1;
JPanel fill = new JPanel();
fill.setOpaque(false);
add(fill, gbc);
}
}
public static class EdgeBorder implements Border {
public enum Edge {
LEFT,
RIGHT
}
private Edge edge;
private Color startColor;
private Color endColor;
public EdgeBorder(Edge edge, Color startColor, Color endColor) {
this.edge = edge;
this.startColor = startColor;
this.endColor = endColor;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
int xPos = x;
switch (edge) {
case RIGHT:
xPos = x + (width - 1);
}
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(x, 0),
new Point(x, height),
new float[]{0, 1},
new Color[]{startColor, endColor});
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(lgp);
g2d.drawLine(xPos, y, xPos, y + height);
}
#Override
public Insets getBorderInsets(Component c) {
int left = edge == Edge.LEFT ? 1 : 0;
int right = edge == Edge.RIGHT ? 1 : 0;
return new Insets(0, left, 0, right);
}
#Override
public boolean isBorderOpaque() {
return false;
}
}
/**
* Blend two colors.
*
* #param color1 First color to blend.
* #param color2 Second color to blend.
* #param ratio Blend ratio. 0.5 will give even blend, 1.0 will return color1,
* 0.0 will return color2 and so on.
* #return Blended color.
*/
public static Color blend(Color color1, Color color2, double ratio) {
float r = (float) ratio;
float ir = (float) 1.0 - r;
float rgb1[] = new float[3];
float rgb2[] = new float[3];
color1.getColorComponents(rgb1);
color2.getColorComponents(rgb2);
float red = rgb1[0] * r + rgb2[0] * ir;
float green = rgb1[1] * r + rgb2[1] * ir;
float blue = rgb1[2] * r + rgb2[2] * ir;
if (red < 0) {
red = 0;
} else if (red > 255) {
red = 255;
}
if (green < 0) {
green = 0;
} else if (green > 255) {
green = 255;
}
if (blue < 0) {
blue = 0;
} else if (blue > 255) {
blue = 255;
}
Color color = null;
try {
color = new Color(red, green, blue);
} catch (IllegalArgumentException exp) {
exp.printStackTrace();
}
return color;
}
public class TimeSheetPane extends JPanel {
private final JPanel timeEntriesPane;
public TimeSheetPane(TimeSheetReportPane reportPane, TimeSheet ts) {
timeEntriesPane = new JPanel(new TimeSheetLayoutManager(reportPane.getColumnWidth(), reportPane.getRowHeight()));
timeEntriesPane.setBackground(Color.BLACK);
setBorder(new EmptyBorder(1, 0, 1, 0));
setLayout(new BorderLayout());
add(timeEntriesPane);
for (TimeEntry te : ts) {
JLabel label = createLabel(te.getType().getColor());
String startTime = format(te.getStartTime());
String duration = format(te.getDuration());
label.setToolTipText("<html>StartTime: " + startTime + "<br>Duration: " + duration);
timeEntriesPane.add(label, te);
}
}
protected JLabel createLabel(Color color) {
JLabel label = new JLabel();
label.setOpaque(true);
label.setBackground(color);
return label;
}
}
public class TimeSheetLayoutManager implements LayoutManager2 {
private Map<Component, TimeEntry> mapConstraints;
private int colWidth;
private int rowHeight;
public TimeSheetLayoutManager(int colWidth, int rowHeight) {
mapConstraints = new HashMap<>(25);
this.colWidth = colWidth;
this.rowHeight = rowHeight;
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof TimeEntry) {
mapConstraints.put(comp, (TimeEntry) constraints);
} else {
throw new IllegalArgumentException(
constraints == null ? "Null is not a valid constraint"
: constraints.getClass().getName() + " is not a valid TimeEntry constraint"
);
}
}
#Override
public Dimension maximumLayoutSize(Container target) {
return preferredLayoutSize(target);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void invalidateLayout(Container target) {
}
#Override
public void addLayoutComponent(String name, Component comp) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void removeLayoutComponent(Component comp) {
mapConstraints.remove(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(colWidth * (24 - 8), rowHeight);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int width = parent.getWidth() - (insets.left + insets.right);
int height = rowHeight;
int hourWidth = colWidth;
int offset = 8;
for (Component comp : mapConstraints.keySet()) {
TimeEntry te = mapConstraints.get(comp);
double startTime = te.getStartTime();
double duration = te.getDuration();
startTime -= offset;
int x = (int) Math.round(startTime * hourWidth);
int unitWidth = (int) Math.round(duration * hourWidth);
comp.setLocation(x, insets.top);
comp.setSize(unitWidth, height);
}
}
}
public enum WorkType {
WORK(WORKING_HOURS_COLOR),
LUNCH(LUNCH_HOURS_COLOR),
OTHER(OTHER_HOURS_COLOR);
private Color color;
private WorkType(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
public interface TimeEntry {
public WorkType getType();
public double getStartTime();
public double getDuration();
}
public interface TimeSheet extends Iterable<TimeEntry> {
public String getName();
public int size();
public TimeEntry get(int index);
public double getWorkingHours();
}
public interface TimeSheetReport extends Iterable<TimeSheet> {
public int size();
public TimeSheet get(int index);
}
public class DefaultTimeEntry implements TimeEntry {
private final double startTime;
private final double endTime;
private final WorkType workType;
public DefaultTimeEntry(WorkType type, double startTime, double endTime) {
this.startTime = startTime;
this.endTime = endTime;
this.workType = type;
}
#Override
public double getStartTime() {
return startTime;
}
public double getEndTime() {
return endTime;
}
#Override
public double getDuration() {
return endTime - startTime;
}
#Override
public WorkType getType() {
return workType;
}
}
public class DefaultTimeSheet implements TimeSheet {
private final List<TimeEntry> timeEntries;
private final String name;
public DefaultTimeSheet(String name) {
this.name = name;
timeEntries = new ArrayList<>(25);
}
public TimeSheet add(TimeEntry te) {
timeEntries.add(te);
return this;
}
#Override
public Iterator<TimeEntry> iterator() {
return timeEntries.iterator();
}
#Override
public int size() {
return timeEntries.size();
}
#Override
public TimeEntry get(int index) {
return timeEntries.get(index);
}
#Override
public String getName() {
return name;
}
#Override
public double getWorkingHours() {
double time = 0;
for (TimeEntry te : this) {
switch (te.getType()) {
case WORK:
time += te.getDuration();
break;
}
}
return time;
}
}
public class DefaultTimeSheetReport implements TimeSheetReport {
private final List<TimeSheet> timeSheets;
public DefaultTimeSheetReport() {
timeSheets = new ArrayList<>(25);
}
public DefaultTimeSheetReport add(TimeSheet ts) {
timeSheets.add(ts);
return this;
}
#Override
public int size() {
return timeSheets.size();
}
#Override
public TimeSheet get(int index) {
return timeSheets.get(index);
}
#Override
public Iterator<TimeSheet> iterator() {
return timeSheets.iterator();
}
}
}
I need to add a label on the right hand side of a JMenuItem, like the labels shown below:
I have an application that uses Ctrl++ and Ctrl+- to zoom into an image. However, the + key by default (without Shift) is the = key. When I try adding accelerators for these menu items, the Ctrl+- shortcut label displays as "Ctrl+Minus" (I would prefer "Ctrl -") and the Ctrl++ shortcut label displays as "Ctrl+Equals" (even worse - in the interest of user experience, I would prefer "Ctrl +"):
menuBar_view_zoomIn.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, ActionEvent.CTRL_MASK));
I want Ctrl++ to display as "Ctrl +" and Ctrl+- to display as "Ctrl -". How can this be done?
not an answer, you need to search for
paint() to heavy, paintComponent() for lightweight JPopup, JMenu (for custom painting can be switch to isHeavyWeight...)
overlay JLabel into container (few question about JTable by #Guillaume Polet and #Robin)
create own JMenu/JPopup (see my comment to your question)
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.plaf.basic.BasicArrowButton;
public class ComboBoxMenuExample extends JFrame {
public ComboBoxMenuExample() {
super("ComboBoxMenu Example");
String[] itemStr = {"name", "Red", "Blue", "number", "255,0,0", "0,0,255",
/*separator*/ "system", "control", "controlHighlight", "controlShadow", "text"};
JMenuItem[] menuItems = new JMenuItem[7];
menuItems[0] = new JMenuItem(itemStr[1]);
menuItems[1] = new JMenuItem(itemStr[2]);
menuItems[2] = new JMenuItem(itemStr[4]);
menuItems[3] = new JMenuItem(itemStr[5]);
menuItems[4] = new JMenuItem(itemStr[8]);
menuItems[5] = new JMenuItem(itemStr[9]);
menuItems[6] = new JMenuItem(itemStr[10]);
JMenu[] menus = new JMenu[4];
menus[0] = new JMenu(itemStr[0]);
menus[1] = new JMenu(itemStr[3]);
menus[2] = new JMenu(itemStr[6]);
menus[3] = new JMenu(itemStr[7]);
menus[0].add(menuItems[0]);
menus[0].add(menuItems[1]);
menus[1].add(menuItems[2]);
menus[1].add(menuItems[3]);
menus[3].add(menuItems[4]);
menus[3].add(menuItems[5]);
menus[2].add(menus[3]);
menus[2].add(menuItems[6]);
JMenu menu = ComboMenuBar.createMenu(menuItems[0].getText());
menu.add(menus[0]);
menu.add(menus[1]);
menu.addSeparator();
menu.add(menus[2]);
ComboMenuBar comboMenu = new ComboMenuBar(menu);
JComboBox combo = new JComboBox();
combo.addItem(itemStr[1]);
combo.addItem(itemStr[2]);
combo.addItem(itemStr[4]);
combo.addItem(itemStr[5]);
combo.addItem(itemStr[8]);
combo.addItem(itemStr[9]);
combo.addItem(itemStr[10]);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(new ComboPanel("Fake ComboBox", comboMenu));
getContentPane().add(new ComboPanel("ComboBox", combo));
}
class ComboPanel extends JPanel {
ComboPanel(String title, JComponent c) {
setLayout(new FlowLayout());
setBorder(new TitledBorder(title));
add(c);
}
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {
}
ComboBoxMenuExample frame = new ComboBoxMenuExample();
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setSize(370, 100);
frame.setVisible(true);
}
}
class ComboMenuBar extends JMenuBar {
JMenu menu;
Dimension preferredSize;
public ComboMenuBar(JMenu menu) {
this.menu = menu;
Color color = UIManager.getColor("Menu.selectionBackground");
UIManager.put("Menu.selectionBackground", UIManager.getColor("Menu.background"));
UIManager.put("Menu.selectionBackground", color);
menu.updateUI();
MenuItemListener listener = new MenuItemListener();
setListener(menu, listener);
add(menu);
}
class MenuItemListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
menu.setText(item.getText());
menu.requestFocus();
}
}
private void setListener(JMenuItem item, ActionListener listener) {
if (item instanceof JMenu) {
JMenu menu1 = (JMenu) item;
int n = menu1.getItemCount();
for (int i = 0; i < n; i++) {
setListener(menu1.getItem(i), listener);
}
} else if (item != null) { // null means separator
item.addActionListener(listener);
}
}
public String getSelectedItem() {
return menu.getText();
}
#Override
public void setPreferredSize(Dimension size) {
preferredSize = size;
}
#Override
public Dimension getPreferredSize() {
if (preferredSize == null) {
Dimension sd = super.getPreferredSize();
Dimension menuD = getItemSize(menu);
Insets margin = menu.getMargin();
Dimension retD = new Dimension(menuD.width, margin.top
+ margin.bottom + menuD.height);
menu.setPreferredSize(retD);
preferredSize = retD;
}
return preferredSize;
}
private Dimension getItemSize(JMenu menu) {
Dimension d = new Dimension(0, 0);
int n = menu.getItemCount();
for (int i = 0; i < n; i++) {
Dimension itemD;
JMenuItem item = menu.getItem(i);
if (item instanceof JMenu) {
itemD = getItemSize((JMenu) item);
} else if (item != null) {
itemD = item.getPreferredSize();
} else {
itemD = new Dimension(0, 0); // separator
}
d.width = Math.max(d.width, itemD.width);
d.height = Math.max(d.height, itemD.height);
}
return d;
}
public static class ComboMenu extends JMenu {
ArrowIcon iconRenderer;
public ComboMenu(String label) {
super(label);
iconRenderer = new ArrowIcon(SwingConstants.SOUTH, true);
setBorder(new EtchedBorder());
setIcon(new BlankIcon(null, 11));
setHorizontalTextPosition(JButton.LEFT);
setFocusPainted(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension d = this.getPreferredSize();
int x = Math.max(0, d.width - iconRenderer.getIconWidth() - 3);
int y = Math.max(0,
(d.height - iconRenderer.getIconHeight()) / 2 - 2);
iconRenderer.paintIcon(this, g, x, y);
}
}
public static JMenu createMenu(String label) {
return new ComboMenu(label);
}
}
class ArrowIcon implements Icon, SwingConstants {
private static final int DEFAULT_SIZE = 11;
//private static final int DEFAULT_SIZE = 5;
private int size;
private int iconSize;
private int direction;
private boolean isEnabled;
private BasicArrowButton iconRenderer;
public ArrowIcon(int direction, boolean isPressedView) {
this(DEFAULT_SIZE, direction, isPressedView);
}
public ArrowIcon(int iconSize, int direction, boolean isEnabled) {
this.size = iconSize / 2;
this.iconSize = iconSize;
this.direction = direction;
this.isEnabled = isEnabled;
iconRenderer = new BasicArrowButton(direction);
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
iconRenderer.paintTriangle(g, x, y, size, direction, isEnabled);
}
#Override
public int getIconWidth() {
//int retCode;
switch (direction) {
case NORTH:
case SOUTH:
return iconSize;
case EAST:
case WEST:
return size;
}
return iconSize;
}
#Override
public int getIconHeight() {
switch (direction) {
case NORTH:
case SOUTH:
return size;
case EAST:
case WEST:
return iconSize;
}
return size;
}
}
class BlankIcon implements Icon {
private Color fillColor;
private int size;
public BlankIcon() {
this(null, 11);
}
public BlankIcon(Color color, int size) {
//UIManager.getColor("control")
//UIManager.getColor("controlShadow")
fillColor = color;
this.size = size;
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if (fillColor != null) {
g.setColor(fillColor);
g.drawRect(x, y, size - 1, size - 1);
}
}
#Override
public int getIconWidth() {
return size;
}
#Override
public int getIconHeight() {
return size;
}
}