JScrollPane blank until you scroll. - java

I have a JScrollPane implemented like so in the frame:
public ImagePanel imgPane = new ImagePanel();
JScrollPane scrollPane = new JScrollPane(imgPane);
ImagePanel is an extension of JPanel:
public class ImagePanel extends JPanel {
private BufferedImage img;
public ImagePanel(BufferedImage img) {
this.img = img;
}
public ImagePanel() {
}
#Override
public Dimension getPreferredSize() {
return img == null ? super.getPreferredSize() : new Dimension(img.getWidth(), img.getHeight());
}
protected Point getImageLocation() {
Point p = null;
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
p = new Point(x, y);
}
return p;
}
public void setImage(BufferedImage bi) {
img = bi;
}
public Point toImageContext(Point p) {
Point imgLocation = getImageLocation();
Point relative = new Point(p);
relative.x -= imgLocation.x;
relative.y -= imgLocation.y;
return relative;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Point p = getImageLocation();
g.drawImage(img, p.x, p.y, this);
}
}
The trouble I'm having is, when I load an image into the Pane:
frame.imgPane.setImage(img);
unless the previous image was the same size, the pane appears blank, no image, until you scroll. imgPane.repaint() has no effect on this. Is there a way to cause the JScrollPane to adjust to the new image without the user having to scroll?
Thanks

The setImage(...) method should also invoke:
img = bi;
revalidate(); // to invoke the layout manager
repaint(); // paint itself

Related

Java2D zoom and scroll relative to mouse position

I am trying to create a simple drawing application using swing and java2D.
The aim is to achieve a smooth zoom, always relative to the mouse cursor point.
The application consists of two classes: CanvasPane and Canvas.
CanvasPane class is a simple container with BorderLayout and JScrollPane in the center.
Canvas class is a drawing component added to a JScrollPane in CanvasPane.
Canvas draws a simple rectangle[800x600], and dispatches it's mouse events (wheel and drag).
When rectangle is smaller then visibleRect, canvas size is equal to visibleRect and I call AffineTransform.translate to follow mouse
(thanks to this question)
When rectangle grows bigger then canvas, canvas size grows too and became scrollable. Then I call scrollRectToVisible on it to follow mouse.
The question is:
How to use translate and scrollRectToVisible together, to smooth scale without graphics jumps. May be there is some known decision?
What I want is perfectly realized in YED Graph Editor, but it's code is closed.
I have tried with many examples but there were only zoom or scroll without complex usage of them.
Full code follows.
Class CanvasPane:
import javax.swing.*;
import java.awt.*;
public class CanvasPane extends JPanel {
private Canvas canvas;
public CanvasPane(boolean isDoubleBuffered) {
super(isDoubleBuffered);
setLayout(new BorderLayout());
canvas = new Canvas(1.0);
JScrollPane pane = new JScrollPane(canvas);
pane.getViewport().setBackground(Color.DARK_GRAY);
add(pane, BorderLayout.CENTER);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Test Graphics");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new CanvasPane(true), BorderLayout.CENTER);
frame.setSize(new Dimension(1000, 800));
frame.setVisible(true);
}
}
Class Canvas:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public class Canvas extends JComponent implements MouseWheelListener, MouseMotionListener, MouseListener {
private double zoom = 1.0;
public static final double SCALE_STEP = 0.1d;
private Dimension initialSize;
private Point origin;
private double previousZoom = zoom;
AffineTransform tx = new AffineTransform();
private double scrollX = 0d;
private double scrollY = 0d;
private Rectangle2D rect = new Rectangle2D.Double(0,0, 800, 600);
public Canvas(double zoom) {
this.zoom = zoom;
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
setAutoscrolls(true);
}
public Dimension getInitialSize() {
return initialSize;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Graphics2D g2d = (Graphics2D) g.create();
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.transform(tx);
g2d.setColor(Color.DARK_GRAY);
g2d.fill(rect);
g2d.setColor(Color.GRAY);
g2d.setStroke(new BasicStroke(5.0f));
g2d.draw(rect);
g2d.dispose();
}
#Override
public void setSize(Dimension size) {
super.setSize(size);
if (initialSize == null) {
this.initialSize = size;
}
}
#Override
public void setPreferredSize(Dimension preferredSize) {
super.setPreferredSize(preferredSize);
if (initialSize == null) {
this.initialSize = preferredSize;
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
double zoomFactor = - SCALE_STEP*e.getPreciseWheelRotation()*zoom;
zoom = Math.abs(zoom + zoomFactor);
//Here we calculate new size of canvas relative to zoom.
Rectangle realView = getVisibleRect();
Dimension d = new Dimension(
(int)(initialSize.width*zoom),
(int)(initialSize.height*zoom));
// if (d.getWidth() >= realView.getWidth() && d.getHeight() >= realView.getHeight()) {
setPreferredSize(d);
setSize(d);
validate();
followMouseOrCenter(e);
// }
//Here we calculate transform for the canvas graphics to scale relative to mouse
translate(e);
repaint();
previousZoom = zoom;
}
private void translate(MouseWheelEvent e) {
Rectangle realView = getVisibleRect();
Point2D p1 = e.getPoint();
Point2D p2 = null;
try {
p2 = tx.inverseTransform(p1, null);
} catch (NoninvertibleTransformException ex) {
ex.printStackTrace();
return;
}
Dimension d = getSize();
if (d.getWidth() <= realView.getWidth() && d.getHeight() <= realView.getHeight()) {
//Zooming and translating relative to the mouse position
tx.setToIdentity();
tx.translate(p1.getX(), p1.getY());
tx.scale(zoom, zoom);
tx.translate(-p2.getX(), -p2.getY());
} else {
//Only zooming, translate is not needed because scrollRectToVisible works;
tx.setToIdentity();
tx.scale(zoom, zoom);
}
// What to do next?
// The only translation works when rect is smaller then canvas size.
// Rect bigger then canvas must be scrollable, but relative to mouse position as before.
// But when the rect gets bigger than canvas, there is a terrible jump of a graphics.
//So there must be some combination of translation ans scroll to achieve a smooth scale.
//... brain explosion(((
}
public void followMouseOrCenter(MouseWheelEvent e) {
Point2D point = e.getPoint();
Rectangle visibleRect = getVisibleRect();
scrollX = point.getX()/previousZoom*zoom - (point.getX()-visibleRect.getX());
scrollY = point.getY()/previousZoom*zoom - (point.getY()-visibleRect.getY());
visibleRect.setRect(scrollX, scrollY, visibleRect.getWidth(), visibleRect.getHeight());
scrollRectToVisible(visibleRect);
}
public void mouseDragged(MouseEvent e) {
if (origin != null) {
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = getVisibleRect();
Dimension size = getSize();
view.x += deltaX;
view.y += deltaY;
scrollRectToVisible(view);
}
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
origin = new Point(e.getPoint());
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
I have finally achieved the enlightenment=)
We can simply make the canvas size much bigger than size of a drawing object, and so forget about calculating of any unintelligible transforms.
I initially make the canvas 100x bigger than drawing rectangle.
Then I zoom Graphics2D and translate zoomed graphics to the center of the canvas while painting. Next, I calculate a new visibleRect to follow mouse point and scroll to it.
When canvas became unscrollable, it's unreasonable to follow mouse because the drawing object is too small (100x smaller then its initial size), so I only center it to be always visible.
It works exactly as I needed.
So we have a working example with zoom following mouse and drag by mouse.
Code follows.
Class CanvasPane:
import javax.swing.*;
import java.awt.*;
public class CanvasPane extends JPanel {
private static Canvas canvas;
public CanvasPane(boolean isDoubleBuffered) {
super(isDoubleBuffered);
setLayout(new BorderLayout());
canvas = new Canvas(1.0);
JScrollPane pane = new JScrollPane(canvas);
pane.getViewport().setBackground(Color.DARK_GRAY);
add(pane, BorderLayout.CENTER);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Test Graphics");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new CanvasPane(true), BorderLayout.CENTER);
frame.setSize(new Dimension(1000, 800));
frame.pack();
frame.setVisible(true);
//Initial scrolling of the canvas to its center
Rectangle rect = canvas.getBounds();
Rectangle visibleRect = canvas.getVisibleRect();
double tx = (rect.getWidth() - visibleRect.getWidth())/2;
double ty = (rect.getHeight() - visibleRect.getHeight())/2;
visibleRect.setBounds((int)tx, (int)ty, visibleRect.width, visibleRect.height);
canvas.scrollRectToVisible(visibleRect);
}
}
Class Canvas:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public class Canvas extends JComponent implements MouseWheelListener, MouseMotionListener, MouseListener {
private double zoom = 1.0;
public static final double SCALE_STEP = 0.1d;
private Dimension initialSize;
private Point origin;
private double previousZoom = zoom;
private double scrollX = 0d;
private double scrollY = 0d;
private Rectangle2D rect = new Rectangle2D.Double(0,0, 800, 600);
private float hexSize = 3f;
public Canvas(double zoom) {
this.zoom = zoom;
addMouseWheelListener(this);
addMouseMotionListener(this);
addMouseListener(this);
setAutoscrolls(true);
//Set preferred size to be 100x bigger then drawing object
//So the canvas will be scrollable until our drawing object gets 100x smaller then its natural size.
//When the drawing object became so small, it is unnecessary to follow mouse on it,
//and we only center it on the canvas
setPreferredSize(new Dimension((int)(rect.getWidth()*100), (int)(rect.getHeight()*100)));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
//Obtain a copy of graphics object without any transforms
Graphics2D g2d = (Graphics2D) g.create();
g2d.clearRect(0, 0, getWidth(), getHeight());
//Zoom graphics
g2d.scale(zoom, zoom);
//translate graphics to be always in center of the canvas
Rectangle size = getBounds();
double tx = ((size.getWidth() - rect.getWidth() * zoom) / 2) / zoom;
double ty = ((size.getHeight() - rect.getHeight() * zoom) / 2) / zoom;
g2d.translate(tx, ty);
//Draw
g2d.setColor(Color.LIGHT_GRAY);
g2d.fill(rect);
g2d.setColor(Color.DARK_GRAY);
g2d.setStroke(new BasicStroke(5.0f));
g2d.draw(rect);
//Forget all transforms
g2d.dispose();
}
#Override
public void setSize(Dimension size) {
super.setSize(size);
if (initialSize == null) {
this.initialSize = size;
}
}
#Override
public void setPreferredSize(Dimension preferredSize) {
super.setPreferredSize(preferredSize);
if (initialSize == null) {
this.initialSize = preferredSize;
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
double zoomFactor = - SCALE_STEP*e.getPreciseWheelRotation()*zoom;
zoom = Math.abs(zoom + zoomFactor);
//Here we calculate new size of canvas relative to zoom.
Dimension d = new Dimension(
(int)(initialSize.width*zoom),
(int)(initialSize.height*zoom));
setPreferredSize(d);
setSize(d);
validate();
followMouseOrCenter(e.getPoint());
previousZoom = zoom;
}
public void followMouseOrCenter(Point2D point) {
Rectangle size = getBounds();
Rectangle visibleRect = getVisibleRect();
scrollX = size.getCenterX();
scrollY = size.getCenterY();
if (point != null) {
scrollX = point.getX()/previousZoom*zoom - (point.getX()-visibleRect.getX());
scrollY = point.getY()/previousZoom*zoom - (point.getY()-visibleRect.getY());
}
visibleRect.setRect(scrollX, scrollY, visibleRect.getWidth(), visibleRect.getHeight());
scrollRectToVisible(visibleRect);
}
public void mouseDragged(MouseEvent e) {
if (origin != null) {
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = getVisibleRect();
view.x += deltaX;
view.y += deltaY;
scrollRectToVisible(view);
}
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
origin = new Point(e.getPoint());
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}

How to Load an Image object in Java

I am getting input==null while trying to load an Image. I can't seem to figure out why, even after browsing a good number of StackOverflow questions. It looks right to me.
Here is the code:
private BufferedImage image;
public practice(){
setLayout(new BorderLayout());
timeBall.start();
JPanel panelNorth = makePanel();
panelNorth.setBackground(Color.CYAN);
add(panelNorth, BorderLayout.NORTH);
try{
image = ImageIO.read(practice.class.getResource("/pics/flying.png"));
}catch(IOException e){
e.printStackTrace();
}
}
public Dimension getPreferredSize() {
return image == null ? new Dimension(400, 300): new Dimension(image.getWidth(), image.getHeight());
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLUE);
ellipse = new Ellipse2D.Double(Ox, Oy+Speedy, height, height);
Graphics2D graphics = (Graphics2D)g;
g.drawImage(image, 0, 0, this);
graphics.fill(ellipse);
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
Oy = Oy + Speedy / 10;
Ox = Ox + Speedx / 10;
}

Calling setVisible(true) on an already visible frame

Question:
What does calling setVisible(true) on a JFrame which is already visible do? I was digging through the source code of JFrame, and ultimately, it boils down to this function in Component which does nothing to a frame if it is already visible. Why does it act like revalidate(); repaint();? (See SSCCE below)
Motivation:
I am working on a java app, for which I wrote a class JImagePanel which extends JPanel and allows the user to set an image as the background (see SSCCE). I have found that after editing the background of the panel, I was having issues repainting the background to the correct size. After scouring the internet, I found that the following works:
if(frame.isVisible()) frame.setVisible(true);
Ultimately, I solved the issue using
panel.revalidate();
panel.repaint();
, which I think is the better solution, but it got me to thinking what setVisible(true) actually does on an already visible frame. From my viewpoint, it shouldn't work - but in fact it does.
SSCCE
Here is an example that illustrates my issue. If nothing else, hopefully you find this class extremely useful in the future.
NOTE: Updated source of this file can be found on the project homepage on GitHub of the project this was created for.
Enjoy!
package com.dberm22.utils;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class JImagePanel extends JPanel {
private static final long serialVersionUID = 6841876236948317038L;
private Image img = null;
private Position position = Position.CENTER;
public enum Position{
STRETCH,
CENTER,
FIT,
FILL,
NONE;
}
public JImagePanel() {
}
public JImagePanel(String img) {
this(new ImageIcon(img).getImage());
}
public JImagePanel(Image img) {
setBackgroundImage(img);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
if (this.position.equals(Position.STRETCH))
{
if(this.img != null) g2.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
else if (this.position.equals(Position.FILL) || this.position.equals(Position.FIT))
{
if(this.img != null)
{
double scaleFactor = getScaleFactor(new Dimension(img.getWidth(null), img.getHeight(null)), getSize());
int scaleWidth = (int) Math.round(img.getWidth(null) * scaleFactor);
int scaleHeight = (int) Math.round(img.getHeight(null) * scaleFactor);
//Image img_scaled = img.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);
g2.drawImage(scaleImage(img, scaleWidth, scaleHeight, getBackground()), (getWidth() - scaleWidth)/2, (getHeight() - scaleHeight)/2, scaleWidth, scaleHeight, null);
}
}
else if (this.position.equals(Position.CENTER)) { if(this.img != null) g2.drawImage(img, (getWidth() - img.getWidth(null))/2, (getHeight() - img.getHeight(null))/2, null); }
}
public void setBackgroundImage(String img)
{
setBackgroundImage(new ImageIcon(img).getImage());
}
public void setBackgroundImage(Image img)
{
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
repaint();
}
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;
}
public double getScaleFactor(Dimension original, Dimension targetSize) {
double dScale = 1d;
if (original != null && targetSize != null) {
double dScaleWidth = getScaleFactor(original.width, targetSize.width);
double dScaleHeight = getScaleFactor(original.height, targetSize.height);
if (this.position.equals(Position.FIT)) dScale = Math.min(dScaleHeight, dScaleWidth);
else if(this.position.equals(Position.FILL)) dScale = Math.max(dScaleHeight, dScaleWidth);
}
return dScale;
}
public BufferedImage scaleImage(Image img, int width, int height, Color background) {
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = newImage.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setBackground(background);
g.clearRect(0, 0, width, height);
g.drawImage(img, 0, 0, width, height, null);
} finally {
g.dispose();
}
return newImage;
}
public void setBackgroundImagePosition(String pos)
{
if("Stretch".equals(pos)) setBackgroundImagePosition(Position.STRETCH);
else if("Center".equals(pos)) setBackgroundImagePosition(Position.CENTER);
else if("Fit".equals(pos)) setBackgroundImagePosition(Position.FIT);
else if("Fill".equals(pos)) setBackgroundImagePosition(Position.FILL);
else if("None".equals(pos)) setBackgroundImagePosition(Position.NONE);
}
public void setBackgroundImagePosition(Position pos)
{
this.position = pos;
repaint();
}
public static void main(String[] args)
{
JFrame frame = new JFrame("JImagePanel Test");
frame.setSize( Toolkit.getDefaultToolkit().getScreenSize());
frame.setPreferredSize( Toolkit.getDefaultToolkit().getScreenSize());
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate size for frame
JImagePanel panel = new JImagePanel();
frame.add(panel);
frame.setVisible(true);
try {Thread.sleep(2000);} catch (InterruptedException e) {}
panel.setBackgroundImage("C:\\Users\\David\\Pictures\\Wood.jpg");
panel.setBackgroundImagePosition(JImagePanel.Position.STRETCH);
panel.revalidate(); // need to revalidate()
panel.repaint(); //doesnt work by itself
try {Thread.sleep(2000);} catch (InterruptedException e) {}
panel.setBackgroundImage("C:\\Users\\David\\Pictures\\Wood.jpg");
panel.setBackgroundImagePosition(JImagePanel.Position.FIT);
frame.setVisible(true); //also works --why?
}
}
Calling setVisible(true) on a JFrame which is already visible works for you because this ends up calling validate() internally, which in turn revalidates all subcomponents in the frame.
To see why, refer to the implementation of Component.setVisible(boolean b):
public void setVisible(boolean b) {
show(b);
}
public void show(boolean b) {
if (b) {
show();
} else {
hide();
}
}
But the show() method is overriden in Window (of which JFrame is a subclass). So this ends up calling Window.show():
public void show() {
if (peer == null) {
addNotify();
}
validate();
[...]
Hope this explains the behaviour you are seeing.
Assuming you are after a half-way clean implementation of your imagePanel:
let the panel do its own revalidation/-paint as need (vs application code)
do not call setXXSize, ever, not even internally in the panel
That's change your setters and override the getXXSize. Note that basing the sizing hints on the image size alone is not what you would want to do in real world code, you probably want to take super's hint into account as well (f.i. if the panel has children)
#Override
public Dimension getPreferredSize() {
if (img != null) {
return new Dimension(img.getWidth(this), img.getHeight(this));
}
return super.getPreferredSize();
}
public void setBackgroundImage(Image img) {
this.img = img;
// need to revalidate as our sizing hints might have changed
revalidate();
repaint();
}
public void setBackgroundImagePosition(Position pos) {
this.position = pos;
repaint();
}
Application code that uses it now simply calls the setters, nothing else:
JFrame frame = new JFrame("JImagePanel Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setLayout(new FlowLayout()); // just to see the effect of a pref-respecting layout
final JImagePanel panel = new JImagePanel();
frame.add(panel);
final Image[] images = new Image[]{
XTestUtils.loadDefaultImage(), XTestUtils.loadDefaultImage("500by500.png"), null};
Action toggleImage = new AbstractAction("toggle image") {
int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
panel.setBackgroundImage(images[index]);
index = (index +1) % images.length;
}
};
Action togglePosition = new AbstractAction("toggle position") {
int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
panel.setBackgroundImagePosition(Position.values()[index]);
index = (index +1) % Position.values().length;
}
};
frame.add(new JButton(toggleImage), BorderLayout.NORTH);
frame.add(new JButton(togglePosition), BorderLayout.SOUTH);
// size for frame
//frame.setSize(800, 800);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate
frame.setVisible(true);

Component with transparent background to BufferedImage?

I have a component extends JPanel. It saves itself as bufferedimage on every call of paintComponent method. Component is not completely transparent, only its background. Problem is background is not transparent. I am using setOpaque(false);
Here is my relevant code;
private BufferedImage bufImage = null;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
// if first time call
if (bufImage == null) {
int w = this.getWidth();
int h = this.getHeight();
bufImage = (BufferedImage)this.createImage(w, h);
}
g2.drawImage(bufImage, null, 0, 0);
// draw sth
g2.draw(sth);
}
--
I also tried
bufImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
instead of
bufImage = (BufferedImage)this.createImage(w, h);
When i do that; background transperancy works but i can only draw with white color. I have no idea what causes that.
Note:
I used that code to check if it is working;
File outputfile = new File("saved.png");
ImageIO.write(bufImage, "png", outputfile);
saved.png had transparent background but drawings were only white.
This is the component, only lets drawing rectangle with mouse;
class PaintPanel extends JPanel implements MouseListener, MouseMotionListener {
private BufferedImage _bufImage = null;
private boolean dragging = false;
private Point _start = null, _end = null;
public PaintPanel() {
setOpaque(false);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
if (_bufImage == null) {
int w = this.getWidth();
int h = this.getHeight();
_bufImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
//_bufImage = (BufferedImage)this.createImage(w, h);
}
g2.drawImage(_bufImage, null, 0, 0);
if (dragging) {
drawCurrentShape(g2);
}
}
private void drawCurrentShape(Graphics2D g2) {
int startx = (int) _start.getX();
int starty = (int) _start.getY();
int stopx = (int) _end.getX();
int stopy = (int) _end.getY();
int width = Math.abs(startx - stopx);
int height = Math.abs(starty - stopy);
int x = startx, y = starty;
if(x > stopx)
x = stopx;
if(y > stopy)
y = stopy;
Rectangle r = new Rectangle(x, y, width, height);
g2.draw(r);
}
public void mousePressed(MouseEvent e) {
dragging = true;
_start = e.getPoint();
_end = _start;
}
public void mouseDragged(MouseEvent e) {
_end = e.getPoint();
this.repaint();
}
public void mouseReleased(MouseEvent e) {
_end = e.getPoint();
if (dragging) {
dragging = false;
drawCurrentShape(_bufImage.createGraphics());
this.repaint();
}
}
public void mouseMoved (MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited (MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
}
try this:
bufImage = new BufferedImage(w,h,java.awt.image.BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufImage.createGraphics();
this.print(graphics);
graphics.dispose();
The key is to use print()
Edit: I tried the following and transparency works like a charm:
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test2 {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel p = new JPanel();
p.setPreferredSize(new Dimension(400, 400));
p.setOpaque(false);
JButton button = new JButton("Hello world");
p.add(button);
frame.add(p);
frame.pack();
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
BufferedImage bufImage = new BufferedImage(p.getWidth(), p.getHeight(), java.awt.image.BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufImage.createGraphics();
p.print(graphics);
graphics.dispose();
try {
ImageIO.write(bufImage, "png", new File("d:/tmp/tmp.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
createImage(w, h) will create a "blank" image with the specified width and height. That being said, what you'll need to do is invoke createGraphics on the BufferedImage instance and draw directly to the returned Graphics object.

How to Zoom specific area of Image on Canvas in Swing

I want to Zoom specific area on image. which is selected by the user. image display on canvas using Swing. i already done full image zoom on canvas but can't implement specific area zoom.
please help
Canvas is awt not swing. Try JPanel instead. Example.
But if you already done full image zoom, try to make the same on a sub-image.
BufferedImage.getSubimage(x, y, w, h);
EDIT
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Example {
private Point startPoint = new Point(0, 0);
private Point rectLocale = new Point();
private Dimension rectSize = new Dimension();
private int zoom = 80;
private BufferedImage capture = null;
private BufferedImage raw;
public Example() throws Exception {
raw = new Robot().createScreenCapture(new Rectangle(
Toolkit.getDefaultToolkit().getScreenSize()));
MouseBehavior behavior = new MouseBehavior();
JPanel b = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(500, 500);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = ((Graphics2D) g);
g2d.drawImage(raw, 0, 0, null);
if (capture != null) {
int width2 = (int) (rectSize.width + rectSize.width * (zoom / 500d));
int height2 = (int) (rectSize.height + rectSize.height * (zoom / 500d));
int x2 = rectLocale.x - ((width2 - rectSize.width) / 2);
int y2 = rectLocale.y - ((height2 - rectSize.height) / 2);
Image scaledInstance = capture.getScaledInstance(
width2, height2, Image.SCALE_AREA_AVERAGING);
g2d.drawImage(scaledInstance, x2, y2, null);
g2d.drawRect(x2, y2, width2, height2);
} else {
g2d.draw(new Rectangle(rectLocale, rectSize));
}
}
};
b.addMouseMotionListener(behavior);
b.addMouseListener(behavior);
b.addMouseWheelListener(behavior);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(3);
f.add(b);
f.pack();
f.setVisible(true);
}
private class MouseBehavior extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
rectLocale = new Point();
rectSize = new Dimension();
capture = null;
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
Point currentPoint = e.getPoint();
rectSize.width = Math.abs(currentPoint.x - startPoint.x);
rectSize.height = Math.abs(currentPoint.y - startPoint.y);
if (e.isShiftDown()) {
rectSize.width = rectSize.height = Math.min(
rectSize.width, rectSize.height);
int dx = startPoint.x - rectSize.width;
int dy = startPoint.y - rectSize.height;
rectLocale.x = startPoint.x < currentPoint.x ? startPoint.x
: Math.max(dx, dy);
rectLocale.y = startPoint.y < currentPoint.y ? startPoint.y
: Math.min(dx, dy);
} else {
rectLocale.x = Math.min(currentPoint.x, startPoint.x);
rectLocale.y = Math.min(currentPoint.y, startPoint.y);
}
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (rectSize.width <= 0 || rectSize.height <= 0) {
capture = null;
} else {
capture = raw.getSubimage(Math.max(0, rectLocale.x),
Math.max(0, rectLocale.y), rectSize.width, rectSize.height);
}
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
zoom = Math.min(2000, Math.max(0, zoom + e.getUnitsToScroll() * 10));
if (e.getSource() instanceof JComponent) {
((JComponent) e.getSource()).repaint();
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Example example = new Example();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}

Categories

Resources