Heres my code, when you select and area you want to crop and then push enter, the cropped image isn't the same size/picture as the original selected area.
public class DragNDrop extends JFrame implements DropTargetListener {
private static final long serialVersionUID = 1872019741456690593L;
private Graphics g;
private BufferedImage image, origiImage;
private Rectangle area;
private Rectangle currentRect;
private Rectangle rectToDraw = null;
private Image buffer;
public static void main(String args[]) {
new DragNDrop();
}
public DragNDrop() {
super("Drop Test");
setSize(300, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setDropTarget(new DropTarget(getContentPane(), this));
setVisible(true);
CaptureListener listener = new CaptureListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
public void drop(DropTargetDropEvent dtde) {
try {
Transferable tr = dtde.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors();
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Object list = tr.getTransferData(flavors[0]);
list = list.toString().substring(1, list.toString().length()-1);
if (isValidImage(list)) {
Image droppedImage = Toolkit.getDefaultToolkit().getImage(list.toString());
image = toBufferedImage(droppedImage);
origiImage = toBufferedImage(droppedImage);
area = new Rectangle(image.getWidth(), image.getHeight());
if (droppedImage != null) {
setSize(image.getWidth(), image.getHeight());
dtde.dropComplete(true);
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 10) {
capture();
}
}
#Override
public void keyPressed(KeyEvent e) {
}
});
return;
}
}
dtde.rejectDrop();
} catch (Exception e) {
dtde.rejectDrop();
}
}
public void paint() {
if (area != null && image != null) {
g.clearRect(area.x, area.y, area.width, area.height);
g.drawImage(image, 0, 0, null);
}
if (currentRect != null) {
g.setColor(Color.RED);
g.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
g.setColor(new Color(255,255,255,150));
g.fillRect(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
}
}
#Override
public void paint(Graphics gr) {
if (buffer == null && area != null) {
this.buffer = createImage(area.width, area.height);
this.g = buffer.getGraphics();
}
paint();
if (buffer != null)
gr.drawImage(buffer, 0, 0, this);
}
public boolean isValidImage(Object list) {
System.out.println(list.toString());
for (String string : ImageIO.getReaderFormatNames())
if (list.toString().contains(string))
return true;
return false;
}
public BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
image = new ImageIcon(image).getImage();
boolean hasAlpha = hasAlpha(image);
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
int transparency = Transparency.OPAQUE;
if (hasAlpha == true) {
transparency = Transparency.BITMASK;
}
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
if (bimage == null) {
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha == true) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
Graphics g = bimage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
public static boolean hasAlpha(Image image) {
if (image instanceof BufferedImage) {
return ((BufferedImage) image).getColorModel().hasAlpha();
}
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}
return pg.getColorModel().hasAlpha();
}
private void updateRectangle(int compWidth, int compHeight) {
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
if ((x + width) > compWidth) {
width = compWidth - x;
}
if ((y + height) > compHeight) {
height = compHeight - y;
}
if (rectToDraw != null) {
rectToDraw.setBounds(x, y, width, height);
} else {
rectToDraw = new Rectangle(x, y, width, height);
}
}
public void capture() {
BufferedImage croppedImage = origiImage.getSubimage(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
setSize(rectToDraw.width, rectToDraw.height);
image = croppedImage;
}
public void upload(BufferedImage image) {
String IMGUR_POST_URI = "http://api.imgur.com/2/upload.xml";
String IMGUR_API_KEY = "b84e430b4a65d16a6955358141f21a61";
String readLine = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(image, "png", outputStream);
URL url = new URL(IMGUR_POST_URI);
String data = URLEncoder.encode("image", "UTF-8") + "=" + URLEncoder.encode(Base64.encodeBase64String(outputStream.toByteArray()).toString(), "UTF-8") + "&" + URLEncoder.encode("key", "UTF-8") + "=" + URLEncoder.encode(IMGUR_API_KEY, "UTF-8");
URLConnection urlConnection = url.openConnection();
urlConnection.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(urlConnection.getOutputStream());
wr.write(data);
wr.flush();
// Get the response
InputStream inputStream;
if (((HttpURLConnection) urlConnection).getResponseCode() == 400) {
inputStream = ((HttpURLConnection) urlConnection).getErrorStream();
} else {
inputStream = urlConnection.getInputStream();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
readLine = line;
}
wr.close();
reader.close();
} catch(Exception e){
e.printStackTrace();
}
//Prints the url link of the image uploaded
System.out.println(readLine.substring(readLine.indexOf("<original>") + 10, readLine.indexOf("</original>")));
}
public void dragEnter(DropTargetDragEvent dtde) {
}
public void dragExit(DropTargetEvent dte) {
}
public void dragOver(DropTargetDragEvent dtde) {
}
public void dropActionChanged(DropTargetDragEvent dtde) {
}
private class CaptureListener extends MouseInputAdapter {
public void mouseDragged(MouseEvent e) {
updateSize(e);
}
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateRectangle(getWidth(), getHeight());
repaint();
}
public void mouseReleased(MouseEvent e) {
updateSize(e);
}
public void updateSize(MouseEvent e) {
currentRect.setSize(e.getX() - currentRect.x, e.getY() - currentRect.y);
updateRectangle(getWidth(), getHeight());
repaint();
}
}
}
Can someone look through my code and find why it doesn't crop the exact same size?
There's nothing wrong with your cropping logic, the problem is with you paint logic.
Firstly, you should never (okay, rearly) override paint on a top level container (like a JFrame). There are lots of reasons and you just discovered one of them.
Secondly, you should ALWAYS call super.paintXxx(g), not doing so is a REALLY bad idea.
To be honest, I've got no idea of what half this code is trying to do (other then double buffering), which wouldn't be required if you used something like JPanel
public void paint() {
if (area != null && image != null) {
g.clearRect(area.x, area.y, area.width, area.height);
g.drawImage(image, 0, 0, null);
}
if (currentRect != null) {
g.setColor(Color.RED);
g.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
g.setColor(new Color(255,255,255,150));
g.fillRect(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
}
}
#Override
public void paint(Graphics gr) {
if (buffer == null && area != null) {
this.buffer = createImage(area.width, area.height);
this.g = buffer.getGraphics();
}
paint();
if (buffer != null)
gr.drawImage(buffer, 0, 0, this);
}
This doesn't allow for the fact that the frame is actually leaving space for the frames decorations (0x0 is actually the very top left hand corner of the window, not the inner drawing surface)...
So I've taken to you're code and rewritten it...
public class DragNDrop extends JFrame {
private static final long serialVersionUID = 1872019741456690593L;
public static void main(String args[]) {
new DragNDrop();
}
public DragNDrop() {
super("Drop Test");
setLayout(new BorderLayout());
add(new ImagePane());
setSize(300, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
protected class ImagePane extends JPanel implements DropTargetListener {
private BufferedImage image, origiImage;
private Rectangle currentRect;
private Rectangle rectToDraw = null;
public ImagePane() {
setDropTarget(new DropTarget(getContentPane(), this));
CaptureListener listener = new CaptureListener();
addMouseListener(listener);
addMouseMotionListener(listener);
setFocusable(true);
requestFocusInWindow();
// Keybindings are better the KeyListeners, as the generally work...
InputMap im = getInputMap(WHEN_FOCUSED);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Capture");
am.put("Capture", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
capture();
}
});
}
#Override
protected void paintComponent(Graphics g) {
// Look how simple this is...
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (image != null) {
g2d.drawImage(image, 0, 0, this);
}
if (currentRect != null) {
g2d.setColor(Color.RED);
g2d.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
g2d.setColor(new Color(255, 255, 255, 150));
g2d.fillRect(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
}
}
public void drop(DropTargetDropEvent dtde) {
try {
Transferable tr = dtde.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors();
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Object list = tr.getTransferData(flavors[0]);
list = list.toString().substring(1, list.toString().length() - 1);
if (isValidImage(list)) {
Image droppedImage = Toolkit.getDefaultToolkit().getImage(list.toString());
image = toBufferedImage(droppedImage);
origiImage = toBufferedImage(droppedImage);
if (droppedImage != null) {
setSize(image.getWidth(), image.getHeight());
dtde.dropComplete(true);
// This is a bad idea, apart from KeyListeners are just a bad idea,
// Each time you drop a new image, your registering a new key listener :P
// addKeyListener(new KeyListener() {
// #Override
// public void keyTyped(KeyEvent e) {
// }
//
// #Override
// public void keyReleased(KeyEvent e) {
// if (e.getKeyCode() == 10) {
// capture();
// }
// }
//
// #Override
// public void keyPressed(KeyEvent e) {
// }
// });
return;
}
}
dtde.rejectDrop();
} catch (Exception e) {
dtde.rejectDrop();
}
}
public boolean isValidImage(Object list) {
System.out.println(list.toString());
for (String string : ImageIO.getReaderFormatNames()) {
if (list.toString().contains(string)) {
return true;
}
}
return false;
}
public BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
image = new ImageIcon(image).getImage();
boolean hasAlpha = hasAlpha(image);
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
int transparency = Transparency.OPAQUE;
if (hasAlpha == true) {
transparency = Transparency.BITMASK;
}
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
if (bimage == null) {
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha == true) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
Graphics g = bimage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
public boolean hasAlpha(Image image) {
if (image instanceof BufferedImage) {
return ((BufferedImage) image).getColorModel().hasAlpha();
}
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}
return pg.getColorModel().hasAlpha();
}
private void updateRectangle(int compWidth, int compHeight) {
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
if ((x + width) > compWidth) {
width = compWidth - x;
}
if ((y + height) > compHeight) {
height = compHeight - y;
}
if (rectToDraw != null) {
rectToDraw.setBounds(x, y, width, height);
} else {
rectToDraw = new Rectangle(x, y, width, height);
}
}
public void capture() {
BufferedImage croppedImage = origiImage.getSubimage(rectToDraw.x, rectToDraw.y, rectToDraw.width, rectToDraw.height);
setSize(rectToDraw.width, rectToDraw.height);
image = croppedImage;
currentRect = null;
repaint();
}
public void upload(BufferedImage image) {
// Sorry, you can uncomment this can't you
// String IMGUR_POST_URI = "http://api.imgur.com/2/upload.xml";
// String IMGUR_API_KEY = "b84e430b4a65d16a6955358141f21a61";
// String readLine = null;
// try {
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// ImageIO.write(image, "png", outputStream);
// URL url = new URL(IMGUR_POST_URI);
//
// String data = URLEncoder.encode("image", "UTF-8") + "=" + URLEncoder.encode(Base64.encodeBase64String(outputStream.toByteArray()).toString(), "UTF-8") + "&" + URLEncoder.encode("key", "UTF-8") + "=" + URLEncoder.encode(IMGUR_API_KEY, "UTF-8");
//
// URLConnection urlConnection = url.openConnection();
// urlConnection.setDoOutput(true);
// OutputStreamWriter wr = new OutputStreamWriter(urlConnection.getOutputStream());
// wr.write(data);
// wr.flush();
// // Get the response
// InputStream inputStream;
// if (((HttpURLConnection) urlConnection).getResponseCode() == 400) {
// inputStream = ((HttpURLConnection) urlConnection).getErrorStream();
// } else {
// inputStream = urlConnection.getInputStream();
// }
// BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
// String line;
// while ((line = reader.readLine()) != null) {
// readLine = line;
// }
// wr.close();
// reader.close();
// } catch (Exception e) {
// e.printStackTrace();
// }
// //Prints the url link of the image uploaded
// System.out.println(readLine.substring(readLine.indexOf("<original>") + 10, readLine.indexOf("</original>")));
}
public void dragEnter(DropTargetDragEvent dtde) {
}
public void dragExit(DropTargetEvent dte) {
}
public void dragOver(DropTargetDragEvent dtde) {
}
public void dropActionChanged(DropTargetDragEvent dtde) {
}
protected class CaptureListener extends MouseInputAdapter {
public void mouseDragged(MouseEvent e) {
updateSize(e);
}
public void mousePressed(MouseEvent e) {
requestFocusInWindow();
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateRectangle(getWidth(), getHeight());
repaint();
}
public void mouseReleased(MouseEvent e) {
updateSize(e);
}
public void updateSize(MouseEvent e) {
if (currentRect != null) {
currentRect.setSize(e.getX() - currentRect.x, e.getY() - currentRect.y);
updateRectangle(getWidth(), getHeight());
repaint();
}
}
}
}
}
Now it works...
Quick answer
The problem you asked about was that the window decorations (the "frame", titlebar etc.) cover parts of the cropped image. (That's why I thought comparing with expected results or the result uploaded/saved to file might help).
In terms of a solution you basically have to ensure that you do not resize the window as by its outer boundaries, but give the content the space needed. There are several ways to do that. MadProgrammer moved most of your code to a panel class and added an instance of that as the JFrame's content.
Alternatively you could keep using the JFrame contentPane and just ensure that you set the size on it instead of the frame:
getContentPane().setPreferredSize(new Dimension(newWidth, newHeight));
pack();
(methods are called on your JFrame instance, the solution works from Java 5 on)
Finding the answer yourself
The image cropping itself is fine. Your problem lies somewhere else and I want to help you find it yourself.
Minimize the problem
You have to narrow down where in your code the "strange things" happen. So do not stare at all your code but make a copy and, as a first step throw out what is not needed for the cropping.
Throw out the upload stuff, you don't need it for cropping.
A lot of your code deals with getting a filename by drag and drop. Shorten it down to either a command line option or a plain hardcoded string (hardcoded stuff is bad in general, but for debugging it's okay). And so on.
Actually cropping does not need any GUI, really. So what happens if you write your cropped image to a file instead of displaying it in a window?
Know what to expect
GUI or not, put out the position(x,y) and dimension(width,height) of your selection. Now, how does the image cropped by your program compare to the same image cropped with the same parameters using gimp/ImageMagick/... ? Which parts of the image are missing?
Ask good questions
Following those steps and asking such questions, you should know what's wrong with your program. At the very least you will be able to ask a short and precise question about your problem. And on StackOverflow there will probably be someone who can answer it!
Related
I want to write a program in Java Swing which will show the world map, where a user can click on each country(i.e each country is a button). I thought that the most convenient way to do it is to split a world map image into buttons, but I couldn't figure out how can I do this.
I looked at this question: Split image into clickable regions , the given answer there shows how to split the image into rectangles, but I have to split it into arbitrary shapes.
This is the image i want to work on:
A 'little' bit of number crunching can define areas or shapes of particular colors in an image. E.G. Starting with this:
Original image, cropped and reduced to a binary (2 color) image, then the oceans flood filled. All but the flood filling done in Java code not shown.
Then running the shape algorithm based on colors near white (be patient - it takes a while), will produce a series of areas used to render this over the top. A mouse motion listener has been added to color the area under the pointer to dark green.
This is the code that produces that image. The mouse pointer is currently pointing at China.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.imageio.ImageIO;
/*
Outline code from:
https://stackoverflow.com/q/7218309/418556
*/
public class WorldMapArea {
private JComponent ui = null;
JLabel output = new JLabel();
public static final int SIZE = 750;
BufferedImage image;
Area area;
ArrayList<Shape> shapeList;
public WorldMapArea() {
try {
initUI();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public final void initUI() throws Exception {
if (ui != null) {
return;
}
URL url = new URL("https://i.stack.imgur.com/N4eOn.png");
image = ImageIO.read(url);
long then = System.currentTimeMillis();
System.out.println("" + then);
area = getOutline(Color.WHITE, image, 12);
long now = System.currentTimeMillis();
System.out.println("Time in mins: " + (now - then) / 60000d);
shapeList = separateShapeIntoRegions(area);
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
output.addMouseMotionListener(new MousePositionListener());
ui.add(output);
refresh();
}
public Area getOutline(Color target, BufferedImage bi, int tolerance) {
// construct the GeneralPath
GeneralPath gp = new GeneralPath();
boolean cont = false;
for (int xx = 0; xx < bi.getWidth(); xx++) {
for (int yy = 0; yy < bi.getHeight(); yy++) {
if (isIncluded(new Color(bi.getRGB(xx, yy)), target, tolerance)) {
//if (bi.getRGB(xx,yy)==targetRGB) {
if (cont) {
gp.lineTo(xx, yy);
gp.lineTo(xx, yy + 1);
gp.lineTo(xx + 1, yy + 1);
gp.lineTo(xx + 1, yy);
gp.lineTo(xx, yy);
} else {
gp.moveTo(xx, yy);
}
cont = true;
} else {
cont = false;
}
}
cont = false;
}
gp.closePath();
// construct the Area from the GP & return it
return new Area(gp);
}
public static ArrayList<Shape> separateShapeIntoRegions(Shape shape) {
ArrayList<Shape> regions = new ArrayList<>();
PathIterator pi = shape.getPathIterator(null);
GeneralPath gp = new GeneralPath();
while (!pi.isDone()) {
double[] coords = new double[6];
int pathSegmentType = pi.currentSegment(coords);
int windingRule = pi.getWindingRule();
gp.setWindingRule(windingRule);
if (pathSegmentType == PathIterator.SEG_MOVETO) {
gp = new GeneralPath();
gp.setWindingRule(windingRule);
gp.moveTo(coords[0], coords[1]);
} else if (pathSegmentType == PathIterator.SEG_LINETO) {
gp.lineTo(coords[0], coords[1]);
} else if (pathSegmentType == PathIterator.SEG_QUADTO) {
gp.quadTo(coords[0], coords[1], coords[2], coords[3]);
} else if (pathSegmentType == PathIterator.SEG_CUBICTO) {
gp.curveTo(
coords[0], coords[1],
coords[2], coords[3],
coords[4], coords[5]);
} else if (pathSegmentType == PathIterator.SEG_CLOSE) {
gp.closePath();
regions.add(new Area(gp));
} else {
System.err.println("Unexpected value! " + pathSegmentType);
}
pi.next();
}
return regions;
}
class MousePositionListener implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent e) {
// do nothing
}
#Override
public void mouseMoved(MouseEvent e) {
refresh();
}
}
public static boolean isIncluded(Color target, Color pixel, int tolerance) {
int rT = target.getRed();
int gT = target.getGreen();
int bT = target.getBlue();
int rP = pixel.getRed();
int gP = pixel.getGreen();
int bP = pixel.getBlue();
return ((rP - tolerance <= rT) && (rT <= rP + tolerance)
&& (gP - tolerance <= gT) && (gT <= gP + tolerance)
&& (bP - tolerance <= bT) && (bT <= bP + tolerance));
}
private void refresh() {
output.setIcon(new ImageIcon(getImage()));
}
private BufferedImage getImage() {
BufferedImage bi = new BufferedImage(
2 * SIZE, SIZE, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.drawImage(image, 0, 0, output);
g.setColor(Color.ORANGE.darker());
g.fill(area);
g.setColor(Color.RED);
g.draw(area);
try {
Point p = MouseInfo.getPointerInfo().getLocation();
Point p1 = output.getLocationOnScreen();
int x = p.x - p1.x;
int y = p.y - p1.y;
Point pointOnImage = new Point(x, y);
for (Shape shape : shapeList) {
if (shape.contains(pointOnImage)) {
g.setColor(Color.GREEN.darker());
g.fill(shape);
break;
}
}
} catch (Exception doNothing) {
}
g.dispose();
return bi;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
ex.printStackTrace();
}
WorldMapArea o = new WorldMapArea();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.setResizable(false);
f.pack();
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
So I have two classes here:
PhotoComponent class:
(This class is to handle a specific image as a JComponent. When "flipped" I want to draw pen strokes instead of having an image. So I replace the image with a rectangle, attempting to draw pen strokes over it.)
public class PhotoComponent extends JComponent {
private Image pic;
private boolean flipped;
private int contentAreaWidth;
private int contentAreaHeight;
p
#Override
public void paintComponent(Graphics g) {
//Does all the drawing and contains whatever state information is associated with the photo
//create an action event to auto call repaint
//call repaint anytime flip was changed to true or false
System.out.println("Draw: " + draw + ", Pic: " + pic);
if (draw && pic != null) {
super.paintComponent(g);
System.out.println("width using this: " + this.getWidth() + ", actual width of JPanel: " + contentAreaWidth);
System.out.println("height using this: " + this.getHeight() + ", actual height of JPanel: " + contentAreaHeight);
g2 = (Graphics2D) g;
int x = (contentAreaWidth - pic.getWidth(null)) / 2;
int y = (contentAreaHeight - pic.getHeight(null)) / 2;
if (!flipped) {
g2.drawImage(pic, x, y, null);
} else if (flipped) {
g2.setColor(Color.WHITE);
g2.fillRect(x,y,pic.getWidth(null), pic.getHeight(null));
g2.drawRect(x, y, pic.getWidth(null), pic.getHeight(null));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (drawingMode) {
g2.setPaint(Color.RED);
if (drawOval) {
penStrokes.put(ovalX, ovalY);
if (penStrokes != null) {
for (Integer xCoor : penStrokes.keySet()) {
g2.setPaint(Color.RED);
int brushSize = 5;
g2.fillOval((xCoor - (brushSize / 2)), (penStrokes.get(xCoor) - (brushSize / 2)), brushSize, brushSize);
//System.out.println("SIZE OF HASHTABLE: " + penStrokes.size());
}
}
System.out.println("Filling an oval!" + ovalX + ", " + ovalY);
}
} else if (textMode) {
g2.setPaint(Color.YELLOW);
if (drawRect) {
rectDimensions.add(rectX);
rectDimensions.add(rectY);
rectDimensions.add(rectWidth);
rectDimensions.add(rectHeight);
for (int i = 0; i < rectDimensions.size(); i+=4) {
g2.fillRect(rectDimensions.get(i), rectDimensions.get(i+1), rectDimensions.get(i+2), rectDimensions.get(i+3));
g2.drawRect(rectDimensions.get(i), rectDimensions.get(i+1), rectDimensions.get(i+2), rectDimensions.get(i+3));
}
}
}
System.out.println("This is being called again!");
}
}
}
public void setRectangle(int x, int y, int width, int height) {
drawRect = true;
rectX = x;
rectY = y;
rectWidth = width;
rectHeight = height;
}
public void removeRectangle() {
drawRect = false;
}
public int[] setOval(int currentX, int currentY) {
drawOval = true;
int[] toReturn = {ovalX, ovalY};
ovalX =
NOTE THE DRAWLINE() METHOD ABOVE. I am drawing at the given points, repainting, and setting the old variables to be the current variables.
Main class:
private static PhotoComponent img;
private static JFrame frame;
private static JPanel contentArea;
//Mouse Coordinates for PenStrokes
private static int oldX, oldY;
//Mouse Coordinates for Sticky Notes
private static Point clickPoint;
public static void main (String[] args) {
frame = new JFrame("PhotoManip");
img = null;
contentArea = null;
oldX = 0;
oldY = 0;
setupMenubar(frame);
setupJFrame(frame);
}
private static void addPhotoComponent(File file) {
}
if (img.getTextMode()) {
img.removeRectangle();
clickPoint = null;
}
}
});
img.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (img.getDrawingMode()) {
if (withinRange(e.getX(), e.getY())) {
int[] toUpdate = img.setOval(e.getX(), e.getY());
oldX = toUpdate[0];
oldY = toUpdate[1];
img.repaint();
}
}
if (img.getTextMode()) {
if (withinRange(e.getX(), e.getY())) {
Point dragPoint = e.getPoint();
h, height);
img.repaint();
}
}
}
});
if (img!=null) {
contentArea.add(img);
}
}
private static boolean withinRange(int x, int y) {
if (x > img.getX() && x < img.getX() + img.getWidth()) {
if (y > img.getY() && y < img.getY() + img.getHeight()) {
return true;
}
}
return false;
}
private static void flipImage() {
if (!img.isFlipped()) {
img.setFlipped(true);
} else if (img.isFlipped()) {
img.setFlipped(false);
}
}
drawLine() is called above in this main class, when a mousedrag occurs. Problem is that the strokes don't appear to show.
I know that the program is calling g2.fillOval() because I am printing out a verification statement afterwards.
Additionally, I have created print statements for when the mouse is pressed and dragged and they are getting the correct coordinates?
Why don't red strokes appear? I'm confused. Is it the way my code is structured?
The crux of your problem is that you are trying to draw something outside the paintComponent method, which is never supported. Whatever you draw will get overwritten by the next call of paintComponent, which will happen almost instantly. We can solve this by storing the co-ordinates of the oval and drawing it within paintComponent instead of trying to draw on a graphics object outside of the paintComponent method. See code below:
First we are going to add the following variables to your PhotoComponent class:
private boolean drawOval = false;
private int ovalX = 0;
private int ovalY = 0;
Then we will add methods for controlling them:
public int[] setOval(int currentX, int currentY) {
drawOval = true;
int[] toReturn = {ovalX, ovalY};
ovalX = currentX;
ovalY = currentY;
return toReturn;
}
public void removeOval() {
drawOval = false;
}
After that we can change the paintComponent method to have it draw the oval based on those variables:
#Override
public void paintComponent(Graphics g) {
//Does all the drawing and contains whatever state information is associated with the photo
//create an action event to auto call repaint
//call repaint anytime flip was changed to true or false
super.paintComponent(g);
g2 = (Graphics2D) g;
int x = (contentAreaWidth - pic.getWidth(null)) / 2;
int y = (contentAreaHeight - pic.getHeight(null)) / 2;
if (!flipped) {
g2.drawImage(pic, x, y, null);
} else if (flipped) {
g2.setColor(Color.WHITE);
g2.fillRect(x, y, pic.getWidth(null), pic.getHeight(null));
g2.drawRect(x, y, pic.getWidth(null), pic.getHeight(null));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.RED);
}
//took the code you already used for drawing the oval and moved it here
if (drawOval) {
g2.setPaint(Color.RED);
int brushSize = 5;
g2.fillOval((ovalX - (brushSize / 2)), (ovalY - (brushSize / 2)), brushSize, brushSize);
}
}
Finally change the addPhotoComponent method to update those variables instead of trying to draw the oval directly:
private static void addPhotoComponent(File file) {
Image image = null;
try {
image = ImageIO.read(file);
} catch (IOException e2) {
System.out.println("ERROR: Couldn't get image.");
}
img = new PhotoComponent(image, contentArea);
img.revalidate();
img.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
// your code here
System.out.println("You flipped the photo!!!");
flipImage();
img.repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
img.setOval(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
img.removeOval();
}
});
img.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int[] toUpdate = img.setOval(e.getX(), e.getY());
oldX = toUpdate[0];
oldY = toUpdate[1];
}
});
if (img != null) {
contentArea.add(img);
}
}
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 implemented a small example using InfiniteProgressDemo and works perfectly, showing the "loading wheel" rotating at the center of the frame.
Now I have ported it to my program. I have a button for a connect action (do not worry about the BussinessException):
public class ConnectAction extends AbstractAction {
private JFrame framePrincipal;
private InfiniteProgressPanel glassPane;
/**
* Constructor
* #param m
* #param pNodos
* #param pGraficas
* #param front
* #throws BusinessException
*/
public ConnectAction(Main main, DockFrontend front) throws BusinessException{
super();
this.framePrincipal = main.getFramePrincipal();
this.glassPane = new InfiniteProgressPanel();
framePrincipal.setGlassPane(glassPane);
}
private void perform() throws BusinessException {
// DOING SOME HEAVY STUFF...
System.out.println("You've successfully waited :)");
glassPane.stop();
}
#Override
public Object execute() throws BusinessException {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
glassPane.start();
Thread performer = new Thread(new Runnable() {
public void run() {
try {
perform();
} catch (BusinessException e) {
e.printStackTrace();
}
}
}, "Performer");
performer.start();
}
});
return null;
}
#Override
public void redo() throws BusinessException {
// TODO Auto-generated method stub
}
#Override
public void undo() throws BusinessException {
// TODO Auto-generated method stub
}
#Override
protected void initServices() throws BusinessException {
}
}
The only file I needed from the InfiniteProgressDemo demo was InfiniteProgressPane.
When I execute and push my button, the "loading wheel" appears, but not at the center of the frame. It appears on one corner... next second it appears on another corner, and so on. I don't know what's wrong.
I also attach here the InfiniteProgressDemo:
public class InfiniteProgressPanel extends JComponent implements MouseListener
{
protected Area[] ticker = null;
protected Thread animation = null;
protected boolean started = false;
protected int alphaLevel = 0;
protected int rampDelay = 300;
protected float shield = 0.70f;
protected String text = "";
protected int barsCount = 14;
protected float fps = 15.0f;
protected RenderingHints hints = null;
public InfiniteProgressPanel()
{
this("");
}
public InfiniteProgressPanel(String text)
{
this(text, 14);
}
public InfiniteProgressPanel(String text, int barsCount)
{
this(text, barsCount, 0.70f);
}
public InfiniteProgressPanel(String text, int barsCount, float shield)
{
this(text, barsCount, shield, 15.0f);
}
public InfiniteProgressPanel(String text, int barsCount, float shield, float fps)
{
this(text, barsCount, shield, fps, 300);
}
public InfiniteProgressPanel(String text, int barsCount, float shield, float fps, int rampDelay)
{
this.text = text;
this.rampDelay = rampDelay >= 0 ? rampDelay : 0;
this.shield = shield >= 0.0f ? shield : 0.0f;
this.fps = fps > 0.0f ? fps : 15.0f;
this.barsCount = barsCount > 0 ? barsCount : 14;
this.hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
this.hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
this.hints.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
public void setText(String text)
{
repaint();
this.text = text;
}
public String getText()
{
return text;
}
public void start()
{
addMouseListener(this);
setVisible(true);
ticker = buildTicker();
animation = new Thread(new Animator(true));
animation.start();
}
public void stop()
{
if (animation != null) {
animation.interrupt();
animation = null;
animation = new Thread(new Animator(false));
animation.start();
}
}
public void interrupt()
{
if (animation != null) {
animation.interrupt();
animation = null;
removeMouseListener(this);
setVisible(false);
}
}
public void paintComponent(Graphics g)
{
if (started)
{
int width = getWidth();
int height = getHeight();
double maxY = 0.0;
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHints(hints);
g2.setColor(new Color(255, 255, 255, (int) (alphaLevel * shield)));
g2.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < ticker.length; i++)
{
int channel = 224 - 128 / (i + 1);
g2.setColor(new Color(channel, channel, channel, alphaLevel));
g2.fill(ticker[i]);
Rectangle2D bounds = ticker[i].getBounds2D();
if (bounds.getMaxY() > maxY)
maxY = bounds.getMaxY();
}
if (text != null && text.length() > 0)
{
FontRenderContext context = g2.getFontRenderContext();
TextLayout layout = new TextLayout(text, getFont(), context);
Rectangle2D bounds = layout.getBounds();
g2.setColor(getForeground());
layout.draw(g2, (float) (width - bounds.getWidth()) / 2,
(float) (maxY + layout.getLeading() + 2 * layout.getAscent()));
}
}
}
private Area[] buildTicker()
{
Area[] ticker = new Area[barsCount];
Point2D.Double center = new Point2D.Double((double) getWidth() / 2, (double) getHeight() / 2);
double fixedAngle = 2.0 * Math.PI / ((double) barsCount);
for (double i = 0.0; i < (double) barsCount; i++)
{
Area primitive = buildPrimitive();
AffineTransform toCenter = AffineTransform.getTranslateInstance(center.getX(), center.getY());
AffineTransform toBorder = AffineTransform.getTranslateInstance(45.0, -6.0);
AffineTransform toCircle = AffineTransform.getRotateInstance(-i * fixedAngle, center.getX(), center.getY());
AffineTransform toWheel = new AffineTransform();
toWheel.concatenate(toCenter);
toWheel.concatenate(toBorder);
primitive.transform(toWheel);
primitive.transform(toCircle);
ticker[(int) i] = primitive;
}
return ticker;
}
private Area buildPrimitive()
{
Rectangle2D.Double body = new Rectangle2D.Double(6, 0, 30, 12);
Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 12, 12);
Ellipse2D.Double tail = new Ellipse2D.Double(30, 0, 12, 12);
Area tick = new Area(body);
tick.add(new Area(head));
tick.add(new Area(tail));
return tick;
}
protected class Animator implements Runnable
{
private boolean rampUp = true;
protected Animator(boolean rampUp)
{
this.rampUp = rampUp;
}
public void run()
{
Point2D.Double center = new Point2D.Double((double) getWidth() / 2, (double) getHeight() / 2);
double fixedIncrement = 2.0 * Math.PI / ((double) barsCount);
AffineTransform toCircle = AffineTransform.getRotateInstance(fixedIncrement, center.getX(), center.getY());
long start = System.currentTimeMillis();
if (rampDelay == 0)
alphaLevel = rampUp ? 255 : 0;
started = true;
boolean inRamp = rampUp;
while (!Thread.interrupted())
{
if (!inRamp)
{
for (int i = 0; i < ticker.length; i++)
ticker[i].transform(toCircle);
}
repaint();
if (rampUp)
{
if (alphaLevel < 255)
{
alphaLevel = (int) (255 * (System.currentTimeMillis() - start) / rampDelay);
if (alphaLevel >= 255)
{
alphaLevel = 255;
inRamp = false;
}
}
} else if (alphaLevel > 0) {
alphaLevel = (int) (255 - (255 * (System.currentTimeMillis() - start) / rampDelay));
if (alphaLevel <= 0)
{
alphaLevel = 0;
break;
}
}
try
{
Thread.sleep(inRamp ? 10 : (int) (1000 / fps));
} catch (InterruptedException ie) {
break;
}
Thread.yield();
}
if (!rampUp)
{
started = false;
repaint();
setVisible(false);
removeMouseListener(InfiniteProgressPanel.this);
}
}
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
Finally the problem is that getWidth() and getHeight() methods aren't getting the correct dimensions of the JFrame of my main windows, because they are called straigth forwards. Modifying the InfiniteProgressDemo constructors to receive a JFrame myFrame, and calling myFrame.getWidth() and myFrame.getHeight() got the animation working correctly in the center of the screen.
I'm trying to create a custom extension of BasicSliderUI. I'm just trying to make the thumb a circle (note I'm in the Windows L&F). I've created a very simple implementation that just calls g.drawOval, but whenever I drag it, it leaves a "trail" behind. Any ideas why this is?
thanks,
Jeff
You need to call repaint on the whole thing, you cant just draw the oval on top of it. Swing will by default only repaint what needs to be repainted, which usually isn't the whole control. When are you drawing the circle?
If you want to get rid of "trail" when you drag you should write your custom TrackListener and control trumb position related to mouse move.
Look at my implementation:
public class LightSliderUI extends BasicSliderUI{
private final Color rangeColor = Color.BLUE;
private final BasicStroke stroke = new BasicStroke(2f);
private transient boolean upperDragging;
public LightSliderUI(JSlider b) {
super(b);
}
public static ComponentUI createUI(JComponent c) {
return new LightSliderUI((JSlider)c);
}
#Override
protected void calculateThumbSize() {
super.calculateThumbSize();
thumbRect.setSize(thumbRect.width, thumbRect.height);
}
/** Creates a listener to handle track events in the specified slider.*/
#Override
protected TrackListener createTrackListener(JSlider slider) {
return new RangeTrackListener();
}
#Override
protected void calculateThumbLocation() {
// Call superclass method for lower thumb location.
super.calculateThumbLocation();
// Adjust upper value to snap to ticks if necessary.
if (slider.getSnapToTicks()) {
int upperValue = slider.getValue() + slider.getExtent();
int snappedValue = upperValue;
int majorTickSpacing = slider.getMajorTickSpacing();
int minorTickSpacing = slider.getMinorTickSpacing();
int tickSpacing = 0;
if (minorTickSpacing > 0) {
tickSpacing = minorTickSpacing;
} else if (majorTickSpacing > 0) {
tickSpacing = majorTickSpacing;
}
if (tickSpacing != 0) {
// If it's not on a tick, change the value
if ((upperValue - slider.getMinimum()) % tickSpacing != 0) {
float temp = (float)(upperValue - slider.getMinimum()) / (float)tickSpacing;
int whichTick = Math.round(temp);
snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
}
if (snappedValue != upperValue) {
slider.setExtent(snappedValue - slider.getValue());
}
}
}
// Calculate upper thumb location. The thumb is centered over its
// value on the track.
if (slider.getOrientation() == JSlider.HORIZONTAL) {
int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent());
thumbRect.x = upperPosition - (thumbRect.width / 2);
thumbRect.y = trackRect.y;
} else {
int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent());
thumbRect.x = trackRect.x;
thumbRect.y = upperPosition - (thumbRect.height / 2);
}
slider.repaint();
}
/** Returns the size of a thumb.
* Parent method not use size from LaF
* #return size of trumb */
#Override
protected Dimension getThumbSize() {
return Dimensions.getSliderThumbSize();
}
private Shape createThumbShape(int width, int height) {
Ellipse2D shape = new Ellipse2D.Double(0, 0, width, height);
return shape;
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke old = g2d.getStroke();
g2d.setStroke(stroke);
g2d.setPaint(Colors.TEXT_STEEL);
Color oldColor = Colors.TEXT_STEEL;
Rectangle trackBounds = trackRect;
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
int lowerX = thumbRect.width / 2;
int upperX = thumbRect.x + (thumbRect.width / 2);
int cy = (trackBounds.height / 2) - 2;
g2d.translate(trackBounds.x, trackBounds.y + cy);
g2d.setColor(rangeColor);
g2d.drawLine(lowerX - trackBounds.x, 2, upperX - trackBounds.x, 2);
g2d.translate(-trackBounds.x, -(trackBounds.y + cy));
g2d.setColor(oldColor);
}
g2d.setStroke(old);
}
/** Overrides superclass method to do nothing. Thumb painting is handled
* within the <code>paint()</code> method.*/
#Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = knobBounds.height;
Graphics2D g2d = (Graphics2D) g.create();
Shape thumbShape = createThumbShape(w - 1, h - 1);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(knobBounds.x, knobBounds.y);
g2d.setColor(Color.WHITE);
g2d.fill(thumbShape);
g2d.setColor(Colors.BIOLIN_BLUE_TINT);
g2d.draw(thumbShape);
g2d.dispose();
}
/** Listener to handle model change events. This calculates the thumb
* locations and repaints the slider if the value change is not caused by dragging a thumb.*/
public class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent arg0) {
calculateThumbLocation();
slider.repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JSlider slider = new JSlider(0, 100);
slider.setPaintTicks(true);
slider.setUI(new LightSliderUI(slider));
frame.add(slider);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
/** Listener to handle mouse movements in the slider track.*/
public class RangeTrackListener extends TrackListener {
#Override
public void mouseClicked(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX -= thumbRect.width / 2; // Because we want the mouse location correspond to middle of the "thumb", not left side of it.
moveUpperThumb();
}
public void mousePressed(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (slider.isRequestFocusEnabled()) {
slider.requestFocus();
}
boolean upperPressed = false;
if (slider.getMinimum() == slider.getValue()) {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
} else {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
}
if (upperPressed) {
switch (slider.getOrientation()) {
case JSlider.VERTICAL:
offset = currentMouseY - thumbRect.y;
break;
case JSlider.HORIZONTAL:
offset = currentMouseX - thumbRect.x;
break;
}
//upperThumbSelected = true;
upperDragging = true;
return;
}
upperDragging = false;
}
#Override
public void mouseReleased(MouseEvent e) {
upperDragging = false;
slider.setValueIsAdjusting(false);
super.mouseReleased(e);
}
#Override
public void mouseDragged(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (upperDragging) {
slider.setValueIsAdjusting(true);
moveUpperThumb();
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
/** Moves the location of the upper thumb, and sets its corresponding value in the slider.*/
public void moveUpperThumb() {
int thumbMiddle = 0;
switch (slider.getOrientation()) {
case JSlider.HORIZONTAL:
int halfThumbWidth = thumbRect.width / 2;
int thumbLeft = currentMouseX - offset;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int hMax = xPositionForValue(slider.getMaximum() -
slider.getExtent());
if (drawInverted()) {
trackLeft = hMax;
}
else {
trackRight = hMax;
}
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
setThumbLocation(thumbLeft, thumbRect.y);//setThumbLocation
thumbMiddle = thumbLeft + halfThumbWidth;
slider.setValue(valueForXPosition(thumbMiddle));
break;
default:
return;
}
}
}
}