TitledBorder in JPanel moves when translate() method is used - java

I have created a JPanel and add it on a JFrame. JPanel has TitledBorder, but when I use the method translate(), e.g.,
g2.translate(getWidth() / 2, getHeight() / 2);
the whole component, including the border is translated. The effect is presented on Figure 1.
The desired result is depicted on the figure below.
Code is pasted below.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
class GPanel extends JPanel {
private void doDrawing(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.translate(getWidth() / 2, getHeight() / 2);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
class Main extends JFrame {
public Main() {
}
public static void main(String[] args) {
Main ex = new Main();
ex.setSize(new Dimension(400, 400));
GPanel panel = new GPanel();
panel.setBorder(BorderFactory.createTitledBorder("Title"));
ex.add(panel);
ex.setLocationRelativeTo(null);
ex.setVisible(true);
}
}

You have invoked setBorder() on an instance of GPanel and then modified the graphics context's transform in the latter's implementation of paintComponent(). The border doesn't know about this, so the result shown is entirely expected. Instead, follow the parent JComponent implementation advice for setBorder(): "put the component in a JPanel and set the border on the JPanel." A related example is shown here.
In the variation below,
The enclosing bPanel now has the Border, and the enclosed gPanel can safely manipulate the graphics context.
Before translate(), the red dot is centered on the origin; after translate(), the blue dot is centered on the origin, but the origin has moved.
Don't use setPreferredSize() when you really mean to override getPreferredSize().
Don't extend JFrame needlessly.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
class GTest {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GPanel gPanel = new GPanel();
JPanel bPanel = new JPanel();
bPanel.setBorder(BorderFactory.createTitledBorder("Title"));
bPanel.add(gPanel);
f.add(bPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class GPanel extends JPanel {
private static final int N = 16;
private void doDrawing(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.red);
g.fillOval(-N, -N, 2 * N, 2 * N);
g2.translate(getWidth() / 2, getHeight() / 2);
g2.setPaint(Color.blue);
g.fillOval(-N, -N, 2 * N, 2 * N);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(256, 256);
}
}
}

You might need to restore the move made by executing g2.translate(x, y); with g2.translate(-x, -y);:
Graphics2D g2 = (Graphics2D) g;
double x = getWidth() / 2d;
double y = getHeight() / 2d;
g2.translate(x, y);
g2.setPaint(Color.BLUE);
g2.fill(s);
g2.translate(-x, -y);
Another common way is to use a new Graphics object which is a copy of GPanel's Graphics object:
Graphics#create(), Graphics#dispose()
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(getWidth() / 2, getHeight() / 2);
g2.setPaint(Color.BLUE);
g2.fill(s);
g2.dispose();
Main2.java
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
class GPanel extends JPanel {
private final Rectangle s = new Rectangle(0, 0, 16, 16);
private void doDrawing(Graphics g) {
g.setColor(Color.RED);
g.fillRect(s.x, s.y, s.width, s.height);
// Graphics2D g2 = (Graphics2D) g;
// double x = getWidth() / 2d;
// double y = getHeight() / 2d;
// g2.translate(x, y);
// g2.setPaint(Color.BLUE);
// g2.fill(s);
// g2.translate(-x, -y);
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(getWidth() / 2, getHeight() / 2);
g2.setPaint(Color.BLUE);
g2.fill(s);
g2.dispose();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
public class Main2 extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
GPanel panel = new GPanel();
panel.setBorder(BorderFactory.createTitledBorder("Title"));
JFrame ex = new JFrame();
ex.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
ex.getContentPane().add(panel);
ex.setSize(400, 400);
ex.setLocationRelativeTo(null);
ex.setVisible(true);
});
}
}

try this code:
private void doDrawing(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.translate(0, 0);
}

Related

Create light in JAVA using RadialGradientPaint

Im working on a simple game engine using java.
Im want to make some light in the game and I want to use RadialGradientPaint.
Here is my light class
package engine.graphics;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;
import engine.Main;
import engine.maths.Vector2f;
public class Light
{
private Vector2f pos;
private int radius;
public Light(Vector2f pos, int radius)
{
this.pos = pos;
this.radius = radius;
}
public void render(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
Point2D center = new Point2D.Float(pos.x, pos.y);
float[] dist = {0.9f, 1.0f};
Color[] color = {new Color(0.0f, 0.0f, 0.0f, 0.1f), new Color(0, 0, 0, 255)};
RadialGradientPaint p = new RadialGradientPaint(center, radius, dist, color);
g2d.setPaint(p);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .95f));
g2d.fillRect(0, 0, Main.WIDTH, Main.HEIGHT);
g2d.dispose();
}
}
The problem that i found is that i cant draw more than one light.
How can i modify my code to make more lights?
Thank you..
I propose you this :
package solamda;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
private static final Color transparency = new Color(0, 0, 0, 0);
private static final int WIDTH = 500;
private static final int HEIGHT = 500;
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setMinimumSize(new Dimension(WIDTH, HEIGHT));
f.setLayout(new BorderLayout());
f.add(new JLabel() {
#Override
public void paint(Graphics g) {
super.paint(g);
render(g);
}
});
f.pack();
f.setVisible(true);
}
public static void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Point[] lights = { new Point(WIDTH / 2, HEIGHT / 2), new Point(0,0),
new Point(WIDTH / 2+10, HEIGHT / 2), new Point(WIDTH / 2-10, HEIGHT / 2) };
for (Point center : lights) {
paintlight(g2d, center);
}
g2d.dispose();
}
private static void paintlight(Graphics2D g2d, Point center) {
float[] dist = { 0.2f, 1.0f };
Color[] color = { Color.white, transparency };
RadialGradientPaint p = new RadialGradientPaint(center, 10, dist, color);
g2d.setPaint(p);
g2d.fillRect(center.x - 20, center.y - 20, 40, 40);
}
}
You don need to fill whole rect just the part where the light is . So from your code i just extract a method where center is a parameter (call paintlight) then in your method render, i can draw as many ligh as i want ; i simply paint a white hallo arround this point and i keep the transparency in the pattern when i paint it

Write a text on JDeskopPane

I want to write a multiline text (3-4 lines is ok) on the bottom right corner of a JDesktopPane, how can I do this?
The text is not fixed, it can change every time i start the swing application but once the application is started it remains the same, I don't need to update from the application.
My first thought was to create an image, put it as background of the JDesktopPane and then write on it, but it doesn't seem a simple solution.
Thanks for the help.
Combining the examples seen here and here, the print() method in the variation below illustrates using FontMetrics to right justify multiple lines of text in the bottom, right corner of a JDesktopPane.
import java.awt.*;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
/** #see http://stackoverflow.com/a/45055215/230513 */
public class JDPTest extends JDesktopPane {
private MyFrame one = new MyFrame("One", 100, 100);
public JDPTest() {
this.setPreferredSize(new Dimension(640, 480));
this.add(one);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.lightGray);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(Color.BLACK);
g2d.setFont(new Font(Font.SERIF, Font.BOLD, 16));
print(g2d, 3, "Hello, world!");
print(g2d, 2, "This is a test.");
print(g2d, 1, "This is another test.");
print(g2d, 0, "This is still another test.");
}
private void print(Graphics2D g2d, int line, String s) {
FontMetrics fm = g2d.getFontMetrics();
int x = this.getWidth() - fm.stringWidth(s) - 5;
int y = this.getHeight() - fm.getDescent()
- line * (fm.getHeight() + fm.getLeading());
g2d.drawString(s, x, y);
}
private final class MyFrame extends JInternalFrame {
MyFrame(String name, int x, int y) {
super(name, true, true, true, true);
this.setSize(320, 240);
this.setLocation(x, y);
this.setVisible(true);
}
}
private void display() {
JFrame f = new JFrame("JDPTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new JDPTest().display();
}
});
}
}
Use this example class.
The background if set will be scaled.
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.swing.JDesktopPane;
public class MyDesktopPane extends JDesktopPane {
Image img;
public MyDesktopPane() {
super();
}
#Override
public void paintComponent(Graphics g) {
int width = this.getWidth();
int height = this.getHeight();
int infoWidth = 150;
int infoHeight = 100;
super.paintComponent(g);
// alpha
final Float alpha = new Float(0.9);
final Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(makeComposite(alpha.floatValue()));
// draw bacground image is set
if (img != null) {
g.drawImage(img, 0, 0, width, height, this);
}
//draw 3 line text in red reound rectangle
g.setColor(Color.RED);
g.fillRoundRect(width - infoWidth, height - infoHeight, infoWidth, infoHeight, 5, 5);
g.setColor(Color.BLACK);
g.drawString("Line 1", width - infoWidth + 5, height - infoHeight + 20);
g.drawString("Line 2", width - infoWidth + 5, height - infoHeight + 40);
g.drawString("Line 3", width - infoWidth + 5, height - infoHeight + 60);
}
public void setBackGroundImage(String path) {
try {
boolean file = new File(path).isFile();
if (file) {
img = javax.imageio.ImageIO.read(new FileInputStream(path));
}
} catch (IOException e) {
e.printStackTrace();
}
this.repaint();
}
private AlphaComposite makeComposite(final float alpha) {
final int type = AlphaComposite.SRC_OVER;
return (AlphaComposite.getInstance(type, alpha));
}
}

How to add imagepanel in jpanel inside Jframe?

I'm trying to add an imagepanel which extends JPanel to another JPanel. Which is not working well for me. The paint function of image panel don't get invoked inside Jpanel but works fine in JFrame. Any ideas or help will be appreciated.
import javax.swing.*;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
class ImagePanel extends JPanel
{
int g_h=10,g_w=10;
int width=50,height=50;
int cornerradius;
Image castle;
Dimension size;
protected int x1,y1;
Color c1=new Color(255, 0, 0);
Rectangle rec;
boolean b=false;
boolean imboo=false;
boolean roundb= false;
Graphics g= this.getGraphics();
protected int strokeSize = 1;
protected Color shadowColor = Color.BLACK;
boolean shadowed = false;
public ImagePanel()
{
//super();
setOpaque(false);
setLayout(null);
System.out.println("it executed");
}
public ImagePanel(int x, int y)
{
setSize(x, y);
}
public void setSize(int x,int y){
width=x;
height=y;
}
public int getheight(){
return height;
}
public int getwidth(){
return width;
}
public void setImagePanelBounds(
int x, int y, int width, int height){
x1=x;
y1=y;
this.width= width;
this.height= height;
System.out.println("6it executed");
}
public void setroundcorners(boolean b, int i){
roundb=b;
cornerradius=i;
System.out.println("5it executed");
}
public void setImage(String s){
imboo=true;
size = new Dimension();
castle = new ImageIcon(s).getImage();
size.width = castle.getWidth(null);
size.height = castle.getHeight(null);
setPreferredSize(size);
System.out.println("4it executed");
}
public void paint(Graphics gh){
System.out.println("it executed p");
{int x=this.getWidth();
int j=20,a=20;
Graphics2D g2= (Graphics2D)gh.create();
{
g2.setColor(Color.WHITE);
g2.setComposite(AlphaComposite.Src);
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setComposite(AlphaComposite.SrcAtop);
rec= new Rectangle(x1, y1, width, height);
//Start of If-else
if(roundb){
g2.setClip(new RoundRectangle2D.Float(
(int)rec.getX(),(int)rec.getY(),
(int)rec.getWidth(),(int)rec.getHeight(),
cornerradius, cornerradius));
System.out.println("it executed");
}
// End of If-Else
// Image condition Starts
if (imboo){
g2.drawImage(castle, (int)rec.getX(),
(int)rec.getY(), (int)rec.getWidth(),
(int)rec.getHeight(), null);
//g.drawImage(castle, (int)rec.getX(),(int)rec.getY(), null);
}
// Image condition Ends
g2.setColor(Color.BLUE);
}
}
}
public static void main(String[]args)
{
ImagePanel t1=new ImagePanel();
JPanel jp1= new JPanel();
jp1.add(t1);
jp1.setLayout(null);
jp1.setBounds(0, 0, 600, 600);
JFrame jf1= new JFrame("Testing");
t1.setImage("icons/1.png");
//t1.setImage("1.jpg");
t1.setLayout(null);
t1.setroundcorners(true, 10);
//t1.setShadow(true);
t1.add(new JLabel("niak"));
//t1.setShadowDimensions(18, 18, 305, 305, 12);
t1.setImagePanelBounds(20, 20, 100, 100);
// jf1.add(t1);
jf1.setSize(600, 600);
jf1.setDefaultCloseOperation(jf1.EXIT_ON_CLOSE);
jf1.setVisible(true);
//jf1.revalidate();
jf1.setLayout(null);
}
}
Let's start with...
Don't use getGraphics. This is not how to perform custom painting. getGraphics may return null and is, at best, a snapshot, which will be discard when the next paint cycle occurs.
JPanel already has getWidth, getHeight and setSize methods, you should never have a need to overridden them. Instead, you should override getPreferredSize and return a size hint back that the parent layout manager can use.
If you create a Graphics context, you should dispose of it. In your paint method, you use gh.create, this is consuming resources and under some systems, until the Graphics context is disposed, it may not actually paint anything.
Don't override paint, instead use paintComponent
DO NOT modify the clip rectangle. Seriously, this is going to cause you more issues then you can imagine.
Don't use null layout managers without EXTREMELY good reason.
JPanel has a setBounds method, while, under normal circumstances, you shouldn't need to use it, since you've thrown away the layout manager, you should use it.
Basically, you've discard all the inner workings of the JPanel that enable the paint system to know that it should actually paint your panel
Updated with example
As an example...
Instead of using the clip, I use a masking technique, and mask the shape I want over the source image. I also buffer the result, which should make it more memory conservative as well as render faster
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class ImagePaneExample {
public static void main(String[] args) {
new ImagePaneExample();
}
public ImagePaneExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
BufferedImage img = ImageIO.read(new File("C:\\hold\\thumbnails\\2005-09-29-3957.jpeg"));
ImagePane imgPane = new ImagePane();
imgPane.setImage(img);
imgPane.setRounded(true);
imgPane.setBorder(new EmptyBorder(20, 20, 20, 20));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(imgPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
}
public class ImagePane extends JPanel {
private BufferedImage img;
private BufferedImage renderImg;
private boolean rounded;
public ImagePane() {
}
public void setRounded(boolean value) {
if (value != rounded) {
rounded = value;
renderImg = null;
firePropertyChange("rounded", !rounded, rounded);
repaint();
}
}
public boolean isRounded() {
return rounded;
}
public void setImage(BufferedImage value) {
if (value != img) {
BufferedImage old = img;
img = value;
renderImg = null;
firePropertyChange("image", old, img);
repaint();
}
}
public BufferedImage getImage() {
return img;
}
#Override
public Dimension getPreferredSize() {
Dimension size = img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
Insets insets = getInsets();
size.width += (insets.left + insets.right);
size.height += (insets.top + insets.bottom);
return size;
}
protected void applyQualityRenderHints(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
}
protected BufferedImage getImageToRender() {
if (renderImg == null) {
BufferedImage source = getImage();
if (source != null) {
if (isRounded()) {
BufferedImage mask = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
applyQualityRenderHints(g2d);
g2d.setBackground(new Color(255, 255, 255, 0));
g2d.clearRect(0, 0, mask.getWidth(), mask.getHeight());
g2d.setBackground(new Color(255, 255, 255, 255));
g2d.fillRoundRect(0, 0, mask.getWidth(), mask.getHeight(), 40, 40);
g2d.dispose();
BufferedImage comp = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB);
g2d = comp.createGraphics();
applyQualityRenderHints(g2d);
g2d.setBackground(new Color(255, 255, 255, 0));
g2d.clearRect(0, 0, source.getWidth(), source.getHeight());
g2d.drawImage(source, 0, 0, this);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN));
g2d.drawImage(mask, 0, 0, this);
g2d.dispose();
renderImg = comp;
} else {
renderImg = source;
}
}
}
return renderImg;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage img = getImageToRender();
System.out.println(img);
if (img != null) {
Insets insets = getInsets();
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
int x = ((width - img.getWidth()) / 2);
int y = ((height - img.getHeight()) / 2);
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
}
I'd recommend some more reading through Creating a UI with Swing, in particular the section on layout managers, as well as Performing Custom Painting and Painting in AWT and Swing
All you have to do is to set the Layout of your panel jp1 to BorderLayout and add the image panel t1 to BorderLayout.CENTER, like this:
JPanel jp1= new JPanel(new BorderLayout());
jp1.add(t1, BorderLayout.CENTER);

Circles in circles fading out, creating a target

I want to create a graphics whereby circles are overlapped and their colour fades out, also the circles should have a white space in between each other, something similar to this:
Here is how far I've got:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
class Circles extends JPanel implements MouseListener {
public void mouseReleased(MouseEvent event) {
}
public void mousePressed(MouseEvent event) {
}
public void mouseClicked(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public Circles() {
addMouseListener(this);
}
public void paint(Graphics g) {
g.setColor(Color.white);
int w = getWidth();
int h = getHeight();
g.fillRect(0, 0, w, h);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < 20; i++) {
if (i % 2 == 0) {
Color c = new Color(255 - i * 10, 255 - i * 10, 255 - i * 10);
g2.setColor(c);
} else {
g2.setColor(Color.white);
}
g2.fillOval((5 * i), (5 * i), (w - 10) * i, (h - 10) * i);
}
}
public static void main(String[] args) {
Frame w = new Frame();
w.setVisible(true);
}
}
Frame:
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Frame extends JFrame {
Circles myPanel;
public static void main(String[] args) {
Frame w = new Frame();
w.setVisible(true);
}
public Frame() {
setTitle("In-class Test 1: Starting Code");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 220);
setLocation(300, 300);
myPanel = new Circles();
add(myPanel);
}
}
There are a number of ways to achieve this, but first, start by overriding paintComponent instead of paint.
Second, you will need some kind of loop that expand the radius of the circle on each iteration.
Thirdly, you will want a simple int value that acts as a alpha value, starting from 255 and decreases down to the faintest alpha level you want, perhaps 64 of example.
On each iteration of the loop, you will want to increase the radius value and decrease the alpha value accordingly. You would then simply need to create a new Color object with the RGB & alpha values you need
Check out 2D Graphics for details
Updated with example...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FadingCircles {
public static void main(String[] args) {
new FadingCircles();
}
public FadingCircles() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public static final int CIRCLE_COUNT = 10;
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int maxRadius = Math.min(getWidth(), getHeight());
int alpha = 255;
int range = 255 - 32;
g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
for (int index = 0; index < CIRCLE_COUNT; index++) {
float progress = (float) index / (float) CIRCLE_COUNT;
alpha = 255 - Math.round(range * progress);
Color color = new Color(0, 0, 0, alpha);
g2d.setColor(color);
int radius = Math.round(maxRadius * progress);
int x = (getWidth() - radius) / 2;
int y = (getHeight() - radius) / 2;
g2d.draw(new Ellipse2D.Float(x, y, radius, radius));
}
g2d.dispose();
}
}
}
You might also like to check out Performing Custom Painting

Drawing a nice circle in Java

I'm using Java Graphics and I keep getting "ugly" circles.
Here's what my Java program makes
And here's the same thing being made in Matlab
I think it is clear that the Java one is not as "nice" looking as the Matlab one, particularly on the edges of the circle. Note that this has nothing to do with the resolution...these images are practically the same size. Also note that I am already setting rendering hints.
Here's a stand alone with a Main function you can run to test this out.
package test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class SimplePaint02 {
private static final int LINE_THICKNESS = 4;
private static final int LINE_GAP = 10;
private Color lineColor = Color.red;
public static void main(String[] args) {
new SimplePaint02();
}
public SimplePaint02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame();
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 {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
#Override
public void paintComponent(Graphics g) {
int radius = 50;
BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
Ellipse2D circle = new Ellipse2D.Float(0, 0, radius,radius);
Shape clip = g2d.getClip();
g2d.setClip(circle);
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45),radius / 2, radius / 2));
int gap = LINE_GAP;
g2d.setColor(Color.WHITE);
g2d.fill(circle);
g2d.setColor(lineColor);
//g2d.setStroke(new BasicStroke(LINE_THICKNESS));
for (int index = 0; index < 10; index++) {
int x1 = index*gap-(LINE_THICKNESS/2);
int y1 = 0;
int x2 = index*gap+(LINE_THICKNESS/2);
int y2 = radius;
int width = x2 - x1;
int height = y2 - y1;
g2d.fillRect(x1, y1, width, height);
//g2d.drawLine(index * gap, 0, index * gap, getRadius());
}
g2d.setTransform(at);
g2d.setClip(clip);
g2d.dispose();
g.drawImage(buffer, 0, 0, this);
}
}
}
EDIT: Please see Code Guy's answer below for a solution. This is marked correct because it was Joey Rohan who figured it out initially!
I got smooth edge when i tried out same thing:
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class DrawSmoothCircle {
public static void main(String[] argv) throws Exception {
BufferedImage bufferedImage = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.green);
g2d.fillOval(10, 10, 50, 50);
g2d.dispose();
ImageIO.write(bufferedImage, "png", new File("e:\\newimage.png"));
}
}
UPDATE:
After searching alot:
There is nothing wrong with the code but,
Well, unfortunately Java 2D (or at least Sun's current implementation) does not support "soft clipping."
But Also got a trick for the clips:
Follow This link,you can achieve what you are asking for.
(Also, i got a smooth edge, cause i din't use clip stuff,in my above image)
Here was the answer. I adapted the majority of the code from this site. Take a look:
Here's the code:
public void paintComponent(Graphics g) {
// Create a translucent intermediate image in which we can perform
// the soft clipping
GraphicsConfiguration gc = ((Graphics2D) g).getDeviceConfiguration();
BufferedImage img = gc.createCompatibleImage(getWidth(), getHeight(), Transparency.TRANSLUCENT);
Graphics2D g2 = img.createGraphics();
// Clear the image so all pixels have zero alpha
g2.setComposite(AlphaComposite.Clear);
g2.fillRect(0, 0, getWidth(), getHeight());
// Render our clip shape into the image. Note that we enable
// antialiasing to achieve the soft clipping effect. Try
// commenting out the line that enables antialiasing, and
// you will see that you end up with the usual hard clipping.
g2.setComposite(AlphaComposite.Src);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.WHITE);
g2.fillOval(0, 0, getRadius(), getRadius());
// Here's the trick... We use SrcAtop, which effectively uses the
// alpha value as a coverage value for each pixel stored in the
// destination. For the areas outside our clip shape, the destination
// alpha will be zero, so nothing is rendered in those areas. For
// the areas inside our clip shape, the destination alpha will be fully
// opaque, so the full color is rendered. At the edges, the original
// antialiasing is carried over to give us the desired soft clipping
// effect.
g2.setComposite(AlphaComposite.SrcAtop);
g2.setColor(lineColor);
int gap = LINE_GAP;
AffineTransform at = g2.getTransform();
g2.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45),getRadius() / 2, getRadius() / 2));
for (int index = 0; index < 10; index++) {
int x1 = index*gap-(LINE_THICKNESS/2);
int y1 = 0;
int x2 = index*gap+(LINE_THICKNESS/2);
int y2 = getRadius();
int width = x2 - x1;
int height = y2 - y1;
g2.fillRect(x1, y1, width, height);
}
g2.setTransform(at);
g2.dispose();
// Copy our intermediate image to the screen
g.drawImage(img, 0, 0, null);
}
Update
OK. Then the idea is to not use clipping at all but instead to make the clipped shape by subtracting areas from each other.
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class SimplePaint02 {
private static final int LINE_THICKNESS = 4;
private static final int LINE_GAP = 10;
private Color lineColor = Color.red;
public static void main(String[] args) {
new SimplePaint02();
}
public SimplePaint02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame();
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 {
int radius = 75;
#Override
public Dimension getPreferredSize() {
return new Dimension(radius, radius);
}
#Override
public void paintComponent(Graphics g) {
Ellipse2D circle = new Ellipse2D.Float(0, 0, radius, radius);
Area lines = new Area();
int gap = LINE_GAP;
for (int index = 0; index < 10; index++) {
int x1 = index * gap - (LINE_THICKNESS / 2);
int y1 = 0;
int x2 = index * gap + (LINE_THICKNESS / 2);
int y2 = radius;
int width = x2 - x1;
int height = y2 - y1;
Shape lineShape = new Rectangle2D.Double(x1, y1, width, height);
lines.add(new Area(lineShape));
//g3d.fillRect(x1, y1, width, height);
//g2d.drawLine(index * gap, 0, index * gap, getRadius());
}
//g2d.setClip(circle);
Area circleNoLines = new Area(circle);
circleNoLines.subtract(lines);
Area linesCutToCircle = new Area(circle);
linesCutToCircle.subtract(circleNoLines);
//g2d.setTransform(at);
BufferedImage buffer = new BufferedImage(radius * 2, radius * 2, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45), radius / 2, radius / 2));
g2d.setRenderingHints(rh);
g2d.setColor(Color.ORANGE);
g2d.fill(linesCutToCircle);
g2d.setColor(Color.RED);
g2d.fill(circleNoLines);
g2d.dispose();
g.drawImage(buffer, 0, 0, this);
}
}
}
Old code
Part of the problem is that the rendering operations typically do not apply to a Clip, though they will apply to the Shape when it is drawn. I generally solve that by (last) painting the Shape itself. E.G.
A 1.5 pixel BasicStroke is used here for the red circle - smoothing the rough edges produced by the Clip.
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class SimplePaint02 {
private static final int LINE_THICKNESS = 4;
private static final int LINE_GAP = 10;
private Color lineColor = Color.red;
public static void main(String[] args) {
new SimplePaint02();
}
public SimplePaint02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame();
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 {
int radius = 75;
#Override
public Dimension getPreferredSize() {
return new Dimension((int)(1.1*radius), (int)(1.1*radius));
}
#Override
public void paintComponent(Graphics g) {
BufferedImage buffer = new BufferedImage(radius*2, radius*2, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_DITHERING,RenderingHints.VALUE_DITHER_ENABLE);
rh.put(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHints(rh);
Ellipse2D circle = new Ellipse2D.Float(0, 0, radius,radius);
Shape clip = g2d.getClip();
g2d.setClip(circle);
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(45),radius / 2, radius / 2));
int gap = LINE_GAP;
g2d.setColor(Color.WHITE);
g2d.fill(circle);
g2d.setColor(lineColor);
//g2d.setStroke(new BasicStroke(LINE_THICKNESS));
for (int index = 0; index < 10; index++) {
int x1 = index*gap-(LINE_THICKNESS/2);
int y1 = 0;
int x2 = index*gap+(LINE_THICKNESS/2);
int y2 = radius;
int width = x2 - x1;
int height = y2 - y1;
g2d.fillRect(x1, y1, width, height);
//g2d.drawLine(index * gap, 0, index * gap, getRadius());
}
g2d.setTransform(at);
g2d.setClip(clip);
g2d.setClip(null);
g2d.setStroke(new BasicStroke(1.5f));
g2d.draw(circle);
g2d.dispose();
g.drawImage(buffer, 0, 0, this);
}
}
}
I used drawPolygon method to draw circle by generating array of most of the points on circumference of circle with proposed radius.
Code:
import java.awt.*;
import java.applet.*;
/*<applet code="OnlyCircle" width=500 height=500>
</applet>*/
public class OnlyCircle extends Applet{
public void paint(Graphics g){
int r=200;//radius
int x1=250;//center x coordinate
int y1=250;//center y coordinate
double x2,y2;
double a=0;
double pi=3.14159;
int count=0;
int i=0;
int f=0;
int[] x22=new int[628319];
int[] y22=new int[628319];
while(a<=2*pi&&i<628319&&f<628319)
{
double k=Math.cos(a);
double l=Math.sin(a);
x2=x1+r*k;
y2=y1+r*l;
x22[i]=(int)x2;
y22[f]=(int)y2;
i++;
f++;
a+=0.00001;
}
int length=x22.length;
g.drawPolygon(x22,y22,length);
}
}
You can enable anti-aliasing:
Graphics2D g2 = (Graphics2D) g;
Map<RenderingHints.Key, Object> hints = new HashMap<RenderingHints.Key, Object>();
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(hints);
I also suggest you draw to the Graphics object you get from the paintComponent method rather than creating an intermediate BufferedImage.

Categories