I have a problem with my program. Every time when I change my screen resolution, my image starts to move out of position. Any suggestions on how to make my image stay in the same location even though I change to any other resolution?
p2 = new JPanel();
p2.setLayout(new FlowLayout());
ImageIcon img2 = new ImageIcon("C:\\Drum\\Invisible4.png");
jbtn2 = new JLabel(img2);
p2.add(jbtn2);
add(jbtn2);
jbtn2.setSize(jbtn2.getPreferredSize());
jbtn2.setLocation(140, 380);
I prefer to always try and work within boundaries of the framework where I can, it makes life generally easier in the long run.
Swing has begin designed to work with LayoutManagers, this means that the way that Swing updates it's components and communicates these changes is based on the use of the LayoutManagers (more or less).
The following example uses pieces from Java: maintaining aspect ratio of JPanel background image to scale the images and a PropertionalLayoutManager which is designed to try and scale not only the size, but also the position of the components based on the size of the parent container.
The PropertionalLayoutManager demonstrated here will try and layout the components around the center of the parent container. You can change this, but it looks weird - IMHO
import java.awt.BorderLayout;
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.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.WeakHashMap;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Drums {
protected static BufferedImage SYMBOL;
protected static BufferedImage DRUM;
public static void main(String[] args) {
new Drums();
}
public Drums() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new PropertionalLayoutManager(400, 400));
add(new Symbol(), new PropertionalConstraint(0f, 0));
add(new Symbol(), new PropertionalConstraint(0.67f, 0));
add(new Symbol(), new PropertionalConstraint(0f, 0.4675f));
add(new Symbol(), new PropertionalConstraint(0.67f, 0.4675f));
add(new Drum(), new PropertionalConstraint(0.205f, 0.1f));
add(new Drum(), new PropertionalConstraint(0.5f, 0.1f));
add(new Drum(), new PropertionalConstraint(0f, 0.33f));
add(new Drum(), new PropertionalConstraint(0.705f, 0.33f));
}
}
public class PropertionalConstraint {
private float x;
private float y;
public PropertionalConstraint(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
public class PropertionalLayoutManager implements LayoutManager2 {
private Map<Component, PropertionalConstraint> constraints;
private Dimension defaultSize;
public PropertionalLayoutManager(int defaultWidth, int defaultHeight) {
constraints = new WeakHashMap<>(25);
defaultSize = new Dimension(defaultWidth, defaultHeight);
}
#Override
public void addLayoutComponent(Component comp, Object constraint) {
if (constraint instanceof PropertionalConstraint) {
constraints.put(comp, ((PropertionalConstraint) 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) {
}
#Override
public void removeLayoutComponent(Component comp) {
constraints.remove(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return defaultSize;
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = parent.getHeight();
double dScaleWidth = getScaleFactor(defaultSize.width, width);
double dScaleHeight = getScaleFactor(defaultSize.height, height);
double scaleSize = Math.min(dScaleHeight, dScaleWidth);
int minRange = Math.min(width, height);
if (width > 0 && height > 0) {
int maxY = 0;
int maxX = 0;
for (Component comp : parent.getComponents()) {
PropertionalConstraint p = constraints.get(comp);
if (p != null) {
Dimension prefSize = comp.getPreferredSize();
prefSize.width *= scaleSize;
prefSize.height *= scaleSize;
int x = Math.round(minRange * p.getX());
int y = Math.round(minRange * p.getY());
comp.setBounds(x, y, prefSize.width, prefSize.height);
maxX = Math.max(maxX, x + prefSize.width);
maxY = Math.max(maxY, y + prefSize.height);
} else {
comp.setBounds(0, 0, 0, 0);
}
}
for (Component comp : parent.getComponents()) {
System.out.println("maxX = " + maxX);
System.out.println("maxY = " + maxY);
if (comp.getWidth() > 0 && comp.getHeight() > 0) {
int x = ((width - maxX) / 2) + comp.getX();
int y = ((height - maxY) / 2) + comp.getY();
comp.setLocation(x, y);
}
}
} else {
for (Component comp : parent.getComponents()) {
comp.setBounds(0, 0, 0, 0);
}
}
}
}
public abstract class AbstractKitPiecePane extends JPanel {
private BufferedImage scaled;
public AbstractKitPiecePane() {
setOpaque(false);
}
public abstract BufferedImage getKitImage();
#Override
public Dimension getPreferredSize() {
return new Dimension(getKitImage().getWidth(), getKitImage().getHeight());
}
#Override
public void invalidate() {
super.invalidate();
if (getWidth() > 0 && getHeight() > 0) {
scaled = getScaledInstanceToFit(getKitImage(), getSize());
} else {
scaled = null;
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
int x = (getWidth() - scaled.getWidth()) / 2;
int y = (getHeight() - scaled.getHeight()) / 2;
g.drawImage(scaled, x, y, this);
}
}
}
public class Drum extends AbstractKitPiecePane {
#Override
public BufferedImage getKitImage() {
return DRUM;
}
}
public class Symbol extends AbstractKitPiecePane {
#Override
public BufferedImage getKitImage() {
return SYMBOL;
}
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
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, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
}
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;
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);
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 BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
double scaleFactor = getScaleFactorToFit(img, size);
return getScaledInstance(img, scaleFactor);
}
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;
}
static {
try {
SYMBOL = ImageIO.read(new File("Symbol.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
try {
DRUM = ImageIO.read(new File("Drum.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
And the images used within the program, for your enjoyment. They live in the same directory the program is run from
create a percentage/ratio of the "normal" screen size to what it currently is and multiply that by the pos. Example if the screen size you are working with was 400x600
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
double widthRat = width/600
double heightRat = height/400
then
jbtn2.setLocation(140*widthRat, 380*heightRat);
that way say the screen size was doubled to 1200x800 widthRat would = 2 and double the position. This is kind of a sloppy example but gives the idea
I prefer to use Absolute layout. And here are the codes which should work for you.
Toolkit toolkit=Toolkit.getDefaultToolkit();
JPanel1.setSize(toolkit.getScreenSize().width, toolkit.getScreenSize().height);
int w=toolkit.getScreenSize().width;
int h=toolkit.getScreenSize().height;
JPanel1.setBounds(0, 0, w, h);
This code will fetch the current resolution of your computer...
Related
I want to adjust the size of logo2.png so that it completely fits to the jFrame. Can anyone help me out?
jLabel2 = new javax.swing.JLabel();
jLabel2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Banking/logo2.png"))); // NOI18N
JDesktopPane.add(jLabel2);
jLabel2.setBounds(0, 0, 500, 290);
JLabel doesn't rescale it's content (ie the image), for that, you're going to have to get you hands a little dirty...
There are a number of ways to achieve this. Personally, I'd start with a custom component, which extends from something like JPanel which takes a base image and is capable of scaling and painting it.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details about performing custom painting.
Scaling an image is not as straightforward as it might seem, while Java does provide some APIs to scale images, generally, they don't generate fantastic results. Take a look at Quality of Image after resize very low -- Java and The Perils of Image.getScaledInstance() for more details.
I would normally recommend taking a look at the imgscalr library, as it's results are generally quite good (better then what the base Java API provides or I've seen through most other methods), but for this example, I've included an example of a divide an conqure approach.
This example provides a "scale to fill" implementation, this ensures that the resulting image ALWAYS fills the available space while maintaining it's aspect ratio, see Java: maintaining aspect ratio of JPanel background image for more discussions on the subject
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScaledBackground {
public static void main(String[] args) {
new ScaledBackground();
}
public ScaledBackground() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
try {
BufferedImage img = ImageIO.read(...);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ImagePane(img));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public class ImagePane extends JPanel {
private BufferedImage original;
private BufferedImage scaled;
public ImagePane(BufferedImage img) {
original = img;
scaled = original;
}
#Override
public Dimension getPreferredSize() {
return original == null ? new Dimension(200, 200) : new Dimension(original.getWidth(), original.getHeight());
}
#Override
public void invalidate() {
super.invalidate();
generateScaledInstance();
}
protected void generateScaledInstance() {
if (original != null) {
scaled = getScaledInstanceToFill(original, getSize());
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (scaled != null) {
int x = (getWidth() - scaled.getWidth()) / 2;
int y = (getHeight() - scaled.getHeight()) / 2;
g2d.drawImage(scaled, x, y, this);
}
g2d.dispose();
}
public BufferedImage getScaledInstanceToFill(BufferedImage img, Dimension size) {
float scaleFactor = getScaleFactorToFill(img, size);
return getScaledInstance(img, scaleFactor);
}
public float getScaleFactorToFill(BufferedImage img, Dimension size) {
float scale = 1f;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
scale = getScaleFactorToFill(new Dimension(imageWidth, imageHeight), size);
}
return scale;
}
public float getScaleFactorToFill(Dimension original, Dimension toFit) {
float scale = 1f;
if (original != null && toFit != null) {
float dScaleWidth = getScaleFactor(original.width, toFit.width);
float dScaleHeight = getScaleFactor(original.height, toFit.height);
scale = Math.max(dScaleHeight, dScaleWidth);
}
return scale;
}
public float getScaleFactor(int iMasterSize, int iTargetSize) {
float scale = 1;
if (iMasterSize > iTargetSize) {
scale = (float) iTargetSize / (float) iMasterSize;
} else {
scale = (float) iTargetSize / (float) iMasterSize;
}
return scale;
}
public BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
BufferedImage imgBuffer = null;
imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
return imgBuffer;
}
protected BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean higherQuality) {
BufferedImage scaled = img;
if (dScaleFactor != 1.0) {
if (dScaleFactor > 1.0) {
scaled = getScaledUpInstance(img, dScaleFactor, hint, higherQuality);
} else if (dScaleFactor > 0.0) {
scaled = getScaledDownInstance(img, dScaleFactor, hint, higherQuality);
}
}
return scaled;
}
protected BufferedImage getScaledDownInstance(BufferedImage img, double dScaleFactor, Object hint, boolean higherQuality) {
int targetWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int targetHeight = (int) Math.round(img.getHeight() * dScaleFactor);
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;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && 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);
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 BufferedImage getScaledUpInstance(BufferedImage img,
double dScaleFactor,
Object hint,
boolean higherQuality) {
int targetWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int targetHeight = (int) Math.round(img.getHeight() * dScaleFactor);
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && 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;
}
}
}
This example will grow and shrink as the image as the amount of available space for the panel changes
You can use the Stretch Icon on your JLabel.
Or you could use the Background Panel to draw the image.
In both cases the Image will shrink or grow as the frame is resized.
First get the Image, then use this method:
yourImage.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT);
You can get the width and height from the JFrame. Then you can convert the Image to ImageIcon and add it.
I'm making a fun little test screen recording program in java, and I want it to have a preview of your screen before you start recording.. but its a very slow and poor method of which I am using, involving capturing an image, saving it, then reading it in through a bufferedimage and drawing that image using Graphics. Its very slow and not useful as a "preview" is there a way to speed up and have a more efficient "previewing system".
Here is what I have so far:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MainFrame implements ActionListener, Runnable {
//add frame components
public static JFrame frame = new JFrame("Screen Caper - v1.0.1");
JButton start = new JButton("record");
JButton close = new JButton("Exit");
JPanel preview = new JPanel();
public static boolean running = false;
public static boolean recording = false;
public static boolean paused = false;
public static String curDir = System.getProperty("user.dir");
//get the screen width
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
Container a = new Container();
Container b = new Container();
public MainFrame() {
frame.setSize((int)(width) - 80, (int)(height) - 80);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setup the buttons and JPanel
a.setLayout(new GridLayout(1, 2));
a.add(start);
start.addActionListener(this);
a.add(close);
close.addActionListener(this);
frame.add(a, BorderLayout.NORTH);
b.setLayout(new GridLayout(1, 2));
b.add(preview);
frame.add(b, BorderLayout.CENTER);
//add anything else
running = true;
//set frame to visible
frame.setVisible(true);
run();
}
public static void main(String[] args) {
new MainFrame();
}
public void run() {
Graphics g = frame.getGraphics();
while (running) {
//draw the preview of the computer screen on the JPanel if its not recording already
if (!recording && !paused) {
drawPreview(g);
}
}
}
public void drawPreview(Graphics g) {
BufferedImage image;
try {
image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "png", new File("test.png"));
} catch (Exception ex) {
ex.printStackTrace();
}
BufferedImage prevIm;
try {
prevIm = ImageIO.read(new File("test.png"));
g.setColor(new Color(0, 0, 0));
g.fillRect(preview.getX() + 3, preview.getY() + 51, preview.getWidth(), preview.getHeight() + 1);
g.drawImage(prevIm, preview.getX() + 3, preview.getY() + 51, preview.getX() + preview.getWidth(), preview.getY() + preview.getHeight(), null);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void record(Graphics g) {
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(start)) {
if (!recording) {
//if the program isn't recording, then start recording
Graphics g = frame.getGraphics();
record(g);
start.setText("Finish");
recording = true;
System.out.println("recording...");
} else {
//else stop recording
start.setText("record");
recording = false;
System.out.println("done");
}
}
if (event.getSource().equals(close)) {
paused = true;
int ans = JOptionPane.showConfirmDialog(null, "Woah there! You're about to quit the application\nAre you sure you want to procced?", "Caution!", JOptionPane.YES_NO_OPTION);
if (ans == JOptionPane.YES_OPTION) {
System.exit(0);
} else if (ans == JOptionPane.NO_OPTION) {
paused = false;
}
}
}
}
any help is appreciated!
Don't use getGraphics, this is not how custom painting is done.
Your run method may simply be running to fast, consider using a javax.swing.Timer instead
Toolkit.getDefaultToolkit().getScreenSize() only returns the "default" screen and does not take into consideration split screens
Capturing the screen is a time consuming process and there's not much you can do about reducing it (as it's outside of your control). You "could" setup a series of Threads whose job it was to capture a given section of the desktop. You could also achieve this using SwingWorkers which would make it easier to sync the updates back to the UI...
Take a look at:
Performing Custom Painting
Concurrency in Swing
How to Use Swing Timers
Updated with example
This is a proof of concept only! You should understand what it's trying to do and borrow ideas from it...
You can see the preview window change inside the preview window...kinda freaky...
It tested this on a virtual desktop of 4480x1600.
Basically, it divides the desktop up into a 4x4 grid and starts a Thread for each section. Each thread is responsible for capturing it's own section of the screen.
It also scales that resulting image down and feeds it back to the UI.
I had started with SwingWorkers, but it seems to be hard to be limited to 10 threads. You could reduce the grid size and use SwingWorkers, they tend to be simpler to use and manage then raw Threads.
Each section is given an id, which allows me keep track of what's changed. Technically, you could just add elements to a List, but how do you determine what's new and what's old?
import java.awt.AWTException;
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.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PreviewDesktop {
public static void main(String[] args) {
new PreviewDesktop();
}
public PreviewDesktop() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Puzzler {
private Rectangle virtualBounds;
private double scale;
private Map<Integer, PuzzlePiece> pieces;
public TestPane() {
virtualBounds = getVirtualBounds();
int columns = 4;
int rows = 4;
pieces = new HashMap<>(columns * rows);
int columnWidth = Math.round(virtualBounds.width / (float) columns);
int rowHeight = Math.round(virtualBounds.height / (float) rows);
int id = 0;
for (int row = 0; row < rows; row++) {
int y = virtualBounds.y + (row * rowHeight);
for (int column = 0; column < columns; column++) {
int x = virtualBounds.x + (column * columnWidth);
Rectangle bounds = new Rectangle(x, y, columnWidth, rowHeight);
GrabberWorker worker = new GrabberWorker(id, this, bounds);
System.out.println(id);
id++;
startThread(worker);
}
}
}
#Override
public double getScale() {
return scale;
}
#Override
public void invalidate() {
super.invalidate();
scale = getScaleFactorToFit(virtualBounds.getSize(), getSize());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Integer id : pieces.keySet()) {
PuzzlePiece piece = pieces.get(id);
Rectangle bounds = piece.getBounds();
BufferedImage img = piece.getImage();
g2d.drawImage(img, bounds.x, bounds.y, this);
// If you want to see each sections bounds, uncomment below...
//g2d.draw(bounds);
}
g2d.dispose();
}
#Override
public void setPiece(int id, PuzzlePiece piece) {
pieces.put(id, piece);
repaint();
}
protected void startThread(GrabberWorker worker) {
Thread thread = new Thread(worker);
thread.setDaemon(true);
thread.start();
}
}
public class PuzzlePiece {
private final Rectangle bounds;
private final BufferedImage img;
public PuzzlePiece(Rectangle bounds, BufferedImage img) {
this.bounds = bounds;
this.img = img;
}
public Rectangle getBounds() {
return bounds;
}
public BufferedImage getImage() {
return img;
}
}
public interface Puzzler {
public void setPiece(int id, PuzzlePiece piece);
public double getScale();
}
public class GrabberWorker implements Runnable {
private Rectangle bounds;
private Puzzler puzzler;
private int id;
private volatile PuzzlePiece parked;
private ReentrantLock lckParked;
public GrabberWorker(int id, Puzzler puzzler, Rectangle bounds) {
this.id = id;
this.bounds = bounds;
this.puzzler = puzzler;
lckParked = new ReentrantLock();
}
protected void process(PuzzlePiece piece) {
// puzzler.setPiece(bounds, chunks.get(chunks.size() - 1));
puzzler.setPiece(id, piece);
}
protected void publish(PuzzlePiece piece) {
lckParked.lock();
try {
parked = piece;
} finally {
lckParked.unlock();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
lckParked.lock();
try {
process(parked);
} finally {
lckParked.unlock();
}
}
});
}
#Override
public void run() {
try {
Robot bot = new Robot();
while (true) {
BufferedImage img = bot.createScreenCapture(bounds);
double scale = puzzler.getScale();
Rectangle scaled = new Rectangle(bounds);
scaled.x *= scale;
scaled.y *= scale;
scaled.width *= scale;
scaled.height *= scale;
BufferedImage imgScaled = getScaledInstance(img, scale);
publish(new PuzzlePiece(scaled, imgScaled));
Thread.sleep(500);
}
} catch (AWTException | InterruptedException exp) {
exp.printStackTrace();
}
}
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(gd.getDefaultConfiguration().getBounds());
}
return bounds;
}
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 = (double) iTargetSize / (double) iMasterSize;
return dScale;
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
// System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
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;
if (higherQuality) {
// 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();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && 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);
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,
boolean higherQuality) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && 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;
}
}
Now, if you're feeling really adventurous, you could update this idea so that if the underlying image for a section didn't change and the scale didn't change, it didn't send that to the UI, which might help reduce some of the overhead ... and no, I don't have code to do that ;)
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 am trying to save new resized image but i exactly don't have any idea to get the new height & width or axis of image.
if anyone knows it then i will be so thankful.
my code to resize image or to scale image is as follows :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ImageViewer {
public static void main(String[] args) {
new ImageViewer();
}
public ImageViewer() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ViewPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ViewPane extends JPanel {
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(200, 200);
}
}
public static class ImagePane extends JPanel {
private BufferedImage bg;
private BufferedImage scaled;
public ImagePane() {
try {
bg = ImageIO.read(new File("src.jpg"));
scaled = getScaledInstanceToFit(bg, new Dimension(100, 100));
} catch (IOException ex) {
ex.printStackTrace();
}
setBackground(Color.BLACK);
MouseHandler handler = new MouseHandler();
addMouseListener(handler);
addMouseMotionListener(handler);
}
#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 Point offset;
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);
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;
}
}
i can also move my image easily and also make alteration in size, but now i want to save new image but i have to get first of all its new height and width , if i will get it then i will easily save it.
anyone can assist me ???
Depending on what it's you want to achieve, I would be tempted to add a method to the ImagePane called (something like) save...
public void save(String path, String name) throws IOException {
if (scaled != null) {
name += scaled.getWidth() + "x" + scaled.getHeight();
ImageIO.write(scaled, "png", new File(path + File.separator + name + ".png"));
} else {
throw new NullPointerException("Scaled instance is null");
}
}
Take a look at Writing/Saving an Image
You could also simply pass back a scaled instance based on the ImagePane's state...
public BufferedImage getScaledInstance() {
return getScaledInstanceToFit(bg, getSize());
}
I wouldn't return the scaled object because you don't want people messing with it if you can help it...
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