How to create a rectangle in a rectangle? - java

In my paintComponent, I have drawRect, which draws a single rectangle. However, I want to make the outline of the rectangle thicker but I don't know how. So I thought of making another rectangle inside the existing one. I tried putting another drawRect but the rectangle isn't in the center.
Thanks for those who'll help!

g2d.setStroke(new BasicStroke(6));
The argument passed to the paintComponent(Graphics) method of a Swing component should actually be a Graphics2D instance. It can be cast to one.
See this example in which 3 strokes are layered.
import javax.swing.*;
import java.awt.*;
class StrokeIt {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
StrokePanel sp = new StrokePanel();
sp.setPreferredSize(new Dimension(400,100));
sp.setBackground(Color.BLUE);
JOptionPane.showMessageDialog(null, sp);
}
});
}
}
class StrokePanel extends JPanel {
int pad = 12;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(10));
g2d.drawRect( 0+pad, 0+pad,
getWidth()-(2*pad), getHeight()-(2*pad) );
g2d.setColor(Color.YELLOW);
g2d.setStroke(new BasicStroke(6));
g2d.drawRect( 0+pad, 0+pad,
getWidth()-(2*pad), getHeight()-(2*pad) );
g2d.setColor(Color.ORANGE);
g2d.setStroke(new BasicStroke(2));
g2d.drawRect( 0+pad, 0+pad,
getWidth()-(2*pad), getHeight()-(2*pad) );
}
}

Related

Creating smooth edges on a BufferedImage while using Graphics2D in java

I created the following code example to demonstrate my problem. I want to draw into a BufferedImage by a Graphics2D object, but the edges are not sharp. I tried using different renderinghints, but it didn't help. I also tried a BufferedImageOp as you can see in the code, but I don't understand its meaning in drawImage and don't know its possibilites. Can you help me please?
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
public class SmoothGraphics extends JComponent{
private BufferedImage image;
private static JFrame frame;
private int x = 100;
private int y = 100;
private int size = 200;
public static void main(String[] args){
frame = new JFrame();
SmoothGraphics component = new SmoothGraphics();
frame.add(component);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
public SmoothGraphics(){
super();
setPreferredSize(new Dimension(400,400));
setBounds(100,100,400,400);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
image = gc.createCompatibleImage(width, height);
Graphics2D imageGraphics = (Graphics2D) image.createGraphics();
imageGraphics.setColor(Color.RED);
/*imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);*/
drawExample(imageGraphics);
imageGraphics.dispose();
/*the following kernel helps with the smoothness of the rectangle, but not of the circle
int kernelWidth = 3;
int kernelHeight = 3;
float[] data = new float[kernelWidth*kernelHeight];
data[4]=1;
Kernel kernel = new Kernel(kernelWidth, kernelHeight, data);
BufferedImageOp op = new ConvolveOp(kernel);
*/
//draw image
BufferedImageOp op = null;
g2d.drawImage(image,op,0,0);
//I don't know if this line is necessary
image.flush();
}
private void drawExample(Graphics2D g2d){
//Square as path
Path2D.Double path = new Path2D.Double();
path.moveTo(x,y);
path.lineTo(x+size,y);
path.lineTo(x+size,y+size);
path.lineTo(x,y+size);
path.closePath();
g2d.draw(path);
//Circle
g2d.fillOval(x+size/4,y+size/4,size/2,size/2);
}
}
The output of my code. Notice that the edges are not very clean/sharp!
My result with antialiasing and kernel usage:
My wished result:
Okay... I believe the real problem you are facing is initial scaling of the component graphics (g), which makes your image stretched during drawImage(...). I don't get the same problem here.
To get proper smooth (or "sharp" as you call it) rendering, you do want to enable antialiasing. But you also need to paint without pixel scaling (it's possible with image too, by creating a larger image, however, I don't see why you need the extra image in this case).
Here's your sample program rewritten:
import javax.swing.*;
import java.awt.*;
public class SmoothGraphics extends JComponent {
private final int x = 100;
private final int y = 100;
private final int size = 200;
public static void main(String[] args) {
JFrame frame = new JFrame("Smooth");
SmoothGraphics component = new SmoothGraphics();
frame.getContentPane().add(component, BorderLayout.CENTER); // Add to content pane
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack(); // Pack *before* setVisible(true)!
frame.setLocationRelativeTo(null); // Center the frame after pack()
frame.setVisible(true);
}
public SmoothGraphics() {
setOpaque(true); // Minor optimization
setPreferredSize(new Dimension(400, 400)); // No need to use setBounds, pack() will fix that for you
}
#Override
public void paintComponent(Graphics g) {
// No need to call super, as we repaint everything
Graphics2D g2d = (Graphics2D) g;
// Clear background to black
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());
// Paint in read, with antialiasing
g2d.setColor(Color.RED);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawExample(g2d);
}
private void drawExample(Graphics2D g2d) {
// Square (this way avoids the odd skewed lines)
g2d.drawRect(x, y, size, size);
// Circle
g2d.fillOval(x + size / 4, y + size / 4, size / 2, size / 2);
}
}
Result:
If you really want/need the BufferedImage, I found a way that works for me (MacOS). It might need some minor tweaks to work perfectly on other platforms.
#Override
public void paintComponent(Graphics g) {
// No need to call super, as we repaint everything
Graphics2D g2d = (Graphics2D) g;
GraphicsConfiguration gc = g2d.getDeviceConfiguration();
AffineTransform transform = gc.getNormalizingTransform();
BufferedImage image = gc.createCompatibleImage((int) ceil(getWidth() * transform.getScaleX()), (int) ceil(getHeight() * transform.getScaleY()));
Graphics2D graphics = image.createGraphics();
try {
graphics.setTransform(transform);
graphics.setColor(Color.RED);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Need antialiasing on
drawExample(graphics);
}
finally {
graphics.dispose();
}
try {
AffineTransform originalTransform = g2d.getTransform();
originalTransform.concatenate(transform.createInverse());
g2d.setTransform(originalTransform);
}
catch (NoninvertibleTransformException e) {
throw new RuntimeException(e); // API oddity, this should have been a RuntimeException
}
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // Need render QUALITY here, to avoid the stretching/tearing
// g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // Don't need this on MacOS, but may be needed on other platforms
g2d.drawImage(image, null, 0, 0);
}
Result:

Drawing traffic light, Error in passing of variables I think

I'm trying to fill each circle with a colour. The paintComponent method is supposed to create the general outline of a traffic light.
Then the other methods are supposed to fill each circle with a different color, depending on what color the traffic light is going to be. I get the error, that it cant find symbol( e.g
TrafficLight.java:56: error: cannot find symbol
g2.fill(circle3);
I didnt think I had to pass the circle variables into the other methods, if they were in the same class. I tried adding the circle variables and then i get identifier expected. Pretty sure there's something about the passing of variables that im not getting, but any help would be appreciated
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class TrafficLight extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2= (Graphics2D) g;
Rectangle box= new Rectangle(100,800,200,700);
g2.setPaint(Color.BLACK);
g2.fill(box);
g2.draw(box);
Ellipse2D.Double circle1=new Ellipse2D.Double(200,200,200,200);
g2.draw(circle1);
Ellipse2D.Double circle2=new Ellipse2D.Double(200,200,200,400);
g2.draw(circle2);
Ellipse2D.Double circle3=new Ellipse2D.Double(200,200,200,600);
g2.draw(circle3);
}
public void drawRed(Graphics g)
{
Graphics2D g2=(Grpahics2D) g;
g2.setPaint(Color.RED);
g2.fill(circle1);
g2.setPaint(Color.BLACK);
g2.fill(circle2);
g2.fill(circle3);
}
public void drawGreen(Graphics g)
{
Graphics2D g2= (Graphics2D) g;
g2.setPaint(Color.GREEN);
g2.fill(circle3);
g2.setPaint(Color.BLACK);
g2.fill(circle2);
g2.fill(circle1);
}
public void drawYellow(Graphics g)
{
Graphics2D g2= (Graphics2D) g;
g2.setPaint(Color.YELLOW);
g2.fill(circle2);
g2.setPaint(Color.BLACK);
g2.fill(circle1);
g2.fill(circle3);
}
}
The entire code is missing.
But the general solution is to have the paintComponent method do all.
So have a state red/green/yellow.
public class TrafficLight extends JComponent {
public enum Light { RED, GREEN, YELLOW, BLACK }
private Light light = Light.BLACK;
public void setLight(Light light) {
this.light = light;
repaint(50L); // Repaint almost immediately.
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
...
// Draw red bulb
g2.setPaint(light == Light.RED ? Color.RED : Color.BLACK);
...
// Draw yellow bulb
g2.setPaint(light == Light.YELLOW ? Color.YELLOW : Color.BLACK);
...
// Draw green bulb
g2.setPaint(light == Light.GREEN ? Color.GREEN : Color.BLACK);
Switching the light then alters the state and causes a repaint. There are some repaint methods.
Instead of the enum one might use Color light;, but that is not so clear.
Also consider an enum value BLACK, for semaphores without electricity.
To handle automatic timed switching, one might use a swing Timer.

Why doesn't both my Polygons have a border when i use setStroke?

I am drawing two stars using:
public void draw(Graphics2D g2) {
g2.drawPolygon(xCoordOfStar, yCoordOfStar, POINTS);
g2.setStroke(new BasicStroke(5));
}
and:
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Star star1 = new Star(100,200,300);
Star star2 = new Star(200,200,300);
star1.draw(g2);
star2.draw(g2);
}
In the other class.
For some reason unknown to me, only the bigger star (star2) gets a thicker border, while star1 does not get any border. What am I doing wrong?
It's an ordering issue. Your second Polygon gets a border because your first Polygon called the g2.setStroke(new BasicStroke(5)); Comment out the first star code, the second star now also loses its border.
To fix it, you just need to rearrange the methods:
public void draw(Graphics2D g2) {
g2.setStroke(new BasicStroke(5));
g2.drawPolygon(xCoordOfStar, yCoordOfStar, POINTS);
}

drawing a diamond inside a square usnig java swing

I am having some trouble while using swing to draw a diamond inside a square.
My code is this,please some one have a look at it and let me know if you can provide a fullfunctional code which is working in creating a diamond inside a square.
The code is:-
import javax.swing.*;
import java.awt.*;
public class MyDrawing extends JPanel
{
static int width=250;
static int height=250;
static int x=0;
static int y=0;
private void doDrawing(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
//for (int i = 0; i <= 1000; i++)
g2d.drawRect(x, y, width,height);
g2d.rotate(Math.toRadians(-45));
System.out.println(Math.toRadians(-45));
x=0;
y=height/2;
System.out.println(y);
width=(int)Math.pow(Math.pow((width/2),2)*2,0.5);
height=width;
System.out.println("width:"+width+"height:"+height);
g2d.drawRect(y, x, width,height);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
To keep the the diamond inside the sqaure, simply
1. Draw a rectangle
2. Rotate the rectangle about its center.
Rectangle2D rectangle = new Rectangle2D.Double(20, 20, 50, 50);
g2.draw(rectangle);
AffineTransform transform = new AffineTransform();
transform.rotate(Math.PI/4, rectangle.getX() + rectangle.width/2, rectangle.getY() + rectangle.height/2);
g2.draw(transform);

How do I use graphics2D in paint or is there a better way to do this?

I want to use graphics2D but I can't get I get it to display my graphics. Is there a better way to go about this that would allow me to use repaint()? Eventually I want to make have a image set as a background and be able to draw on it then save the contents of the frame as a image.
import java.awt.image.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.swing.JApplet;
import java.awt.*;
// assume that the drawing area is 150 by 150
public class test extends JApplet
{
final int radius = 25;
int width = 200, height = 200;
BufferedImage img = new BufferedImage(
width, height, BufferedImage.TYPE_INT_ARGB);
public void paint ( )
{
Graphics2D g = img.createGraphics();
g.setColor( Color.orange );
g.fillRect( 0, 0, 150, 150 );
g.setColor( Color.black );
g.drawOval( (150/2 - radius), (150/2 - radius), radius*2, radius*2 );
}
}
Ok so,
You have public void paint( ) what the hell is this doing lol? You need a graphics object. public void paint(Graphics g) is like the default method which gets called automatically when your applet is initialised.
You have Graphics2D g = img.createGraphics(); when you need to use your default Graphics g object and cast it into a Graphics2D object like so Graphics2D g2d = (Graphics2D) g;
You should search for a little more information on double buffering too :)
anyway... This code works so take from it what you want :)
P.S Note how I implemented Runnable; You do not need to do this if you only want to use the Graphics2D code. It is just making the class a thread and is used for game frame rates :)
Hope this helped.
import java.applet.*;
import java.awt.*;
public class Test extends Applet implements Runnable{
public boolean isRunning = false;
public int radius = 25;
public void start() {
isRunning = true;
new Thread(this).start();
}
public void stop() {
isRunning = false;
}
public void paint(Graphics g) {
//Create Graphics2D object, cast g as a Graphics2D
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.ORANGE);
g2d.fillRect(0, 0, 150, 150);
g2d.setColor(Color.BLACK);
g2d.drawOval((150/2 - radius), (150/2 - radius), radius * 2, radius * 2);
}
public void run() {
while (isRunning) {
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Categories

Resources