I have a custom button that is not being drawn properly. It shows up as a dot in the upper left hand corner. I have three classes. One for the button, one for the menu or drawing of several buttons and a main class that calls the menu.
Class 1 - button
#Override
protected void paintComponent(Graphics g) {
g.setColor(Color.white);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(img, this.x, this.y,this.getWidth(), this.getHeight(), null);
g2d.setFont(this.font);
g2d.drawString(this.label, x, y);
}
Class 2 - menu
public void draw(Graphics g, int width, int height) {
int x, y;
for(int i = 0; i < buttons.length; i++) {
x = (int) (width / 2 - buttons[i].getWidth() / 2);
y = (int) (height / 2 - buttons[i].getHeight() / 2);
buttons[i].setBounds(x, y + (i*60), buttons[i].getWidth(), buttons[i].getHeight());
buttons[i].paintComponent(g);
}
}
Class 3 - main
if(gMenu != null) {
gMenu.draw(g, gWindow.getWidth(), gWindow.getHeight());
}
Edit: To clarify what I'm trying to do is create a popup menu with a few custom buttons (components).
Edit: I got them to draw, but the mouse listener doesn't work.
here is the menu class
public class Menu extends JComponent {
GameWindow window;
public Menu(GameWindow window) {
this.window = window;
this.setVisible(true);
}
public void addChildToPanel(JComponent child) {
int width = (int) getWidth();
if(child.getWidth() > width) {
width = child.getWidth();
}
int height = (int) getHeight();
height += child.getHeight();
setSize(width, height);
Dimension screen = new Dimension(window.getWidth(), window.getHeight());
int x = (screen.width - width) / 2;
int y = (screen.height - height) / 2;
setBounds(x, y, width, height);
}
}
Here is the button class
public class MenuButton extends JComponent implements MouseListener {
private BufferedImage img;
private BufferedImage img_h;
private int x, y;
private String label;
private Font font;
private int state = 0;
// state 0 = normal
// state 1 = highlight
// state 2 = pressed
public MenuButton(BufferedImage img, BufferedImage img_h, String label, Font font) {
this.setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
this.img_h = img_h;
this.img = img;
this.label = label;
this.font = font;
setVisible(true);
setBounds(0, 0, img.getWidth(), img.getHeight());
this.addMouseListener(this);
}
#Override
protected void paintComponent(Graphics g) {
g.setColor(Color.white);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
switch (state) {
case 0:
g2d.drawImage(img, this.getBounds().x, this.getBounds().y,this.getWidth(), this.getHeight(), null);
break;
case 1:
g2d.drawImage(img_h, this.getBounds().x, this.getBounds().y,this.getWidth(), this.getHeight(), null);
break;
case 2:
g2d.drawImage(img, this.x, this.y,this.getWidth(), this.getHeight(), null);
break;
}
g2d.setFont(this.font);
int size = g2d.getFontMetrics(font).stringWidth(this.label);
int x = this.getBounds().x + this.getWidth() - 20 - size;
int y = this.getBounds().y + 29;
g2d.drawString(this.label,x, y);
}
public void setState(int state) {
this.state = state;
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
setState(1);
}
#Override
public void mouseExited(MouseEvent e) {
setState(0);
}
#Override
public void mousePressed(MouseEvent e) {
setState(2);
}
#Override
public void mouseReleased(MouseEvent e) {
setState(1);
}
}
Child class that I call draw on
public class PauseMenu extends Menu {
private int width;
private int height;
private MenuButton[] buttons = new MenuButton[4];
public PauseMenu(GameWindow window) {
super(window);
Font font = null;
BufferedImage img = null;
BufferedImage img_h = null;
try {
InputStream is = getClass().getResourceAsStream("/fonts/ALDOPC.ttf");
font = Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(Font.PLAIN, 24f);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(font);
img = ImageIO.read(getClass().getResourceAsStream("/gui/bg_menu_button_round.png"));
img_h = ImageIO.read(getClass().getResourceAsStream("/gui/bg_menu_button_round_highlight.png"));
}
catch(Exception e)
{
System.out.print("Failed to load resources");
System.out.println();
}
MenuButton resume = new MenuButton(img, img_h, "CONTINUE", font);
final MenuButton quit = new MenuButton(img, img_h, "QUIT", font);
MenuButton vid = new MenuButton(img, img_h, "VIDEO", font);
MenuButton sound = new MenuButton(img, img_h, "SOUND", font);
buttons[0] = resume;
buttons[1] = vid;
buttons[2] = sound;
buttons[3] = quit;
for(int i = 0; i < buttons.length; i++) {
int x = (window.getWidth() - img.getWidth()) / 2;
int y = (window.getHeight() - img.getHeight()) / 2;
buttons[i].setBounds(x, y + (i * img.getHeight()), img.getWidth(), img.getHeight());
this.addChildToPanel(buttons[i]);
}
}
public void draw(Graphics g) {
for(int i = 0; i < buttons.length; i++)
buttons[i].paintComponent(g);
}
}
Related
I am working on a Music Player
I am using a JSlider as seek bar and using a JLabel to draw text on screen, such as song name.
I am new to Graphics2D
Here's the minimized code:
public class JSliderDemo extends JFrame
{
JLabel label;
JSlider seek = new JSlider();
int y = 10;
public JSliderDemo()
{
setSize(400, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
createWindow();
setVisible(true);
startThread();
}
public void createWindow()
{
JPanel panel = new JPanel(null);
panel.setOpaque(true);
panel.setBackground(Color.BLUE);
label = new Component();
label.setSize(400, 400);
label.setLocation(0, 0);
createSlider();
panel.add(seek);
panel.add(label);
add(panel);
}
protected void createSlider()
{
seek.setUI(new SeekBar(seek, 300, 10, new Dimension(20, 20), 5,
Color.DARK_GRAY, Color.RED, Color.RED));
seek.setOrientation(JProgressBar.HORIZONTAL);
seek.setOpaque(false);
seek.setLocation(10, 50);
seek.setSize(300, 20);
seek.setMajorTickSpacing(0);
seek.setMinorTickSpacing(0);
seek.setMinimum(0);
seek.setMaximum(1000);
}
protected void startThread()
{
Thread thread = new Thread(new Runnable(){
#Override
public void run()
{
try
{
while(true)
{
if(y == label.getHeight()){y = 1;}
label.repaint();
y += 1;
Thread.sleep(100);
}
}
catch(Exception ex){}
}
});
thread.start();
}
protected class Component extends JLabel
{
#Override
public void paintComponent(Graphics g)
{
Graphics2D gr = (Graphics2D) g;
gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gr.setColor(Color.RED);
gr.setFont(new Font("Calibri", Font.PLAIN, 16));
gr.drawString("Slider", 50, y);
}
}
public static void main(String[] args)
{
new JSliderDemo();
}
}
The Custom Slider UI class prints a line each time the JSlider is repainted.
Through this, I was able to find out that, when I call repaint() for JLabel it automatically repaints JSlider with it even though JSlider is not included in JLabel.
Output :
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........
Now if I remove label.repaint() from the Thread, then the JSlider is not re-painted.
Output:
Slider re-painted
Slider re-painted
Is the repaint() method supposed to work like this?
Here's the Custom Slider UI class :
package jsliderdemo;
import java.awt.*;
import javax.swing.*;
import java.awt.geom.RoundRectangle2D;
import javax.swing.plaf.basic.BasicSliderUI;
public class SeekBar extends BasicSliderUI
{
private int TRACK_ARC = 5;
private int TRACK_WIDTH = 8;
private int TRACK_HEIGHT = 8;
private Color backGround = Color.GRAY;
private Color trackColor = Color.RED;
private Color thumbColor = Color.WHITE;
private Dimension THUMB_SIZE = new Dimension(20, 20);
private final RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float();
public SeekBar(final JSlider b, int width, int height, Dimension thumbSize, int arc,
Color backGround, Color trackColor, Color thumbColor)
{
super(b);
this.TRACK_ARC = arc;
this.TRACK_WIDTH = width;
this.TRACK_HEIGHT = height;
this.THUMB_SIZE = thumbSize;
this.backGround = backGround;
this.trackColor = trackColor;
this.thumbColor = thumbColor;
}
#Override
protected void calculateTrackRect()
{
super.calculateTrackRect();
if (isHorizontal())
{
trackRect.y = trackRect.y + (trackRect.height - TRACK_HEIGHT) / 2;
trackRect.height = TRACK_HEIGHT;
}
else
{
trackRect.x = trackRect.x + (trackRect.width - TRACK_WIDTH) / 2;
trackRect.width = TRACK_WIDTH;
}
trackShape.setRoundRect(trackRect.x, trackRect.y, trackRect.width, trackRect.height, TRACK_ARC, TRACK_ARC);
}
#Override
protected void calculateThumbLocation()
{
super.calculateThumbLocation();
if (isHorizontal())
{
thumbRect.y = trackRect.y + (trackRect.height - thumbRect.height) / 2;
}
else
{
thumbRect.x = trackRect.x + (trackRect.width - thumbRect.width) / 2;
}
}
#Override
protected Dimension getThumbSize()
{
return THUMB_SIZE;
}
private boolean isHorizontal()
{
return slider.getOrientation() == JSlider.HORIZONTAL;
}
#Override
public void paint(final Graphics g, final JComponent c)
{
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
#Override
public void paintTrack(final Graphics g)
{
System.out.println("Slider re-painted");
Graphics2D g2 = (Graphics2D) g;
Shape clip = g2.getClip();
boolean horizontal = isHorizontal();
boolean inverted = slider.getInverted();
// Paint shadow.
//g2.setColor(new Color(170, 170 ,170));
//g2.fill(trackShape);
// Paint track background.
g2.setColor(backGround);
g2.setClip(trackShape);
trackShape.y += 1;
g2.fill(trackShape);
trackShape.y = trackRect.y;
g2.setClip(clip);
// Paint selected track.
if (horizontal)
{
boolean ltr = slider.getComponentOrientation().isLeftToRight();
if (ltr) inverted = !inverted;
int thumbPos = thumbRect.x + thumbRect.width / 2;
if (inverted)
{
g2.clipRect(0, 0, thumbPos, slider.getHeight());
}
else
{
g2.clipRect(thumbPos, 0, slider.getWidth() - thumbPos, slider.getHeight());
}
}
else
{
int thumbPos = thumbRect.y + thumbRect.height / 2;
if (inverted)
{
g2.clipRect(0, 0, slider.getHeight(), thumbPos);
}
else
{
g2.clipRect(0, thumbPos, slider.getWidth(), slider.getHeight() - thumbPos);
}
}
g2.setColor(trackColor);
g2.fill(trackShape);
g2.setClip(clip);
}
#Override
public void paintThumb(final Graphics g)
{
g.setColor(thumbColor);
g.fillOval(thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height);
}
#Override
public void paintFocus(final Graphics g) {}
}
I want to write a custom subclass of JLabel that would have two images attached to the border, that can be moved by moving the mouse. Real effects like this:
Here's my subclass, how could I add these attached images?
public class Rect extends JLabel{
private int width,height;
public Rect (int width,int height){
this.width = width;
this.height = height;
setText("b1");
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(0, 0, this.width, this.height);
}
public void reDraw(){
this.repaint();
}
public void setWidth(int width) {
this.width = width;
repaint();
}
public void setHeight(int height) {
this.height = height;
repaint();
}
}
To do this there are 4 things you should to do:
Extend an AbstractBorder not a Jlabel, then you can easily add your custom border to any component, not just a jLabel.
Override the paintBorder method so that you can draw your border.
Add an mouse action listeners to keep track of your border images.
And lastly you need a bit of logic to manage your border images.
I found this question interesting so I took a crack at making something as a test. It came out well, and does what you want, but will need a bit of work to get it looking correct. See below for a break down of each point.
Example image before we look at the code:
Extend an AbstractBorder:
public class MyCustomBorder extends AbstractBorder
{
private Color borderColour;
private int borderThickness = 10;
private Point firstSlider = new Point(0, 0);
private Point secondSlider = new Point(0, 0);
private BufferedImage firstSliderImage;
private BufferedImage secondSliderImage;
Boolean draggingFirst = false;
Boolean draggingSecond = false;
//See usage info
public MyCustomBorder(Color colour, int thickness, Point firstSlider, BufferedImage firstSliderImage, Point secondSlider, BufferedImage secondSliderImage)
{
borderColour = colour;
borderThickness = thickness;
this.firstSlider = firstSlider;
this.secondSlider = secondSlider;
this.firstSliderImage = firstSliderImage;
this.secondSliderImage = secondSliderImage;
}
Override the paintBorder method and insets:
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
super.paintBorder(c, g, x, y, width, height);
Graphics2D g2d = null;
if (g instanceof Graphics2D)
{
g2d = (Graphics2D) g;
//Draw border fill (currently hard coded to white, but can be changed)
g2d.setColor(Color.white);
//Top
g2d.fill(new Rectangle2D.Double(0, 0, width, borderThickness));
//Left
g2d.fill(new Rectangle2D.Double(0, 0, borderThickness, height));
//Bottom
g2d.fill(new Rectangle2D.Double(0, height-borderThickness, width, borderThickness));
//Right
g2d.fill(new Rectangle2D.Double(width-borderThickness, 0, borderThickness, height));
//draw black seperator
g2d.setColor(borderColour);
//Top
g2d.fill(new Rectangle2D.Double(borderThickness, borderThickness, width-(borderThickness*2), 1));
//Left
g2d.fill(new Rectangle2D.Double(borderThickness, borderThickness, 1, height-(borderThickness*2)));
//Bottom
g2d.fill(new Rectangle2D.Double(borderThickness, height-borderThickness-1, width-(borderThickness*2), 1));
//Right
g2d.fill(new Rectangle2D.Double(width-borderThickness-1, borderThickness, 1, height-(borderThickness*2)));
//draw sliders an custom position
g2d.drawImage(scale(secondSliderImage), null, secondSlider.x, secondSlider.y);
g2d.drawImage(scale(firstSliderImage), null, firstSlider.x, firstSlider.y);
}
}
#Override
public Insets getBorderInsets(Component c)
{
return (getBorderInsets(c, new Insets(borderThickness, borderThickness, borderThickness, borderThickness)));
}
#Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.left = insets.top = insets.right = insets.bottom = borderThickness;
return insets;
}
#Override
public boolean isBorderOpaque()
{
return false;
}
}
Add mouse action listeners:
//listeners for dragging
void addListeners(Component button)
{
button.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
{
public void mouseDragged(java.awt.event.MouseEvent evt)
{
//Only drag if a slider was selected
if (draggingFirst)
{
//update position of silder
firstSlider = snapToEdge(evt.getPoint(), evt.getComponent());
evt.getComponent().repaint();
}
else if (draggingSecond)
{
//update position of silder
secondSlider = snapToEdge(evt.getPoint(), evt.getComponent());
evt.getComponent().repaint();
}
}
});
button.addMouseListener(new java.awt.event.MouseAdapter()
{
//check if a slider was selected
public void mousePressed(java.awt.event.MouseEvent evt)
{
if (isInside(evt.getPoint(), firstSlider))
{
draggingFirst = true;
}
else if (isInside(evt.getPoint(), secondSlider))
{
draggingSecond = true;
}
}
public void mouseReleased(java.awt.event.MouseEvent evt)
{
//cancel selected slider
draggingFirst = false;
draggingSecond = false;
}
});
}
Logic:
//check if a slider was selected
private Boolean isInside(Point clicked, Point toCheck)
{
if (clicked.x > toCheck.x && clicked.x < toCheck.x + borderThickness)
{
if (clicked.y > toCheck.y && clicked.y < toCheck.y + borderThickness)
{
return true;
}
}
return false;
}
//snap a sliders co-ords to as edge
private Point snapToEdge(Point dragged, Component label)
{
//work out how close to each edge
int topEdge = dragged.y;
int leftEdge = dragged.x;
int rightEdge = label.getWidth()- dragged.x;
int bottomEdge = label.getHeight() - dragged.y;
//snap to slider co-ords to closest edge
if (topEdge < leftEdge && topEdge < rightEdge && topEdge < bottomEdge)
{
dragged.y = 0;
}
else if (leftEdge < rightEdge && leftEdge < bottomEdge)
{
dragged.x = 0;
}
else if (rightEdge < bottomEdge)
{
dragged.x = label.getWidth()-borderThickness;
}
else
{
dragged.y = label.getHeight()-borderThickness;
}
return dragged;
}
//scale slider images to fit border size
public BufferedImage scale(BufferedImage image)
{
BufferedImage resizedImage = null;
if (image != null)
{
double border = borderThickness;
resizedImage = new BufferedImage(borderThickness, borderThickness, TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
AffineTransform at = AffineTransform.getScaleInstance(border / (double)image.getWidth(), border / (double)image.getHeight());
g.drawRenderedImage(image, at);
}
return resizedImage;
}
The full code to copy and paste can be found here:
https://github.com/sorifiend/customBorder/blob/master/MyCustomBorder.java
Usage Example:
You can put this code in your form class to add a border to most swing components. In this example I added it to a jLabel called my_jLabel:
//Create border
MyCustomBorder border = new MyCustomBorder(Color.BLACK, 10, new Point(0, 0), img1, new Point(0, 0), img2);
//Add border to component called my_jLabel
my_jLabel.setBorder(border);
//Add action listeners for dragging sliders (very important)
border.addListeners(my_jLabel);
So I have code like this:
public class TestPane extends JPanel {
private Rectangle selection = new Rectangle();
private Point clickPoint;
private BufferedImage tempimage;
public TestPane() {
try {
tempimage = ImageIO.read(new File("/Users/droop//omega.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int minX = Math.min(e.getX(), clickPoint.x);
int minY = Math.min(e.getY(), clickPoint.y);
int maxX = Math.max(e.getX(), clickPoint.x);
int maxY = Math.max(e.getY(), clickPoint.y);
selection.x = minX;
selection.y = minY;
selection.width = maxX - minX;
selection.height = maxY - minY;
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
clickPoint = new Point(e.getPoint());
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
#Override
public Dimension getPreferredSize() {
return tempimage == null ? new Dimension(200, 200) : new Dimension(tempimage.getWidth(), tempimage.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - tempimage.getWidth()) / 2;
int y = (getHeight() - tempimage.getHeight()) / 2;
g2d.drawImage(tempimage, x, y, this);
if (selection.width > 0 && selection.height > 0) {
g2d.setColor(new Color(0, 0, 255, 64));
g2d.fill(selection);
g2d.setColor(Color.BLUE);
g2d.draw(selection);
}
g2d.dispose();
}
}
What I am trying to do is: change this code so I can change the picture using a button click. SO I want to have my TestPane created and put on frame but load the image later on with a button click.
And there is one more problem : sometimes the picture is too big to display on TestPane so I added scrools but then x and y coordinates of the mouse click are not synchronized with drawing the shape. When scrolls are on and I do the mouse click then the rectangle is being drawn above NOT at the exact place.
please help
i am developing an application in which user load image can scale it, also can save it.
can also rotate image through menu item click rotate.
on click rotate one other frame opens and the last positioned or last scaled image load into rotate panel.
now when user click on rotate option then image should be saved in that position but it is not done.
if anyone knows it then please help me.
i have made 2 files
1. load image and save image that is ScaleIMG and
2. to rotate image that is RotateIMGn.
ScaleIMG.java
package logic;
import logic.RotateIMGn;
public class ScaleIMG extends JFrame {
private static final long serialVersionUID = 1L;
public static int widthx,heightx;
public static String passpath;
public static void main(String[] args)
{
new ScaleIMG().run();
}
public void run()
{
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
ScaleIMG frame1 = new ScaleIMG();
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.getContentPane().setLayout(new BorderLayout());
frame1.getContentPane().add(new ViewPane());
frame1.pack();
frame1.setLocationRelativeTo(null);
frame1.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public ScaleIMG() {
final ImagePane s = new ImagePane();
setTitle("Keyur");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 500, 300);
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu mnFile = new JMenu("File");
menuBar.add(mnFile);
JMenuItem mntmLoadImage = new JMenuItem("Load Image");
mnFile.add(mntmLoadImage);
JMenuItem mntmSaveImage = new JMenuItem("Save Image");
mntmSaveImage.addActionListener(new ActionListener()
{
#Override
public void actionPerformed (ActionEvent e)
{
try
{
s.save("D:\\Workspace\\ScaleImage\\src\\images", "scaled_img_");
} catch (IOException e1)
{
e1.printStackTrace();
}
}
});
mnFile.add(mntmSaveImage);
JSeparator separator = new JSeparator();
mnFile.add(separator);
JMenuItem mntmExit = new JMenuItem("Exit");
mnFile.add(mntmExit);
JMenu mnEdit = new JMenu("Edit");
menuBar.add(mnEdit);
JMenuItem mntmIncreaseBright = new JMenuItem("Increase Bright");
mnEdit.add(mntmIncreaseBright);
JMenuItem mntmDecreaseBright = new JMenuItem("Decrease Bright");
mnEdit.add(mntmDecreaseBright);
JSeparator separator_1 = new JSeparator();
mnEdit.add(separator_1);
JMenuItem mntmRestoreImage = new JMenuItem("Restore Image");
mnEdit.add(mntmRestoreImage);
JMenuItem mntmRotateImage = new JMenuItem("Rotate Image");
mnEdit.add(mntmRotateImage);
mntmRotateImage.addActionListener(new ActionListener() {
#Override
public void actionPerformed (ActionEvent e)
{
System.out.println(widthx);
System.out.println(heightx);
try
{
s.save("D:\\Workspace\\ScaleImage\\src\\images", "scaled_img_");
RotateIMGn rm = new RotateIMGn(passpath);
JFrame frame = new JFrame();
frame.setContentPane(rm);
frame.pack();
frame.setVisible(true);
} catch (IOException e1)
{
e1.printStackTrace();
}
}
});
JMenu mnHelp = new JMenu("Help");
menuBar.add(mnHelp);
JMenuItem mntmHelpCtrl = new JMenuItem("Help ctrl + K");
mnHelp.add(mntmHelpCtrl);
JMenuItem mntmAboutImageEditor = new JMenuItem("About Image Editor");
mnHelp.add(mntmAboutImageEditor);
JSeparator separator_2 = new JSeparator();
mnHelp.add(separator_2);
JMenuItem mntmAboutCompany = new JMenuItem("About Company");
mnHelp.add(mntmAboutCompany);
}
public class ViewPane extends JPanel {
private static final long serialVersionUID = 1L;
public ViewPane() {
setLayout(null);
ImagePane imagePane = new ImagePane();
imagePane.setSize(imagePane.getPreferredSize());
imagePane.setLocation(0, 0);
add(imagePane);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1200, 665);
}
}
public static class ImagePane extends JPanel {
private static final long serialVersionUID = 1L;
private BufferedImage bg;
private BufferedImage scaled;
public String pathpass1;
public String namepass1;
public ImagePane() {
try {
bg = ImageIO.read(getClass().getResource("/images/src11.jpg"));
pathpass1="D:\\Workspace\\ScaleImage\\src\\images";
namepass1="src11.jpg";
scaled = getScaledInstanceToFit(bg, new Dimension(600, 600));
} catch (IOException ex) {
ex.printStackTrace();
}
setBackground(Color.BLACK);
MouseHandler handler = new MouseHandler();
addMouseListener(handler);
addMouseMotionListener(handler);
}
public void save(String path, String name) throws IOException
{
BufferedImage bf = new BufferedImage(widthx, heightx, BufferedImage.TYPE_INT_RGB);
Graphics gg = bf.getGraphics();
gg.drawImage(scaled,0,0,widthx,heightx,null);
System.out.println(widthx);
System.out.println(heightx);
String s = "/images/src11.jpg";
String sub = s.substring(s.lastIndexOf("/")+1);
System.out.println(sub);
if (bf != null)
{
name += bf.getWidth() + "x" + bf.getHeight();
ImageIO.write(bf, "jpg", new File(path + File.separator + name + ".jpg"));
passpath = path+File.separator+name+".jpg";
pathpass1 =path;
namepass1=sub;
System.out.println(pathpass1);
}
else
{
throw new NullPointerException("Scaled instance is null");
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? new Dimension(200, 200) : new Dimension(scaled.getWidth(), scaled.getHeight());
}
#Override
public void invalidate() {
super.invalidate();
scaled = getScaledInstanceToFit(bg, getSize());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - scaled.getWidth()) / 2;
int y = (getHeight() - scaled.getHeight()) / 2;
g2d.drawImage(scaled, x, y, this);
g2d.dispose();
}
public enum MouseAction {
Move(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)),
ResizeSouth(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)),
ResizeNorth(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)),
ResizeEast(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)),
ResizeWest(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)),
ResizeNorthEast(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)),
ResizeNorthWest(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)),
ResizeSouthEast(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)),
ResizeSouthWest(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
private Cursor cursor;
private MouseAction(Cursor cursor) {
this.cursor = cursor;
}
public Cursor getCursor() {
return cursor;
}
}
public class MouseHandler extends MouseAdapter {
private MouseAction action;
private Point clickPoint;
private boolean ignoreMoves;
protected void updateAction(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int width = getWidth();
int height = getHeight();
if (x < 10 && y < 10) {
action = MouseAction.ResizeNorthWest;
} else if (x > width - 10 && y < 10) {
action = MouseAction.ResizeNorthWest;
} else if (y < 10) {
action = MouseAction.ResizeNorth;
} else if (x < 10 && y > height - 10) {
action = MouseAction.ResizeSouthWest;
} else if (x > width - 10 && y > height - 10) {
action = MouseAction.ResizeSouthEast;
} else if (y > height - 10) {
action = MouseAction.ResizeSouth;
} else if (x < 10) {
action = MouseAction.ResizeWest;
} else if (x > width - 10) {
action = MouseAction.ResizeEast;
} else {
action = MouseAction.Move;
}
setCursor(action.getCursor());
}
#Override
public void mouseMoved(MouseEvent e) {
if (!ignoreMoves) {
updateAction(e);
}
}
#Override
public void mousePressed(MouseEvent e) {
updateAction(e);
ignoreMoves = true;
clickPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
clickPoint = null;
ignoreMoves = false;
}
#Override
public void mouseDragged(MouseEvent e) {
switch (action) {
case Move: {
Point p = e.getPoint();
p.x -= clickPoint.x;
p.y -= clickPoint.y;
p = SwingUtilities.convertPoint(ImagePane.this, p, getParent());
setLocation(p);
}
break;
case ResizeWest: {
Point p = e.getPoint();
int xDelta = p.x - clickPoint.x;
int width = getWidth() - xDelta;
int x = getX() + xDelta;
setSize(width, getHeight());
setLocation(x, getY());
revalidate();
}
break;
case ResizeEast: {
Point p = e.getPoint();
int xDelta = p.x - clickPoint.x;
int width = getWidth() + xDelta;
setSize(width, getHeight());
revalidate();
clickPoint = p;
}
break;
case ResizeNorth: {
Point p = e.getPoint();
int yDelta = p.y - clickPoint.y;
int height = getHeight() - yDelta;
int y = getY() + yDelta;
setSize(getWidth(), height);
setLocation(getX(), y);
revalidate();
}
break;
case ResizeSouth: {
Point p = e.getPoint();
int yDelta = p.y - clickPoint.y;
int height = getHeight() + yDelta;
setSize(getWidth(), height);
revalidate();
clickPoint = p;
}
break;
}
}
#Override
public void mouseExited(MouseEvent e) {
}
}
}
public static BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
double scaleFactor = getScaleFactorToFit(img, size);
return getScaledInstance(img, scaleFactor);
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
BufferedImage imgBuffer = null;
imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
return imgBuffer;
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint) {
// System.out.println("Scale down...");
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
do {
if (w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
ScaleIMG.heightx=h;
ScaleIMG.widthx=w;
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
w = img.getWidth();
h = img.getHeight();
do {
if (w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
public static double getScaleFactorToFit(BufferedImage img, Dimension size) {
double dScale = 1;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
dScale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
}
return dScale;
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
if (iMasterSize > iTargetSize) {
dScale = (double) iTargetSize / (double) iMasterSize;
} else {
dScale = (double) iTargetSize / (double) iMasterSize;
}
return dScale;
}
}
RotateIMGn.java
package logic;
import logic.ScaleIMG.ImagePane;
public class RotateIMGn extends JPanel
{
private static final long serialVersionUID = 1L;
public ImageIcon image;
JLabel label = new JLabel(image);
JPanel rotationPanel;
final int WIDTH = 350;
final int HEIGHT = 500;
double degrees=0;
ImagePane iobj = new ImagePane();
public RotateIMGn(String passpath)
{
image =new ImageIcon(passpath);
setPreferredSize(new Dimension(446, 500));
setFocusable(true);
//addKeyListener(new KeyboardListener());
rotationPanel = new JPanel();
rotationPanel = new turningCanvas();
rotationPanel.setPreferredSize(new Dimension(image.getIconWidth(),image.getIconHeight()));
add(rotationPanel);
JMenuBar menuBar = new JMenuBar();
add(menuBar);
JMenu mnFile = new JMenu("Rotate");
menuBar.add(mnFile);
ImageIcon icon90 = createImageIcon("/images/images_Right.png");
JMenuItem mntmTR90 = new JMenuItem("Rotate 90+",icon90);
mntmTR90.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0)
{
try
{
degrees+=90.0;
repaint();
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
mnFile.add(mntmTR90);
ImageIcon icon180 = createImageIcon("/images/images_Vertical.png");
JMenuItem mntmRT180 = new JMenuItem("Rotate 180+",icon180);
mntmRT180.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
try
{
degrees+=180.0;
repaint();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
});
mnFile.add(mntmRT180);
JSeparator separator = new JSeparator();
mnFile.add(separator);
ImageIcon micon90 = createImageIcon("/images/images_Left.png");
JMenuItem mntmTRM90 = new JMenuItem("Rotate 90-",micon90);
mntmTRM90.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
try
{
degrees-=90.0;
repaint();
}
catch(Exception exc)
{
exc.printStackTrace();
}
}
});
mnFile.add(mntmTRM90);
ImageIcon micon180 = createImageIcon("/images/images_Horizontal.png");
JMenuItem mntmRTM180 = new JMenuItem("Rotate 180-",micon180);
mntmRTM180.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
try
{
degrees-=180.0;
repaint();
}
catch(Exception exz)
{
exz.printStackTrace();
}
}
});
mnFile.add(mntmRTM180);
rotationPanel.setBounds(WIDTH/2, HEIGHT/2, rotationPanel.getPreferredSize().width,
rotationPanel.getPreferredSize().height);
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
}
public class turningCanvas extends JPanel
{
private static final long serialVersionUID = 1L;
public void paintComponent (Graphics g)
{
try
{
System.out.println(iobj.pathpass1);
System.out.println(iobj.namepass1);
iobj.save(iobj.pathpass1, iobj.namepass1);
}
catch (IOException e)
{
e.printStackTrace();
}
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.rotate(Math.toRadians(degrees),image.getIconWidth()/2,image.getIconHeight()/2);
image.paintIcon(this, g2d, 0, 0);
}
}
public static void main(String[] args)
{
String mn = null;
RotateIMGn test = new RotateIMGn(mn);
JFrame frame = new JFrame();
frame.setTitle("Rotate Panel");
frame.setContentPane(test);
frame.pack();
frame.setVisible(true);
}
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = RotateIMGn.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
You can use the Screen Image class to create an image of any component.
I have a problem with my current animation that I'm running using Java Swing. It is a discrete event simulation and the text based simulation is working fine, I'm just having problems connecting the simulating to GUI output.
For this example I will have 10 cars to be simulated. The cars are represented by JPanels which I will elaborate on in a few moments.
So consider, the event process_car_arrival. Every time this event is scheduled for execution, I'm adding a Car object to an ArrayList called cars in my Model class. The Car class has the following relevant attributes:
Point currentPos; // The current position, initialized in another method when knowing route.
double speed; // giving the speed any value still causes the same problem but I have 5 atm.
RouteType route; // for this example I only consider one simple route
In addition it has the following method move() :
switch (this.route) {
case EAST:
this.currentPos.x -= speed;
return this.currentPos;
.
.
.
//only above is relevant in this example
This is all well. so in theory the car traverses along a straight road from east to west as I just invoke the move() method for each car I want to move.
Returning to the process_car_arrival event. After adding a Car object it invokes a method addCarToEast() in the View class. This adds a JPanel at the start of the road going from east to west.
Going to the View class now I have a ** separate** thread which does the following ( the run() method) :
#Override
public void run() {
while (true) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!cars.isEmpty()) {
cars.get(i).setLocation(
new Point(getModel.getCars().get(i).move()));
if (i == cars.size() - 1) {
i = 0;
} else {
i++;
}
}
}
}
The above does move the car from east to west smoothly at first. But after there is 3-4 cars moving it just ends up being EXTREMELY slow and when I have 10 cars moving it just ends up moving very little.
Just to clear up, at the moment in the Model class there's an ArrayList of Car objects, and in the View class there is also an ArrayList of JPanel objects representing the cars. I'm trying to match the Car objects to the JPanels, but I'm obviously doing a cra**y job.
I suspect that I'm doing something insanely inefficient but I don't know what. I thought initially maybe it's accessing the ArrayList so much which I guess would make it really slow.
Any pointers to what I can change to make it run smoothly?
Based on this previous answer, the example below simulates a fleet of three cabs moving randomly on a rectangular grid. A javax.swing.Timer drives the animation at 5 Hz. The model and view are tightly coupled in CabPanel, but the animation may provide some useful insights. In particular, you might increase the number of cabs or lower the timer delay.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* #see https://stackoverflow.com/a/14887457/230513
* #see https://stackoverflow.com/questions/5617027
*/
public class FleetPanel extends JPanel {
private static final Random random = new Random();
private final MapPanel map = new MapPanel();
private final JPanel control = new JPanel();
private final List<CabPanel> fleet = new ArrayList<CabPanel>();
private final Timer timer = new Timer(200, null);
public FleetPanel() {
super(new BorderLayout());
fleet.add(new CabPanel("Cab #1", Hue.Cyan));
fleet.add(new CabPanel("Cab #2", Hue.Magenta));
fleet.add(new CabPanel("Cab #3", Hue.Yellow));
control.setLayout(new GridLayout(0, 1));
for (CabPanel cp : fleet) {
control.add(cp);
timer.addActionListener(cp.listener);
}
this.add(map, BorderLayout.CENTER);
this.add(control, BorderLayout.SOUTH);
}
public void start() {
timer.start();
}
private class CabPanel extends JPanel {
private static final String format = "000000";
private final DecimalFormat df = new DecimalFormat(format);
private JLabel name = new JLabel("", JLabel.CENTER);
private Point point = new Point();
private JLabel position = new JLabel(toString(point), JLabel.CENTER);
private int blocks;
private JLabel odometer = new JLabel(df.format(0), JLabel.CENTER);
private final JComboBox colorBox = new JComboBox();
private final JButton reset = new JButton("Reset");
private final ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int ds = random.nextInt(3) - 1;
if (random.nextBoolean()) {
point.x += ds;
} else {
point.y += ds;
}
blocks += Math.abs(ds);
update();
}
};
public CabPanel(String s, Hue hue) {
super(new GridLayout(1, 0));
name.setText(s);
this.setBackground(hue.getColor());
this.add(map, BorderLayout.CENTER);
for (Hue h : Hue.values()) {
colorBox.addItem(h);
}
colorBox.setSelectedIndex(hue.ordinal());
colorBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Hue h = (Hue) colorBox.getSelectedItem();
CabPanel.this.setBackground(h.getColor());
update();
}
});
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
point.setLocation(0, 0);
blocks = 0;
update();
}
});
this.add(name);
this.add(odometer);
this.add(position);
this.add(colorBox);
this.add(reset);
}
private void update() {
position.setText(CabPanel.this.toString(point));
odometer.setText(df.format(blocks));
map.repaint();
}
private String toString(Point p) {
StringBuilder sb = new StringBuilder();
sb.append(Math.abs(p.x));
sb.append(p.x < 0 ? " W" : " E");
sb.append(", ");
sb.append(Math.abs(p.y));
sb.append(p.y < 0 ? " N" : " S");
return sb.toString();
}
}
private class MapPanel extends JPanel {
private static final int SIZE = 16;
public MapPanel() {
this.setPreferredSize(new Dimension(32 * SIZE, 32 * SIZE));
this.setBackground(Color.lightGray);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = this.getWidth();
int h = this.getHeight();
g2d.setColor(Color.gray);
for (int col = SIZE; col <= w; col += SIZE) {
g2d.drawLine(col, 0, col, h);
}
for (int row = SIZE; row <= h; row += SIZE) {
g2d.drawLine(0, row, w, row);
}
for (CabPanel cp : fleet) {
Point p = cp.point;
int x = SIZE * (p.x + w / 2 / SIZE) - SIZE / 2;
int y = SIZE * (p.y + h / 2 / SIZE) - SIZE / 2;
g2d.setColor(cp.getBackground());
g2d.fillOval(x, y, SIZE, SIZE);
}
}
}
public enum Hue {
Cyan(Color.cyan), Magenta(Color.magenta), Yellow(Color.yellow),
Red(Color.red), Green(Color.green), Blue(Color.blue),
Orange(Color.orange), Pink(Color.pink);
private final Color color;
private Hue(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
private static void display() {
JFrame f = new JFrame("Dispatch");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FleetPanel fp = new FleetPanel();
f.add(fp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
fp.start();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
}
I couldn't resist...
I got 500 cars running on the screen with little slow down (it wasn't the fastest...about 200-300 was pretty good...
This uses panels to represent each vehicle. If you want to get better performance, your probably need to look at using a backing buffer of some kind.
public class TestAnimation10 {
public static void main(String[] args) {
new TestAnimation10();
}
public TestAnimation10() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final TrackPane trackPane = new TrackPane();
JSlider slider = new JSlider(1, 500);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
trackPane.setCongestion(((JSlider)e.getSource()).getValue());
}
});
slider.setValue(5);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(trackPane);
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TrackPane extends JPanel {
private List<Car> cars;
private int maxCars = 1;
private List<Point2D[]> points;
private Ellipse2D areaOfEffect;
public TrackPane() {
points = new ArrayList<>(25);
cars = new ArrayList<>(25);
setLayout(null);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle bounds = areaOfEffect.getBounds();
List<Car> tmp = new ArrayList<>(cars);
for (Car car : tmp) {
car.move();
if (!bounds.intersects(car.getBounds())) {
remove(car);
cars.remove(car);
}
}
updatePool();
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
updateAreaOfEffect();
}
protected void updateAreaOfEffect() {
double radius = Math.max(getWidth(), getHeight()) * 1.5d;
double x = (getWidth() - radius) / 2d;
double y = (getHeight() - radius) / 2d;
areaOfEffect = new Ellipse2D.Double(x, y, radius, radius);
}
#Override
public void invalidate() {
super.invalidate();
updateAreaOfEffect();
}
protected void updatePool() {
while (cars.size() < maxCars) {
// if (cars.size() < maxCars) {
Car car = new Car();
double direction = car.getDirection();
double startAngle = direction - 180;
double radius = areaOfEffect.getWidth();
Point2D startPoint = getPointAt(radius, startAngle);
int cx = getWidth() / 2;
int cy = getHeight() / 2;
double x = cx + (startPoint.getX() - car.getWidth() / 2);
double y = cy + (startPoint.getY() - car.getHeight() / 2);
car.setLocation((int)x, (int)y);
Point2D targetPoint = getPointAt(radius, direction);
points.add(new Point2D[]{startPoint, targetPoint});
add(car);
cars.add(car);
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
Font font = g.getFont();
font = font.deriveFont(Font.BOLD, 48f);
FontMetrics fm = g.getFontMetrics(font);
g.setFont(font);
g.setColor(Color.RED);
String text = Integer.toString(maxCars);
int x = getWidth() - fm.stringWidth(text);
int y = getHeight() - fm.getHeight() + fm.getAscent();
g.drawString(text, x, y);
text = Integer.toString(getComponentCount());
x = getWidth() - fm.stringWidth(text);
y -= fm.getHeight();
g.drawString(text, x, y);
text = Integer.toString(cars.size());
x = getWidth() - fm.stringWidth(text);
y -= fm.getHeight();
g.drawString(text, x, y);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void setCongestion(int value) {
maxCars = value;
}
}
protected static Point2D getPointAt(double radius, double angle) {
double x = Math.round(radius / 2d);
double y = Math.round(radius / 2d);
double rads = Math.toRadians(-angle);
double fullLength = Math.round((radius / 2d));
double xPosy = (Math.cos(rads) * fullLength);
double yPosy = (Math.sin(rads) * fullLength);
return new Point2D.Double(xPosy, yPosy);
}
public class Car extends JPanel {
private double direction;
private double speed;
private BufferedImage background;
public Car() {
setOpaque(false);
direction = Math.random() * 360;
speed = 5 + (Math.random() * 10);
int image = 1 + (int) Math.round(Math.random() * 5);
try {
String name = "/Car0" + image + ".png";
background = ImageIO.read(getClass().getResource(name));
} catch (IOException ex) {
ex.printStackTrace();
}
setSize(getPreferredSize());
// setBorder(new LineBorder(Color.RED));
}
public void setDirection(double direction) {
this.direction = direction;
revalidate();
repaint();
}
public double getDirection() {
return direction;
}
public void move() {
Point at = getLocation();
at.x += (int)(speed * Math.cos(Math.toRadians(-direction)));
at.y += (int)(speed * Math.sin(Math.toRadians(-direction)));
setLocation(at);
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (background != null) {
double radian = Math.toRadians(direction);
double sin = Math.abs(Math.sin(radian)), cos = Math.abs(Math.cos(radian));
int w = background.getWidth(), h = background.getHeight();
int neww = (int) Math.floor(w * cos + h * sin);
int newh = (int) Math.floor(h * cos + w * sin);
size = new Dimension(neww, newh);
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.rotate(Math.toRadians(-(direction + 180)), getWidth() / 2, getHeight() / 2);
g2d.drawImage(background, x, y, this);
g2d.dispose();
// Debug graphics...
// int cx = getWidth() / 2;
// int cy = getHeight() / 2;
//
// g2d = (Graphics2D) g.create();
// g2d.setColor(Color.BLUE);
// double radius = Math.min(getWidth(), getHeight());
// Point2D pointAt = getPointAt(radius, direction);
// g2d.draw(new Ellipse2D.Double(cx - (radius / 2d), cy - (radius / 2d), radius, radius));
//
// double xo = cx;
// double yo = cy;
// double xPos = cx + pointAt.getX();
// double yPos = cy + pointAt.getY();
//
// g2d.draw(new Line2D.Double(xo, yo, xPos, yPos));
// g2d.draw(new Ellipse2D.Double(xPos - 2, yPos - 2, 4, 4));
// g2d.dispose();
}
}
}
Updated with optimized version
I did a little bit of code optimisation with the creation of the car objects (there's still room for improvement) and ehanched the graphics ouput (made it look nicer).
Basically, now, when a car leaves the screen, it's placed in a pool. When another car is required, if possible, it's pulled from the pool, otherwise a new car is made. This has reduced the overhead of creating and destorying so many (relativly) short lived objects, which makes the memory usage a little more stable.
On my 2560x1600 resolution screen (running maximised), I was able to get 4500 cars running simultaneously. Once the object creation was reduced, it ran relatively smoothly (it's never going to run as well as 10, but it didn't suffer from a significant reduction in speed).
public class TestAnimation10 {
public static void main(String[] args) {
new TestAnimation10();
}
public TestAnimation10() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final TrackPane trackPane = new TrackPane();
JSlider slider = new JSlider(1, 5000);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
trackPane.setCongestion(((JSlider) e.getSource()).getValue());
}
});
slider.setValue(5);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(trackPane);
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TrackPane extends JPanel {
private List<Car> activeCarList;
private List<Car> carPool;
private int maxCars = 1;
private List<Point2D[]> points;
private Ellipse2D areaOfEffect;
public TrackPane() {
points = new ArrayList<>(25);
activeCarList = new ArrayList<>(25);
carPool = new ArrayList<>(25);
setLayout(null);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle bounds = areaOfEffect.getBounds();
List<Car> tmp = new ArrayList<>(activeCarList);
for (Car car : tmp) {
car.move();
if (!bounds.intersects(car.getBounds())) {
remove(car);
activeCarList.remove(car);
carPool.add(car);
}
}
updatePool();
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
updateAreaOfEffect();
}
protected void updateAreaOfEffect() {
double radius = Math.max(getWidth(), getHeight()) * 1.5d;
double x = (getWidth() - radius) / 2d;
double y = (getHeight() - radius) / 2d;
areaOfEffect = new Ellipse2D.Double(x, y, radius, radius);
}
#Override
public void invalidate() {
// super.invalidate();
updateAreaOfEffect();
}
protected void updatePool() {
if (activeCarList.size() < maxCars) {
int count = Math.min(maxCars - activeCarList.size(), 10);
for (int index = 0; index < count; index++) {
Car car = null;
if (carPool.isEmpty()) {
car = new Car();
} else {
car = carPool.remove(0);
}
double direction = car.getDirection();
double startAngle = direction - 180;
double radius = areaOfEffect.getWidth();
Point2D startPoint = getPointAt(radius, startAngle);
int cx = getWidth() / 2;
int cy = getHeight() / 2;
double x = cx + (startPoint.getX() - car.getWidth() / 2);
double y = cy + (startPoint.getY() - car.getHeight() / 2);
car.setLocation((int) x, (int) y);
Point2D targetPoint = getPointAt(radius, direction);
points.add(new Point2D[]{startPoint, targetPoint});
add(car);
activeCarList.add(car);
}
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
Font font = g.getFont();
font = font.deriveFont(Font.BOLD, 48f);
FontMetrics fm = g.getFontMetrics(font);
g.setFont(font);
g.setColor(Color.RED);
String text = Integer.toString(maxCars);
int x = getWidth() - fm.stringWidth(text);
int y = getHeight() - fm.getHeight() + fm.getAscent();
g.drawString(text, x, y);
text = Integer.toString(getComponentCount());
x = getWidth() - fm.stringWidth(text);
y -= fm.getHeight();
g.drawString(text, x, y);
text = Integer.toString(activeCarList.size());
x = getWidth() - fm.stringWidth(text);
y -= fm.getHeight();
g.drawString(text, x, y);
text = Integer.toString(carPool.size());
x = getWidth() - fm.stringWidth(text);
y -= fm.getHeight();
g.drawString(text, x, y);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void setCongestion(int value) {
maxCars = value;
}
#Override
public void validate() {
}
#Override
public void revalidate() {
}
// #Override
// public void repaint(long tm, int x, int y, int width, int height) {
// }
//
// #Override
// public void repaint(Rectangle r) {
// }
// public void repaint() {
// }
#Override
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
System.out.println(propertyName);
// // Strings get interned...
// if (propertyName == "text"
// || propertyName == "labelFor"
// || propertyName == "displayedMnemonic"
// || ((propertyName == "font" || propertyName == "foreground")
// && oldValue != newValue
// && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
//
// super.firePropertyChange(propertyName, oldValue, newValue);
// }
}
#Override
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
}
}
protected static Point2D getPointAt(double radius, double angle) {
double x = Math.round(radius / 2d);
double y = Math.round(radius / 2d);
double rads = Math.toRadians(-angle);
double fullLength = Math.round((radius / 2d));
double xPosy = (Math.cos(rads) * fullLength);
double yPosy = (Math.sin(rads) * fullLength);
return new Point2D.Double(xPosy, yPosy);
}
public class Car extends JPanel {
private double direction;
private double speed;
private BufferedImage background;
public Car() {
setOpaque(false);
direction = Math.random() * 360;
speed = 5 + (Math.random() * 10);
int image = 1 + (int) Math.round(Math.random() * 5);
try {
String name = "/Car0" + image + ".png";
background = ImageIO.read(getClass().getResource(name));
} catch (IOException ex) {
ex.printStackTrace();
}
setSize(getPreferredSize());
// setBorder(new LineBorder(Color.RED));
}
public void setDirection(double direction) {
this.direction = direction;
revalidate();
repaint();
}
public double getDirection() {
return direction;
}
public void move() {
Point at = getLocation();
at.x += (int) (speed * Math.cos(Math.toRadians(-direction)));
at.y += (int) (speed * Math.sin(Math.toRadians(-direction)));
setLocation(at);
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (background != null) {
double radian = Math.toRadians(direction);
double sin = Math.abs(Math.sin(radian)), cos = Math.abs(Math.cos(radian));
int w = background.getWidth(), h = background.getHeight();
int neww = (int) Math.floor(w * cos + h * sin);
int newh = (int) Math.floor(h * cos + w * sin);
size = new Dimension(neww, newh);
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g2d.rotate(Math.toRadians(-(direction + 180)), getWidth() / 2, getHeight() / 2);
g2d.drawImage(background, x, y, this);
g2d.dispose();
// Debug graphics...
// int cx = getWidth() / 2;
// int cy = getHeight() / 2;
//
// g2d = (Graphics2D) g.create();
// g2d.setColor(Color.BLUE);
// double radius = Math.min(getWidth(), getHeight());
// Point2D pointAt = getPointAt(radius, direction);
// g2d.draw(new Ellipse2D.Double(cx - (radius / 2d), cy - (radius / 2d), radius, radius));
//
// double xo = cx;
// double yo = cy;
// double xPos = cx + pointAt.getX();
// double yPos = cy + pointAt.getY();
//
// g2d.draw(new Line2D.Double(xo, yo, xPos, yPos));
// g2d.draw(new Ellipse2D.Double(xPos - 2, yPos - 2, 4, 4));
// g2d.dispose();
}
#Override
public void invalidate() {
}
#Override
public void validate() {
}
#Override
public void revalidate() {
}
#Override
public void repaint(long tm, int x, int y, int width, int height) {
}
#Override
public void repaint(Rectangle r) {
}
#Override
public void repaint() {
}
#Override
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
// System.out.println(propertyName);
// // Strings get interned...
// if (propertyName == "text"
// || propertyName == "labelFor"
// || propertyName == "displayedMnemonic"
// || ((propertyName == "font" || propertyName == "foreground")
// && oldValue != newValue
// && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
//
// super.firePropertyChange(propertyName, oldValue, newValue);
// }
}
#Override
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
}
}
}
ps - I should add 1- My 10 month old loved it 2- It reminded me of the run to work :P