Related
I am trying to create spinning image Animation but something seems to be not working in the code. I am rotating image at various angles and drawing it but at the end I only end up single rotated image than animation. Is this possible to do in Java or do I need switch to C# Unity where I found multiple examples on doing so nothing so far in Java. I am new to Swing so I would really appreciate simplified answer.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.util.concurrent.TimeUnit;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Rotate extends JPanel {
public static void main(String[] args) {
new Rotate().go();
}
public void go() {
JFrame frame = new JFrame("Rotate");
JButton b = new JButton("click");
MyDrawPanel p = new MyDrawPanel();
frame.add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000, 1000);
frame.setVisible(true);
for(int i = 0; i < 300; i++) {
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
repaint();
}
}
class MyDrawPanel extends JPanel{
Image image = new ImageIcon(
getClass()
.getResource("wheel.png"))
.getImage();
public void animateCircle(Graphics2D g2d ) {
//g2d = (Graphics2D) g2d.create();
g2d.rotate(Math.toRadians(25), 250, 250);
g2d.drawImage(image, 0, 0, 500, 500, this);
}
#Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
Graphics2D g2d = (Graphics2D) g;
animateCircle(g2d);
}
}
}
I tried moving for loop in the paintComponent() method but it didn't help either.
Here
public void animateCircle(Graphics2D g2d ) {
//g2d = (Graphics2D) g2d.create();
g2d.rotate(Math.toRadians(25), 250, 250);
g2d.drawImage(image, 0, 0, 500, 500, this);
}
You rotation is fixed, so you aren't seeing your image spinning
By changing your value in Math.toRadians(...), you can make it appear to spin
This
for(int i = 0; i < 300; i++) {
rotationStep ++;
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
repaint();
}
}
Is the wrong way to do animation in swing. The right way is to use a javax.swing.Timer
public class MyTimer implements ActionListener {
int rotationStep = 0;
public void actionPerformed(ActionEvent ae) {
// for(int i = 0; i < 300; i++) {
rotationStep ++;
repaint();
}
}
You can do it like this. I reorganized some of your code which you can of course change at your leisure. Most of the critical elements are documented within the code. Major changes include:
eliminating magic numbers - allows alterations to happen in one place
using Rendering hints to eliminate rotating images.
overridding getPreferredSize() in the panel class
computing panel size to allow full rotation within panel.
using a swing timer to control repaint and angle updates
public class Rotate extends JPanel {
BufferedImage image = null;
public static void main(String[] args) {
new Rotate().go();
}
public void go() {
JFrame frame = new JFrame("Rotate");
JButton b = new JButton("click");
File file = new File("wheel.png");
try {
image = ImageIO
.read(new FileInputStream(new File("H:/Bench.jpg")));
} catch (IOException ioe) {
ioe.printStackTrace();
}
// invoke an instance of the panel with the image
MyDrawPanel p = new MyDrawPanel();
frame.add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
// center the frame on the screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// start the animation
p.animateCircle();
}
class MyDrawPanel extends JPanel {
double angle = 0;
//increment of the angle of rotation
double inc = Math.toRadians(.1);
int imageWidth;
int imageHeight;
int panelWidth;
int panelHeight;
double ctrX;
double ctrY;
int startX;
int startY;
#Override
public Dimension getPreferredSize() {
return new Dimension(panelWidth, panelHeight);
}
public MyDrawPanel() {
double imageWidth = image.getWidth();
double imageHeight = image.getHeight();
setBackground(Color.WHITE);
// compute panel size to allow full rotation within by computing
//the image's diagonal length
panelWidth = (int)Math.hypot(imageWidth, imageHeight);
panelHeight = panelWidth;
//target location for writing object (upper left corner)
startX = (int)(panelWidth-imageWidth)/2;
startY = (int)(panelHeight-imageHeight)/2;
// center of rotation
ctrX = panelWidth/2;
ctrY = panelHeight/2;
}
// This starts the animation using a swing timer to update the angle and repaint the image
public void animateCircle() {
Timer timer = new Timer(0, (ae)-> {
angle += inc; repaint();
});
timer.setDelay(10);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// setting the rendering hints allows smooth rotation of images with minimal distortion
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
// rotate the graphics context about the center
g2d.rotate(angle, ctrX, ctrY);
// draw the image. Top left at startX and startY
g2d.drawImage(image, startX, startY, this);
}
}
}
Note: If the timer is set to a low value (faster rotation) and the image is too large, the image may not finish the current rotation cycle before the timer re-fires.
So I have to create an implementation of a Sierpinski Gasket with Swing.
I can't use recursion or triangles. I have to use the following
algorithm:
Pick 3 points to define a triangle.
Select one of the vertices as current Loop 50,000 times:
Randomly choose a vertex as the target.
Draw a pixel at the mid-point between the target and current.
Make current the mid-point.
In the image below is what I sometimes get upon compilation, but other times it will pop up and disappear or it will not show up at all. If it does show up, and then I resize the window it disappears (I don't care about this, but if it helps.) I can only produce the below image sometimes when I compile (about 1/3rd of the time.) Below the image is my code, separated in two classes.
Image of when it works
import java.awt.*;
import javax.swing.JFrame;
public class SierpinskiGasket {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("SierpinskiGasket");
frame.setSize(630,580);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawSierpinski Sierpinski = new drawSierpinski();
frame.add(Sierpinski);
frame.setVisible(true);
}
}
import javax.swing.*;
import java.awt.*;
public class drawSierpinski extends JPanel{
Point point1 = new Point(10,550),
point2 = new Point(300,30),
point3 = new Point(600,555),
current = point1, target;
private int count = 0;
public void paintComponent(Graphics g){
super.paintComponent(g);
while(count<= 50000){
int choice = (int)(Math.random()*3);
switch(choice){
case 0: target = point1; break;
case 1: target = point2; break;
case 2: target = point3; break;
default: System.exit(0);
}
current = midpoint(current,target);
g.drawLine(current.x,current.y,current.x,current.y);
count++;
}
}
public Point midpoint(Point a, Point b){
return new Point((Math.round(a.x+b.x)/2),
(Math.round(a.y+b.y)/2));
}
}
I am assuming that it has something to do with how Swing does multithreading, but unfortunately I don't have too much knowledge of how to fix it. Thank you very much for any help!
This loop:
while(count<= 50000) {
// ....
}
may take a while to complete, and meanwhile it will be completely blocking the Swing event thread at its most key point -- while drawing. What's more, any trivial re-draw will trigger the loop to re-run, again freezing your GUI completely.
The solution: do your drawing outside of paintComponent. Instead create a BufferedImage the size of your JPanel, get the image's Graphics object, draw your random dots for your triangle in the BufferedImage, and then display that image within your JPanel's paintComponent method. You could draw the image at program start up, and then start up the GUI after its complete, or you can start the GUI and draw to the BufferedImage in a background thread, and display it when done, either would be fine (if this is the only thing your GUI should be doing).
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SierpTest {
public static final int BI_WIDTH = 630;
public static final int BI_HEIGHT = 580;
public static void main(String[] args) {
// do this stuff off the swing event thread
final BufferedImage sierpImg = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = sierpImg.getGraphics();
// draw triangle with g here
g.dispose(); // always dispose of any Graphics you create yourself
// do this on the Swing event thread
SwingUtilities.invokeLater(() -> {
SierpPanel sierpPanel = new SierpPanel(sierpImg); // pass in image
JFrame frame = new JFrame("Siep Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(sierpPanel);
frame.pack(); // size it to the size of the JPanel
frame.setLocationRelativeTo(null); // center it
frame.setVisible(true);
});
}
}
class SierpPanel extends JPanel {
private BufferedImage img = null;
public SierpPanel(BufferedImage img) {
this.img = img;
}
// so that JPanel sizes itself with the image
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
}
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SierpTest {
public static final int BI_WIDTH = 630;
public static final int BI_HEIGHT = 580;
private static final int MAX_COUNT = 100000;
public static void main(String[] args) {
// do this stuff off the swing event thread
Point point1 = new Point(10, 550);
Point point2 = new Point(300, 30);
Point point3 = new Point(600, 555);
Point current = point1;
Point target = current;
int count = 0;
final BufferedImage sierpImg = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = sierpImg.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g.setColor(Color.BLACK);
while (count <= MAX_COUNT) {
int choice = (int) (Math.random() * 3);
switch (choice) {
case 0:
target = point1;
break;
case 1:
target = point2;
break;
case 2:
target = point3;
break;
default:
System.exit(0);
}
current = midpoint(current, target);
g.drawLine(current.x, current.y, current.x, current.y);
count++;
}
// draw triangle with g here
g.dispose(); // always dispose of any Graphics you create yourself
// do this on the Swing event thread
SwingUtilities.invokeLater(() -> {
SierpPanel sierpPanel = new SierpPanel(sierpImg); // pass in image
JFrame frame = new JFrame("Siep Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(sierpPanel);
frame.pack(); // size it to the size of the JPanel
frame.setLocationRelativeTo(null); // center it
frame.setVisible(true);
});
}
public static Point midpoint(Point a, Point b) {
return new Point((Math.round(a.x + b.x) / 2), (Math.round(a.y + b.y) / 2));
}
}
class SierpPanel extends JPanel {
private BufferedImage img = null;
public SierpPanel(BufferedImage img) {
this.img = img;
}
// so that JPanel sizes itself with the image
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
}
Note that if you want to get fancy and draw the triangle as it's being created, and with a delay, then consider using either a Swing Timer or a SwingWorker.
I have tried to save the JFrame as an image using the following approach.
try
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
this.paint(image.getGraphics());
ImageIO.write(image,"png", new File("Test.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception unable to write image");
}
I am trying to save a screenshot as follows:
I would like to have even the title in my screenshot
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DividedSquare {
public static void main(String[] args) {
new DividedSquare();
}
public DividedSquare() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private TriangleShape baseTriangle;
private Color[] colors;
public TestPane() {
colors = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA};
}
#Override
public void invalidate() {
super.invalidate();
baseTriangle = new TriangleShape(
new Point(0, 0),
new Point(getWidth(), 0),
new Point(getWidth() / 2, getHeight() / 2));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text[] = new String[]{
"123.123",
"456.789",
"012.315",
"678.921"
};
FontMetrics fm = g2d.getFontMetrics();
double angel = 0;
for (int index = 0; index < 4; index++) {
g2d.setColor(colors[index]);
Path2D rotated = rotate(baseTriangle, angel);
g2d.fill(rotated);
Rectangle bounds = rotated.getBounds();
int x = bounds.x + ((bounds.width - fm.stringWidth(text[0])) / 2);
int y = bounds.y + (((bounds.height - fm.getHeight()) / 2) + fm.getAscent());
g2d.setColor(Color.WHITE);
g2d.drawString(text[index], x, y);
angel += 90;
}
g2d.setColor(Color.BLACK);
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.drawLine(getWidth(), 0, 0, getHeight());
g2d.dispose();
try
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
frame.paint(image.getGraphics());
ImageIO.write(image,"png", new File("Practice.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception to write image");
}
}
public Path2D rotate(TriangleShape shape, double angel) {
Rectangle bounds = shape.getBounds();
int x = bounds.width / 2;
int y = bounds.width / 2;
return new Path2D.Float(shape, AffineTransform.getRotateInstance(
Math.toRadians(angel),
x,
y));
}
}
public class TriangleShape extends Path2D.Double {
public TriangleShape(Point2D... points) {
moveTo(points[0].getX(), points[0].getY());
lineTo(points[1].getX(), points[1].getY());
lineTo(points[2].getX(), points[2].getY());
closePath();
}
}
}
But I the image does not get created. I am unable to understand why.
I looked at this but am unable to understand how to incorporate it in my case.
Edit
Based on comments, I tried using robot class but am unable to know where to call this function from. If I call this function from the paint() method, I am unable to get the colors and text.
void screenshot()
{
try
{
Robot robot = new Robot();
// Capture the screen shot of the area of the screen defined by the rectangle
Point p = frame.getLocationOnScreen();
System.out.print("point" + p);
BufferedImage bi=robot.createScreenCapture(new Rectangle((int)p.getX(),(int)p.getY(),frame.getWidth(),frame.getHeight()));
ImageIO.write(bi, "png", new File("imageTest.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception to write image");
}
}
There are at least two ways you might achieve this...
You Could...
Use Robot to capture a screen shot. For example
The problem with this is it takes a little effort to target the component you want to capture. It also only captures a rectangular area, so if the component is transparent, Robot won't respect this...
You Could...
Use printAll to render the component to your own Graphics context, typically from a BufferedImage
printAll allows you to print a component, because the intention is not to print this to the screen, printAll disables double buffering, making it more efficient to use when you don't want to render the component to the screen, such printing it to a printer...
Forexample
You can use Robot to capture screenshot. But it not gives Jframe Screenshot. We need to give correct coordinates and refer the frame. gFrame is my frame name and below code works for only Jframe area screenshot.
try {
Robot cap=new Robot();
Rectangle rec=new Rectangle(gFrame.getX(),gFrame.getY(),gFrame.getWidth(),gFrame.getHeight());
BufferedImage screenshot=cap.createScreenCapture(rec);
ImageIO.write(screenshot, "JPG",
new File("C:\\Users\\ruwan\\Downloads\\screenshot.jpg");
} catch (Exception e) {
e.printStackTrace();
}
I have a jLabel with an Icon that I should print. However, I can't get the jLabel's icon to full size.
Here's some of the code that I think that it is affecting the print size.
public static void printComponentToFile(Component comp, boolean fill) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72); //here
paper.setImageableArea(18, 18, 100, 300); //and here
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()),
(int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
ComponentPrinter cp = new ComponentPrinter(comp, fill);
try {
cp.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", new File("Page-" + (fill ? "Filled" : "") + ".png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class ComponentPrinter implements Printable {
private Component comp;
private boolean fill;
public ComponentPrinter(Component comp, boolean fill) {
this.comp = comp;
this.fill = fill;
}
#Override
public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {
if (page_index > 0) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) g;
g2.translate(format.getImageableX(), format.getImageableY());
double width = (int) Math.floor(format.getImageableWidth()); // here too
double height = (int) Math.floor(format.getImageableHeight()); // and here
if (!fill) {
width = Math.min(width, comp.getPreferredSize().width); // here
height = Math.min(height, comp.getPreferredSize().height); // here
}
comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
if (comp.getParent() == null) {
comp.addNotify();
}
comp.validate();
comp.doLayout();
comp.printAll(g2);
if (comp.getParent() != null) {
comp.removeNotify();
}
return Printable.PAGE_EXISTS;
}
}
So what should I change with those? Also, how can I put a radiobutton on the printing process? It's because I want to print the radiobutton altogether with the label.
This is how I print a label using a button:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
printComponent(jLabel2, false);
} catch (PrinterException ex) {
Logger.getLogger(MappingScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
Can I make it like this?:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
printComponent(jLabel2, false);
printComponent(jRadioBtn1, false); //change
} catch (PrinterException ex) {
Logger.getLogger(M.class.getName()).log(Level.SEVERE, null, ex);
}
}
UPDATE:
I think I have to add something here to print another component:
public static void main(String args[]) {
try {
JLabel label = new JLabel(
"This is a test",
new ImageIcon("/adv/mapp.jpg"),
JLabel.CENTER);
printComponentToFile(label, true);
printComponentToFile(label, false);
} catch (PrinterException exp) {
exp.printStackTrace();
}
Please help. Thanks
So, based on the concept presented in Printing a JFrame and its components, I've been able to produce these two examples...
Which used the following JPanel as the base component...
public static class PrintForm extends JPanel {
public PrintForm() {
setLayout(new GridBagLayout());
JLabel label = new JLabel("This is a label");
label.setVerticalTextPosition(JLabel.BOTTOM);
label.setHorizontalTextPosition(JLabel.CENTER);
try {
label.setIcon(new ImageIcon(ImageIO.read(new File("C:\\hold\\thumbnails\\_cg_1009___Afraid___by_Serena_Clearwater.png"))));
} catch (IOException ex) {
ex.printStackTrace();
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
add(label, gbc);
JRadioButton rb = new JRadioButton("Open to suggestions");
rb.setSelected(true);
gbc.gridy++;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.NONE;
add(rb, gbc);
}
}
And based on the concept presented in Fit/Scale JComponent to page being printed I was able to take an image of 7680x4800 and scale it down to print within an area of 842x598.
Now note. JLabel DOES NOT support scaling. If your image does not fit within the available space, you are going to have to scale it yourself some how. The following solution scales the entire component, having said that, with a little bit of clever re-arranging, it would be possible to make the TestPane scale it's image instead and use the above example instead...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScalablePrintingTest {
public static void main(String[] args) {
new ScalablePrintingTest();
}
public ScalablePrintingTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final TestPane imagePane = new TestPane();
JButton print = new JButton("Print");
print.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
//printComponent(imagePane);
printComponentToFile(imagePane);
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(imagePane);
frame.add(print, BorderLayout.SOUTH);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage bg;
public TestPane() {
try {
bg = ImageIO.read(new File("/path/to/a/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (bg != null) {
int x = (getWidth() - bg.getWidth()) / 2;
int y = (getHeight() - bg.getHeight()) / 2;
g2d.drawImage(bg, x, y, this);
}
g2d.dispose();
}
}
public void printComponent(Component comp) {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
pj.setPrintable(new ComponentPrintable(comp));
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
System.out.println(ex);
}
}
public static void printComponentToFile(Component comp) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72);
paper.setImageableArea(18, 18, 559, 783);
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()),
(int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
ComponentPrintable cp = new ComponentPrintable(comp);
try {
cp.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", new File("Page-Scaled.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class ComponentPrintable implements Printable {
private Component comp;
private ComponentPrintable(Component comp) {
this.comp = comp;
}
#Override
public int print(Graphics g, PageFormat pf, int pageNumber)
throws PrinterException {
// TODO Auto-generated method stub
if (pageNumber > 0) {
return Printable.NO_SUCH_PAGE;
}
// Get the preferred size ofthe component...
Dimension compSize = comp.getPreferredSize();
// Make sure we size to the preferred size
comp.setSize(compSize);
// Get the the print size
Dimension printSize = new Dimension();
printSize.setSize(pf.getImageableWidth(), pf.getImageableHeight());
// Calculate the scale factor
double scaleFactor = getScaleFactorToFit(compSize, printSize);
// Don't want to scale up, only want to scale down
if (scaleFactor > 1d) {
scaleFactor = 1d;
}
// Calcaulte the scaled size...
double scaleWidth = compSize.width * scaleFactor;
double scaleHeight = compSize.height * scaleFactor;
// Create a clone of the graphics context. This allows us to manipulate
// the graphics context without begin worried about what effects
// it might have once we're finished
Graphics2D g2 = (Graphics2D) g.create();
// Calculate the x/y position of the component, this will center
// the result on the page if it can
double x = ((pf.getImageableWidth() - scaleWidth) / 2d) + pf.getImageableX();
double y = ((pf.getImageableHeight() - scaleHeight) / 2d) + pf.getImageableY();
// Create a new AffineTransformation
AffineTransform at = new AffineTransform();
// Translate the offset to out "center" of page
at.translate(x, y);
// Set the scaling
at.scale(scaleFactor, scaleFactor);
// Apply the transformation
g2.transform(at);
// Print the component
comp.printAll(g2);
// Dispose of the graphics context, freeing up memory and discarding
// our changes
g2.dispose();
comp.revalidate();
return Printable.PAGE_EXISTS;
}
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
if (iMasterSize > iTargetSize) {
dScale = (double) iTargetSize / (double) iMasterSize;
} else {
dScale = (double) iTargetSize / (double) iMasterSize;
}
return dScale;
}
}
I was going to update my previous answer, but it's been accepted...
This example basically combines the solutions presented in Fit/Scale JComponent to page being printed and Printing a JFrame and its components and demonstrates the difference between scaling the component when it's printed as apposed to have the component capable of scaling itself...
It creates a interface chain of the Printables, which I hope will help clear up any confusion...well, less then there was...
So starting with...
The panel on the left is static, that is, the image is not scaled by the component. The panel on the right is dynamic, that is, the component will scale the image as the size of the component is changed.
The static panel when printed using the scaled approach. You will note that both the label and radio button have been scaled as well
Compared to the dynamic panel when using the filled approach. You will note that the label and radio button are not scaled, but remain at there normal size, but the background image is scaled instead...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PrintComponentTest {
public static void main(String[] args) {
new PrintComponentTest();
}
public PrintComponentTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private StaticImagePane staticImagePane;
private DynamicImagePane dynamicImagePane;
public TestPane() {
JPanel content = new JPanel(new GridLayout());
content.add(new JScrollPane(preparePane(staticImagePane = new StaticImagePane())));
content.add(preparePane(dynamicImagePane = new DynamicImagePane()));
setLayout(new BorderLayout());
add(content);
JPanel options = new JPanel();
JButton normal = new JButton("Print");
normal.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
printComponentToFile(new FillableCompentPrintable(staticImagePane, false), new File("Static-Normal.png"));
printComponentToFile(new FillableCompentPrintable(staticImagePane, true), new File("Static-Filled.png"));
printComponentToFile(new ScalableCompentPrintable(staticImagePane), new File("Static-Scaled.png"));
printComponentToFile(new FillableCompentPrintable(dynamicImagePane, false), new File("Dynamic-Normal.png"));
printComponentToFile(new FillableCompentPrintable(dynamicImagePane, true), new File("Dynamic-Filled.png"));
printComponentToFile(new ScalableCompentPrintable(dynamicImagePane), new File("Dynamic-Scaled.png"));
staticImagePane.invalidate();
dynamicImagePane.invalidate();
staticImagePane.revalidate();
dynamicImagePane.revalidate();
invalidate();
revalidate();
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
});
options.add(normal);
add(options, BorderLayout.SOUTH);
}
protected JPanel preparePane(JPanel panel) {
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
JLabel label = new JLabel("This is some text on a label");
label.setForeground(Color.WHITE);
panel.add(label, gbc);
JRadioButton btn = new JRadioButton("Do you agree", true);
btn.setOpaque(false);
btn.setForeground(Color.WHITE);
panel.add(btn, gbc);
return panel;
}
}
public void printComponent(ComponentPrintable printable) {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
pj.setPrintable(printable);
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
System.out.println(ex);
}
}
public static void printComponentToFile(ComponentPrintable printable, File file) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72);
paper.setImageableArea(18, 18, 559, 783);
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()),
(int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
try {
printable.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static interface ComponentPrintable extends Printable {
public Component getComponent();
}
public abstract static class AbstractComponentPrintable implements ComponentPrintable {
private final Component component;
public AbstractComponentPrintable(Component component) {
this.component = component;
}
#Override
public Component getComponent() {
return component;
}
protected void beforePrinting(Component comp) {
if (comp.getParent() == null) {
comp.addNotify();
}
comp.invalidate();
comp.revalidate();
comp.doLayout();
}
protected void afterPrinting(Component comp) {
if (comp.getParent() != null) {
comp.removeNotify();
} else {
comp.invalidate();
comp.revalidate();
}
}
#Override
public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {
if (page_index > 0) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) g;
printComponent(g2, format, getComponent());
return Printable.PAGE_EXISTS;
}
protected abstract void printComponent(Graphics2D g, PageFormat pf, Component comp);
}
public static class FillableCompentPrintable extends AbstractComponentPrintable {
private boolean fill;
public FillableCompentPrintable(Component component, boolean fill) {
super(component);
this.fill = fill;
}
public boolean isFill() {
return fill;
}
#Override
protected void printComponent(Graphics2D g2, PageFormat pf, Component comp) {
g2.translate(pf.getImageableX(), pf.getImageableY());
double width = (int) Math.floor(pf.getImageableWidth());
double height = (int) Math.floor(pf.getImageableHeight());
if (!isFill()) {
width = Math.min(width, comp.getPreferredSize().width);
height = Math.min(height, comp.getPreferredSize().height);
}
comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
beforePrinting(comp);
comp.printAll(g2);
afterPrinting(comp);
// Debug purposes only...
g2.translate(-pf.getImageableX(), -pf.getImageableY());
g2.setColor(Color.RED);
g2.drawRect(0, 0, (int) pf.getWidth() - 1, (int) pf.getHeight() - 1);
}
}
public static class ScalableCompentPrintable extends AbstractComponentPrintable {
public ScalableCompentPrintable(Component component) {
super(component);
}
#Override
protected void printComponent(Graphics2D g2d, PageFormat pf, Component comp) {
// Get the preferred size ofthe component...
Dimension compSize = comp.getPreferredSize();
// Make sure we size to the preferred size
comp.setSize(compSize);
// Get the the print size
Dimension printSize = new Dimension();
printSize.setSize(pf.getImageableWidth(), pf.getImageableHeight());
// Calculate the scale factor
double scaleFactor = getScaleFactorToFit(compSize, printSize);
// Don't want to scale up, only want to scale down
if (scaleFactor > 1d) {
scaleFactor = 1d;
}
// Calcaulte the scaled size...
double scaleWidth = compSize.width * scaleFactor;
double scaleHeight = compSize.height * scaleFactor;
// Create a clone of the graphics context. This allows us to manipulate
// the graphics context without begin worried about what effects
// it might have once we're finished
Graphics2D g2 = (Graphics2D) g2d.create();
// Calculate the x/y position of the component, this will center
// the result on the page if it can
double x = ((pf.getImageableWidth() - scaleWidth) / 2d) + pf.getImageableX();
double y = ((pf.getImageableHeight() - scaleHeight) / 2d) + pf.getImageableY();
// Create a new AffineTransformation
AffineTransform at = new AffineTransform();
// Translate the offset to out "center" of page
at.translate(x, y);
// Set the scaling
at.scale(scaleFactor, scaleFactor);
// Apply the transformation
g2.transform(at);
// Print the component
beforePrinting(comp);
comp.printAll(g2);
afterPrinting(comp);
// Dispose of the graphics context, freeing up memory and discarding
// our changes
g2.dispose();
// Debug purposes only...
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, (int) pf.getWidth() - 1, (int) pf.getHeight() - 1);
}
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;
}
}
public class StaticImagePane extends JPanel {
private BufferedImage image;
public StaticImagePane() {
try {
setImage(ImageIO.read(new File("path\to\a\image")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
repaint();
}
#Override
public Dimension getPreferredSize() {
BufferedImage bg = getImage();
return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
paintBackground(g2d);
g2d.dispose();
}
protected void paintBackground(Graphics2D g2d) {
paintBackground(g2d, getImage());
}
protected void paintBackground(Graphics2D g2d, Image bg) {
if (bg != null) {
int x = (getWidth() - bg.getWidth(this)) / 2;
int y = (getHeight() - bg.getHeight(this)) / 2;
g2d.drawImage(bg, x, y, this);
}
}
}
public class DynamicImagePane extends StaticImagePane {
private Image scaled;
public DynamicImagePane() {
try {
setImage(ImageIO.read(new File("path\to\a\image")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public void invalidate() {
super.invalidate();
if (getImage() != null) {
int width = getWidth();
int height = getHeight();
if (width > 0 && height > 0) {
// Keep the aspect ratio
if (width > height) {
width = -1;
} else if (height > width) {
height = -1;
}
scaled = getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
}
}
}
public Image getScaledImage() {
return scaled;
}
#Override
protected void paintBackground(Graphics2D g2d) {
paintBackground(g2d, getScaledImage());
}
}
}
Note, this is just an example, there is plenty of work that needs to be done.
One issue is with the scaling, see The Perils of Image.getScaledInstance() for details and Quality of Image after resize very low -- Java for a better approach...
To make it work, I changed it to something like this:
//OLD:
public void printComponent(Component comp) {
//NEW:
public void printComponent(JComponent comp, boolean fill) throws PrinterException {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setJobName(" Print Component ");
pj.setPrintable(new ComponentPrintable(comp));
if (!pj.printDialog()) {
return;
}
try {
pj.print();
} catch (PrinterException ex) {
System.out.println(ex);
}
}
I am printing various elements such as text and images using the Panels and components it is generating pages for printing and print is also coming but the hard print also has the print button on physical paper. I to remove the print button from the page. here is the code
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.print.*;
public class Printing extends JFrame
implements ActionListener {
public static void main(String[] args)
{
// intialise
}
public Printing(String Firstname,String LastName,String contactid)
{
super("Print badge");
WindowUtilities.setNativeLookAndFeel();
addWindowListener(new ExitListener());
Container content = getContentPane();
JButton printButton = new JButton("Print");
printButton.addActionListener(this);
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(Color.BLACK);
buttonPanel.add(printButton);
content.add(buttonPanel, BorderLayout.SOUTH);
DrawingPanel drawingPanel = new DrawingPanel(Firstname,LastName,contactid);
content.add(drawingPanel, BorderLayout.CENTER);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent event)
{
//call for printing
}
}
and code for actual printing panel
public class DrawingPanel extends JPanel
{
private int fontSize1 = 32;
private Image img1=null;
public DrawingPanel(String n1,String n2,String n3)
{
String path="D:"+"\\25175.jpg";
setBackground(Color.white);
Font font = new Font("Serif", Font.PLAIN, 32);
setFont(font);
img1=new ImageIcon(path).getImage();
setPreferredSize(new Dimension(400, 400));
}
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
g2d.translate(x, y);
g2d.setPaint(Color.lightGray);
AffineTransform origTransform = g2d.getTransform();
g2d.shear(-0.95, 0);
g2d.scale(1, 3);
g2d.setTransform(origTransform);
g2d.setPaint(Color.BLUE);
g2d.drawString(string,25 , 50);
g2d.drawString(string, 125,100);
g.drawImage(img1, 280, 190, null);
}
}
The print method setup is here
import java.awt.*;
import javax.swing.*;
import java.awt.print.*;
public class PrintUtilities implements Printable {
private Component componentToBePrinted;
public static void printComponent(Component c) {
new PrintUtilities(c).print();
}
public PrintUtilities(Component componentToBePrinted) {
this.componentToBePrinted = componentToBePrinted;
}
public void print() {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(this);
if (printJob.printDialog())
try {
printJob.print();
} catch(PrinterException e) {
System.out.println("Error printing: " + e);
}
}
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
if (pageIndex > 0) {
return(NO_SUCH_PAGE);
} else {
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
disableDoubleBuffering(componentToBePrinted);
componentToBePrinted.paint(g2d);
enableDoubleBuffering(componentToBePrinted);
return(PAGE_EXISTS);
}
}
public static void disableDoubleBuffering(Component c) {
RepaintManager currentManager = RepaintManager.currentManager(c);
currentManager.setDoubleBufferingEnabled(false);
}
public static void enableDoubleBuffering(Component c) {
RepaintManager currentManager = RepaintManager.currentManager(c);
currentManager.setDoubleBufferingEnabled(true);
}
}
by this call PrintUtilities.printComponent(this) in button action listener
This would seem to be your problem.
This will, technically, print the contents of the entire frame, you only need to print the DrawingPanel.
This is going to require you to make some minor changes to your code so you access the instance of the DrawingPanel from your actionPerformed method...
private DrawingPanel drawingPanel;
public Printing(String Firstname,String LastName,String contactid)
{
super("Print badge");
//...
drawingPanel = new DrawingPanel(Firstname,LastName,contactid);
//...
}
This should no allow you to do something like...
PrintUtilities.printComponent(drawingPanel);
Instead...
You can
define custom clip for the print Graphics to exclude the print button area
OR 2. just hide the button
OR 3. override the button's paintComponent() method where check isPrint flag (if it's false call super it true do nothing).