How to draw smooth dot in Java? [duplicate] - java

We know that there are a class named RadialGradientPaint in Java and we can use it to have a gradient painting for circle.
But I want to have an oval (ellipse) GradientPaint. How to implement oval GradientPaint?

Use an AffineTransform when drawing the RadialGradientPaint. This would require a scale instance of the transform. It might end up looking something like this:
import java.awt.*;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class OvalGradientPaint {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
JPanel gui = new JPanel(new BorderLayout());
gui.setBorder(new EmptyBorder(2, 3, 2, 3));
gui.add(new OvalGradientPaintSurface());
gui.setBackground(Color.WHITE);
JFrame f = new JFrame("Oval Gradient Paint");
f.add(gui);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
class OvalGradientPaintSurface extends JPanel {
public int yScale = 150;
public int increment = 1;
RadialGradientPaint paint;
AffineTransform moveToOrigin;
OvalGradientPaintSurface() {
Point2D center = new Point2D.Float(100, 100);
float radius = 90;
float[] dist = {0.05f, .95f};
Color[] colors = {Color.RED, Color.MAGENTA.darker()};
paint = new RadialGradientPaint(center, radius, dist, colors,CycleMethod.REFLECT);
moveToOrigin = AffineTransform.
getTranslateInstance(-100d, -100d);
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if (increment < 0) {
increment = (yScale < 50 ? -increment : increment);
} else {
increment = (yScale > 150 ? -increment : increment);
}
yScale += increment;
repaint();
}
};
Timer t = new Timer(15, listener);
t.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
AffineTransform moveToCenter = AffineTransform.
getTranslateInstance(getWidth()/2d, getHeight()/2d);
g2.setPaint(paint);
double y = yScale/100d;
double x = 1/y;
AffineTransform at = AffineTransform.getScaleInstance(x, y);
// We need to move it to the origin, scale, and move back.
// Counterintutitively perhaps, we concatentate 'in reverse'.
moveToCenter.concatenate(at);
moveToCenter.concatenate(moveToOrigin);
g2.setTransform(moveToCenter);
// fudge factor of 3 here, to ensure the scaling of the transform
// does not leave edges unpainted.
g2.fillRect(-getWidth(), -getHeight(), getWidth()*3, getHeight()*3);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
}
Original image: The original static (boring) 'screen shot' of the app.

RadialGradientPaint provides two ways to paint itself as an ellipse instead of a circle:
Upon construction, you can specify a transform for the gradient. For example, if you provide the following transform: AffineTransform.getScaleInstance(0.5, 1), your gradient will be an upright oval (the x dimension will be half that of the y dimension).
Or, you can use the constructor that requires a Rectangle2D be provided. An appropriate transform will be created to make the gradient ellipse bounds match that of the provided rectangle. I found the class documentation helpful: RadialGradientPaint API. In particular, see the documentation for this constructor.

Related

java decrease time between mouseMotionListener intervals

I want to create a simple drawing programm in java which currently only draws a line using Graphics.fillOval() and a mouseMotionListener(). The problem is, that if you move the mouse quickly the line gets less precise and the ovals (circles in this case) spread apart.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Drawing
{
private JFrame window;
private Graphics g;
public Drawing()
{
window=new JFrame();
window.setTitle("Paint_window");
window.setSize(1000,700);
window.setVisible(true);
window.setDefaultCloseOperation(window.EXIT_ON_CLOSE);
g=window.getGraphics();
window.addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged(MouseEvent e)
{
if(SwingUtilities.isLeftMouseButton(e)
{
g.fillOval((int)e.getX(),(int)e.getY(),10,10);
}
}
});
}
}
Is there a way of improving this or a better way to this?
g=window.getGraphics();
First of all you should not be using getGraphics() of a component. Any painting you do will only be temporary and will be erased the first time Swing determines the component needs to be repainted. In you above example just try resizing the frame to see this.
The proper way to do custom painting is to override the paintComponent(...) method of a JPanel and add the panel to the frame. See Custom Painting for more information.
The problem is, that if you move the mouse quickly the line gets less precise and the ovals (circles in this case) spread apart
You will not be able to have an event generated for every pixel the mouse moves.
Instead you need to be able to "draw a line" between consecutive points generated as you drag the mouse.
So you need to store each point in an ArrayList and in the custom painting code iterate through all the points and draw a line.
A basic example to get you started:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
class DrawingPanel extends JPanel
{
private ArrayList<ArrayList<Point>> previous = new ArrayList<ArrayList<Point>>();
private ArrayList<Point> current = new ArrayList<Point>();
private BasicStroke basicStroke;
public DrawingPanel(int strokeSize)
{
basicStroke = new BasicStroke(strokeSize, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
MouseAdapter ma = new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
current.add( new Point(e.getX(), e.getY()) );
}
#Override
public void mouseDragged(MouseEvent e)
{
current.add( new Point(e.getX(), e.getY()) );
repaint();
}
#Override
public void mouseReleased(MouseEvent e)
{
if (current.size() > 1)
{
previous.add( current );
}
current = new ArrayList<Point>();
}
};
addMouseMotionListener( ma );
addMouseListener( ma );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke( basicStroke );
// Paint lines from previous drags
for (int i = 0; i < previous.size(); i++)
{
drawLines(g, previous.get(i));
}
// Paint line from current drag
drawLines(g, current);
}
private void drawLines(Graphics g, ArrayList<Point> points)
{
for (int i = 0; i < points.size() - 1; i++)
{
int x = (int) points.get(i).getX();
int y = (int) points.get(i).getY();
int x2 = (int) points.get(i + 1).getX();
int y2 = (int) points.get(i + 1).getY();
g.drawLine(x, y, x2, y2);
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel(15));
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
Using the above approach you will redraw the lines every time the component is repainted.
Another approach is to draw to a BufferedImage and then paint the BufferedImage on the panel. You can check out Custom Painting Approaches for an example of this approach.

Java Rotate Image Towards Point from any X/Y position on screen

I have a ship object that I want to be able to rotate towards any certain point I click on the screen (See pic of ship and sqaures as points). I can get the ship to face the general direction, but it has this strange behavior of as it rotates the ship itself; the image moves around an circular axis, instead of rotating from the center point of the image itself.
Can someone please, give me the formula to get the angle from the center xy point of image to the destination sqaure(mouse click)?
First you have to find the difference on the x axis and the difference on the y axis. Since you seem to say that your ship is centered, you only have to get the (x,y) coordinates of the click. To find the angle, you must know that sin(your angle) = y/sqrt(y^2 + x^2), therefore, your angle = sin^-1(y/sqrt(y^2 + x^2)). It is basic maths, but it's always good to refresh basic knowledge, as it can cause quite the headache when debugging if you made a small mistake there, so I suggest you check out this page:
https://www.mathsisfun.com/algebra/trig-finding-angle-right-triangle.html
but it has this strange behavior of as it rotates the ship itself; the image moves around an circular axis, instead of rotating from the center point of the image itself.
You need to rotate the image about its center point, which means you need to translate the Graphics object to the center of your image before you paint the image.
This example rotates about a fixed point:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation2 extends JPanel
{
BufferedImage image;
int degrees;
int point = 250;
public Rotation2(BufferedImage image)
{
this.image = image;
setDegrees( 0 );
setPreferredSize( new Dimension(600, 600) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
double radians = Math.toRadians( degrees );
g2.translate(point, point);
g2.rotate(radians);
g2.translate(-image.getWidth(this) / 2, -image.getHeight(this) / 2);
g2.drawImage(image, 0, 0, null);
g2.dispose();
g.setColor(Color.RED);
g.fillOval(point - 5, point - 5, 10, 10);
}
public void setDegrees(int degrees)
{
this.degrees = degrees;
repaint();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "mong.jpg";
// String path = "dukewavered.gif";
ClassLoader cl = Rotation2.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
final Rotation2 r = new Rotation2(bi);
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
r.setDegrees( value );
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(r));
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}

How to draw a rectangle moving in a circle around the center of the canvas?

The code is meant to draw a rectangle, which moves in a circle around the center of the canvas one time. The code I currently have is
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.Timer;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Q3_Circular extends JComponent {
protected int degree = 0;
protected double xStart;
protected double yStart;
protected Timer timer;
public Q3_Circular() {
timer = new Timer(1000, new TimerCallback()); //creates new times that refreshes every 100 ms, and called the TimerCallback class
timer.start();
}
protected class TimerCallback implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (degree < (2 * Math.PI)){
xStart = getWidth()/2 * Math.cos(degree+1);
yStart = getHeight()/2 * Math.sin(degree+1);
degree+= 1;
repaint();
}
else {
degree += 0;
repaint();
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("AnimatedSquare");
Q3_Circular canvas = new Q3_Circular();
frame.add(canvas);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void paintComponent(Graphics g){
xStart = (double)(getWidth())/2.0 * Math.cos(degree);
yStart = (double)(getHeight())/2.0 * Math.sin(degree);
Graphics2D g2 = (Graphics2D) g;
g2.draw(new Rectangle2D.Double(xStart,yStart, 25,25));
repaint();
}
}
This code appears to draw the rectangle very quickly around the point (0,0). I'm not sure where the code is wrong.
Your code was confusing. Here's the GUI I created.
When creating a Swing GUI, use the model / view / controller pattern. Create a GUI model, and GUI view, and one or more controllers to modify the model and repaint the view.
Here are the changes I made to your code.
I created a DrawingRectangle class to hold the information about the drawing rectangle. This class is a plain old Java object with getters and setters. This class is the GUI model.
I moved everything out of the main method except for the call to the SwingUtilities invokeLater method. The invokeLater method puts the creation and use of the Swing components on the Event Dispatch thread. Oracle and I insist that all Swing applications start on the Event Dispatch thread.
I create the drawing rectangle in the constructor of the Q3_Circular class. Generally, you create the GUI model, then the GUI view.
I rearranged the JFrame code in the run method to be in the proper order. I removed the setSize method and replaced it with the pack method. We don't care how big the JFrame is. We care how big the drawing panel is.
I created a drawing panel from a JPanel. Here, we set the preferred size of the drawing panel. We extend a JPanel so we can override the paintComponent method.
The paintComponent method does nothing but paint the drawing rectangle. No calculations or anything but painting is done in the paintComponent method. I added a call to the super paintComponent method to maintain the Swing paint chain and clear the drawing panel before I paint the drawing rectangle. I draw the rectangle using the x and y coordinates as the center of the rectangle, rather than the upper left corner. This is the one transformation I do in the drawing code.
I created a drawing animation from a Runnable. You can use a Swing Timer if you want. I find it easier to create my own animation code. This is the GUI controller. Here is where we do the calculations, update the model, and repaint the drawing panel. In the repaint method, I use the SwingUtilities invokeLater method to do the painting on the Event Dispatch thread. I do this because the animation thread is a separate thread.
Here's the code. I put all the classes together so I could paste the code easier. You should separate the classes into different files.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Q3_Circular implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Q3_Circular());
}
private static final int DRAWING_WIDTH = 300;
private static final int DRAWING_HEIGHT = DRAWING_WIDTH;
private DrawingRectangle drawingRectangle;
public Q3_Circular() {
int center = DRAWING_WIDTH / 2;
Rectangle2D rectangle = new Rectangle2D.Double(center, center, 32D, 32D);
drawingRectangle = new DrawingRectangle(Color.RED, rectangle);
}
#Override
public void run() {
JFrame frame = new JFrame("Animated Square");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = new DrawingPanel(DRAWING_WIDTH,
DRAWING_HEIGHT, drawingRectangle);
frame.add(drawingPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
new Thread(new DrawingAnimation(drawingPanel, drawingRectangle))
.start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 8226587438110549806L;
private DrawingRectangle drawingRectangle;
public DrawingPanel(int width, int height,
DrawingRectangle drawingRectangle) {
this.setPreferredSize(new Dimension(width, height));
this.drawingRectangle = drawingRectangle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(drawingRectangle.getColor());
Rectangle2D rectangle = drawingRectangle.getRectangle();
int x = (int) Math.round(rectangle.getX());
int y = (int) Math.round(rectangle.getY());
int width = (int) Math.round(rectangle.getWidth());
int height = (int) Math.round(rectangle.getHeight());
g.fillRect(x - width / 2, y - height / 2, width, height);
}
}
public class DrawingAnimation implements Runnable {
private DrawingPanel drawingPanel;
private DrawingRectangle drawingRectangle;
public DrawingAnimation(DrawingPanel drawingPanel,
DrawingRectangle drawingRectangle) {
this.drawingPanel = drawingPanel;
this.drawingRectangle = drawingRectangle;
}
#Override
public void run() {
int xCenter = drawingPanel.getWidth() / 2;
int yCenter = drawingPanel.getHeight() / 2;
double radius = drawingPanel.getWidth() / 3;
for (int degree = 0; degree < 360; degree++) {
double radians = Math.toRadians((double) degree);
double x = radius * Math.cos(radians) + xCenter;
double y = radius * Math.sin(radians) + yCenter;
drawingRectangle.setRectangleOrigin(x, y);
repaint();
sleep(100L);
}
}
private void sleep(long interval) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
}
public class DrawingRectangle {
private final Color color;
private Rectangle2D rectangle;
public DrawingRectangle(Color color, Rectangle2D rectangle) {
this.color = color;
this.rectangle = rectangle;
}
public void setRectangleOrigin(double x, double y) {
rectangle
.setRect(x, y, rectangle.getWidth(), rectangle.getHeight());
}
public Color getColor() {
return color;
}
public Rectangle2D getRectangle() {
return rectangle;
}
}
}

Confusion with Graphics2d, canvas and shapes

I am learning the basics of java games programming and I am confused about a few things.
I know you use the "canvas" class to create a blank canvas and then use the paint method to create stuff.
But what does Graphics2D? I have seen people using the grahpics2d class to create a canvas for example
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLACK);
Now why did they use the grahpics2d and not the canvas?
Also I have seen people creating shapes like a rectangle by using:
Rectangle r = new Rectangle();
but some people have created them like:
Shape shape = new Rectangle2D.Double(value1,valu2,valu3,valu4);
What's the difference between these two?
Thanks in advance.
regards,
First, no I wouldn't use a Canvas object but rather a JPanel, and I'd draw in the paintComponent method override, not the paint method. Think of the JPanel as if it were a paint canvas and the Graphics or Graphics2D as if it were the brush that you were using to paint with. So in other words, you would need them both to create your drawing.
As for Rectangle vs. Rectangle2D, the 2D shapes are part of a newer addition to Graphics, when Graphics2D came about. These are based on the Shape interface, one that allows you a little more flexibility and OOPs to your drawing.
For greater detail, please have a look at:
Lesson: Performing Custom Painting
Trail: 2D Graphics
Painting in AWT and Swing
Edit
Re your questions:
Q: So you would use JPanel as my empty canvas and the Graphics2D g2d = (Graphics2D) g; create a brush kind of thing that you can use to change the JPanel. Hence this g2d.setColor(Color.BLACK); changes the background colour of our JPanel canvas. Is this right?
Yes. And you can even change the Graphics2D object's Stroke via
g2d.setStroke(new BasicStroke(...));
Q: Also can you explain to me what is "Shape" and what do you use it for?
Please look at the 2nd tutorial that I've linked to above as it will go into a fair bit of detail on what Shape represents and how to use it. It is in sum an interface used by all of the Xxxxx2D classes such as Rectangle2D and Ellipse2D. And it allows them all to share certain properties including being fillable, drawable, transormable, and more.
Edit 2
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.*;
#SuppressWarnings("serial")
public class RotateFoo extends JPanel {
private static final int PREF_WIDTH = 800;
private static final int PREF_HEIGHT = 600;
private static final Color STAR_COLOR = Color.red;
private static final int ROTATE_TIMER_DELAY = 20;
private static final int POINTS = 5;
private static final int RADIUS = 50;
private static final String TITLE = "Press \"r\" to rotate";
private static final float TITLE_POINTS = 52f;
private Path2D star = new Path2D.Double();
private Timer rotateTimer = new Timer(ROTATE_TIMER_DELAY, new RotateTimerListener());
public RotateFoo() {
double x = 0.0;
double y = 0.0;
double theta = 0.0;
for (int i = 0; i <= POINTS; i++) {
x = RADIUS + RADIUS * Math.cos(theta);
y = RADIUS + RADIUS * Math.sin(theta);
if (i == 0) {
star.moveTo(x, y);
} else {
star.lineTo(x, y);
}
theta += 4 * Math.PI / POINTS;
}
double tx = (getPreferredSize().getWidth() - star.getBounds().getWidth()) / 2;
double ty = (getPreferredSize().getHeight() - star.getBounds().getHeight()) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(tx, ty);
star.transform(at );
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
String rotateOn = "rotate on";
String rotateOff = "rotate off";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0, false), rotateOn);
actionMap.put(rotateOn, new AbstractAction() {
public void actionPerformed(ActionEvent arg0) {
if (rotateTimer != null && !rotateTimer.isRunning()) {
rotateTimer.start();
}
}
});
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0, true), rotateOff);
actionMap.put(rotateOff, new AbstractAction() {
public void actionPerformed(ActionEvent arg0) {
if (rotateTimer != null && rotateTimer.isRunning()) {
rotateTimer.stop();
}
}
});
//rotateTimer.start();
JLabel titleLabel = new JLabel(TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, TITLE_POINTS));
add(titleLabel);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(STAR_COLOR);
if (star != null) {
g2.draw(star);
}
}
private class RotateTimerListener implements ActionListener {
private static final double BASE_THETA = Math.PI / 90;
#Override
public void actionPerformed(ActionEvent e) {
double anchorx = getPreferredSize().getWidth() / 2;
double anchory = getPreferredSize().getHeight() / 2;
AffineTransform at = AffineTransform.getRotateInstance(BASE_THETA, anchorx, anchory);
star.transform(at);
repaint();
}
}
private static void createAndShowGui() {
RotateFoo mainPanel = new RotateFoo();
JFrame frame = new JFrame("RotateFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
you have to make a certain difference:
a Canvas (or maybe a Panel or a JPanel or a Frame) are Objects that represent an GUI-Object! such an object is required to capture Input Events, or maybe used to be layouted. it can be set active and disabled, all that stuff.
a Graphics Objects is that thing, that is inside of the canvas. it is responsible for the pure drawing! it can use special drawing features, having strokes and fonts and colors...
so - you have two different classes for different purpose! it took me a while to understand that...
excuse my puny english...

Paint a JPanel to a BufferedImage or Print it without rendering it to screen first

Picture this... A program GUI JFrame that is split in 2, EAST and WEST. The first JPanel is just a print preview screen. The EAST side of the JFrame is where the user can create a 1 2 or 3 size image. The user clicks the "Add" button and the defined image on the right goes to the panel on the left. So if the user clicks "Add" 3 times with different size images, then the panel uses FlowLayout to organize the added panel images added on the left.
When you run this code, you can see a sorta idea of what I want. Really what would be nice is to create all this off-screen and call it MainPanel. Then have printPreview extend MainPanel and scale it down for screen view. And have the Printable method paint the MainPanel into the print method which would be a correct size.
So my question...
-Can you copy or paint a JPanel before it is rendered on the screen?
-Is there a better way to do what I want, I FlowLayout solves what I want amazingly, so a JPanel seems to be the answer unless there is something I do not know of.
Ok now that that is pictured. I have built some code that is about as SSCCE as I can get.
Guys I have tried asking this question at New To Java forums and they just do not respond, I am not double posting on purpose, I completely rewrote this from scratch.
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.print.*;
import java.awt.event.*;
public class PrintGrid extends JFrame {
Paper paper = new Paper();
PrintGrid() {
super("Check out this grid panel");
setSize(672, 750);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(paper);
setVisible(true);
} // end PrintGrid constructor
// **************************
// ****** PAPER CLASS *******
// **************************
private class Paper extends JPanel {
final int PAPER_X = 672, PAPER_Y = 975, UNIT = 12, DPI = 72;
X1 x1a = new X1(), x1b = new X1(), x1c = new X1();
X2 x2a = new X2(), x2b = new X2(), x2c = new X2();
X3 x3a = new X3(), x3b = new X3(), x3c = new X3();
Paper() {
setPreferredSize(new Dimension(PAPER_X, PAPER_Y));
setBackground(Color.GRAY);
setLayout(new FlowLayout(FlowLayout.LEADING));
//Users will manually add different sizes to this sheet.
add(x1a);
add(x2a);
add(x3a);
add(x1b);
add(x1c);
add(x2b);
add(x3b);
}
// ******* Parent Class for GridUnits *******
abstract class GridUnit extends JPanel {
MouseListen ml = new MouseListen();
float alpha = 1.0f;
GridUnit() {
this.addMouseListener(ml);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(makeComposite(alpha));
g.setColor(Color.WHITE);
g.drawRect(0, 0, this.getWidth()-1, this.getHeight()-1);
g.setColor(Color.darkGray);
g.fillRect(15, 15, this.getWidth()-30, this.getHeight()-30);
} // end paintComponent.
private AlphaComposite makeComposite(float alpha) {
int type = AlphaComposite.SRC_OVER;
return(AlphaComposite.getInstance(type, alpha));
}
void click() {
setVisible(false);
}
void entered() {
alpha = 0.8f;
repaint();
}
void exited() {
alpha = 1.0f;
repaint();
}
class MouseListen extends MouseAdapter {
public void mouseEntered(MouseEvent event) {
entered();
}
public void mouseExited(MouseEvent event) {
exited();
}
public void mousePressed(MouseEvent event) {
click();
}
}
} // end GridUnit class
class X1 extends GridUnit {
X1() {
setPreferredSize(new Dimension(UNIT*13, UNIT*18));
}
} // end X1 Class
class X2 extends GridUnit {
X2() {
setPreferredSize(new Dimension(UNIT*26, UNIT*18));
}
} // end X1 Class
class X3 extends GridUnit {
X3() {
setPreferredSize(new Dimension(UNIT*39, UNIT*18));
}
} // end X1 Class
} // end Paper class.
public static void main(String[] args) {
new PrintGrid();
} // end main method.
} // end PrintGrid class.
It's quite trivial to paint any Java component to an offscreen image, from which you can do as you please, including copying a portion or scaled image to a final target.
Subclass JComponent and override void paintComponent(Graphics g). Paint to a BufferedImage, then copy the image to the target component. Off the top of my head, something like:
void paintComponent(Graphics g) {
BufferedImage img=new BufferedImage(getWidth(),getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D gph=(Graphics2D)img.getGraphics();
// paint to gph here
gph.dispose();
g.drawImage(img); // paints the contents of img to the component's graphics context.
}

Categories

Resources