I am trying to draw each pixel on the frame but I cannot work out how to draw the next pixel, it only shows one pixel drawn, plz help.
I do not know how to achieve this would someone edit this code so that it draws the pixels in the adjacent coordinates plz.
import java.lang.*;
import java.util.*;
import java.util.List;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class MyDrawPixel extends Frame {
public Point mypoint = new Point();
public static void drawPixel(Graphics g, int x, int y, int size, Paint color)
{
Graphics2D ga = (Graphics2D)g;
Shape circle = new Ellipse2D.Float(x, y, size, size);
ga.setPaint(color);
ga.draw(circle);
ga.setPaint(color);
ga.fill(circle);
}
public void paint(Graphics g) {
Graphics2D ga = (Graphics2D)g;
drawPixel(g, mypoint.x, mypoint.y, 1, Color.black);
}
public static void main(String args[])
{
MyDrawPixel frame = new MyDrawPixel();
frame.mypoint.x = 43;
frame.mypoint.y = 43;
MyDrawPixel frame1 = new MyDrawPixel();
frame1.mypoint.x = 44;
frame1.mypoint.y = 44;
MyDrawPixel frame2 = new MyDrawPixel();
frame2.mypoint.x = 45;
frame2.mypoint.y = 45;
MyDrawPixel frame3 = new MyDrawPixel();
frame3.mypoint.x = 46;
frame3.mypoint.y = 46;
MyDrawPixel frame4 = new MyDrawPixel();
frame4.mypoint.x = 47;
frame4.mypoint.y = 47;
frame.addWindowListener(
new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
System.exit(0);
}
}
);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
You're creating 5 frames and displaying only one. What you need to do is create 1 frame and display it correctly.
You can use repaint() to refresh the screen, then just change the attributes between the repaints if you want to move a single dot around.
Or even better, find a proper tutorial about custom painting, your code is quite horrible.
Related
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 am just trying to make a simple aquarium type application. The fish moves from left to right. (the mouth of fish is faced towards right). When it reaches the end of the JFrame, it returns back. What I wanted is that it must face towards left when it returns.(goes back) So, I have decided to paint with a new image when the fish reaches at the specific coordinate. How to do it? Please.
image 1 = fish of image whose mouth is right faced
image 2 = fish of image whose mouth is left faced
package aquarium;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.Timer;
public class Aquarium extends JPanel implements ActionListener{
Random r = new Random();
Timer t = new Timer(5, this);
int x = 0, y= 30;
int velX = 1 ,velY =1;
ImageIcon image = new ImageIcon(getClass().getResource("../res/aquarium.gif"));
ImageIcon image1 = new ImageIcon(getClass().getResource("../res/smallFish.gif"));
ImageIcon image2 = new ImageIcon(getClass().getResource("../res/new.gif"));
int numberFish = 12;
Aquarium() {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
image.paintIcon(this, g, 0, 0);
image1.paintIcon(this, g, x, y);
t.start();
}
#Override
public void actionPerformed(ActionEvent e){
Graphics g = null;
if(x<0 || x>465) {
velX = -velX;
}
x += velX;
repaint();
}
public static void main(String[] args) {
Aquarium a = new Aquarium();
JFrame f = new JFrame();
f.setTitle("The Aquarium");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setResizable(false);
f.setBounds(500,200,500,300); //left,top,width,height
f.add(a);
}
}
Use velX to check which fish it is and draw it:
public void paintComponent(Graphics g){
super.paintComponent(g);
image.paintIcon(this, g, 0, 0);
if (velX > 0) { // moving right
image1.paintIcon(this, g, x, y);
} else { // moving left
image2.paintIcon(this, g, x, y);
}
t.start();
}
Hey I am supposed to take in a list of cities and x and y coordinates and plot them. I have all the cities in as Vertexes with x and y coordinates. Now I am trying to plot them but I can't seem to see what I am doing wrong and I am not getting an error. This is my first time using GUI so it could be a dumb mistake.
import javax.swing.JTextField;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
import java.util.Arrays;
public class GraphMaker{
public GraphMaker(Vertex[] a )
{
JFrame frame = new JFrame();
String start = "Start";
int columns=20;
String end = "End";
JTextField startCity = new JTextField(start,columns);
JTextField endCity = new JTextField(end,columns);
JButton button = new JButton("Find Path");
//button.addActionListener(button);
int length = a.length;
Vertex current = a[0];
CityComponent cityPanel = new CityComponent(current);
/*for(int i=0; i < length; i++){
Vertex current = a[i];
g2.draw(new Line2D.Double(x,y,x,y));
}*/
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(startCity);
panel.add(endCity);
panel.add(button);
frame.setLayout(new BorderLayout());
frame.add(cityPanel,BorderLayout.CENTER);
frame.add(panel,BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
return;
}
}
import javax.swing.*;
import java.awt.*;
public class CityComponent extends JComponent {
private Vertex m;
private int x = 0;
private int y = 0;
public CityComponent(Vertex m) {
this.m = m;
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
m.draw(g2);
}
}
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
public class Vertex{
public String element;
public Double x;
public Double y;
public Vertex(String city, String a, String b){
this.element = city;
this.x = Double.parseDouble(a);
this.y = Double.parseDouble(b);
}
public void draw(Graphics2D g2){
Point2D.Double r1 = new Point2D.Double(x/10, y/10);
Line2D.Double line = new Line2D.Double(r1,r1);
g2.draw(line);
}
}
You're trying to use a Graphics object that doesn't exist. As I see it you have one of two choices to make here:
You could draw in the paintComponent(Graphics g) method of a class that extends JPanel, using a for loop to iterate through the vertices, and drawing with the Graphics object supplied by the JVM...
Or you could draw in a BufferedImage, using the Graphics object you obtain by calling getGraphics() on the BufferedImage. You could then place the image into an ImageIcon, and then the Icon into a JLabel.
Or you could do a combintation of the above by drawing the BufferedImage created above in a JPanel's paintComponent method.
Whatever you do, don't use a Graphics object obtained by calling getGraphics() on a Swing component. You've been warned.
Edit
I'm now seeing your CityComponent class which extends JComponent, and now see that you should be drawing with this. The key will be to pass the correct Vertex into it, something that I don't know if you're doing correctly, since we don't see how you construct your GraphMaker class.
You might wish to tell us which code is yours, which was given to you, and also give us your exact requirements. Some of your code still seems a bit off.
I created a background using a relatively bland texture (it repeats well, so that's a bonus). However, on top of that, I am trying to add two images in random positions, each five times. So I tried that out with this -
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RepeatDiagonals {
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
public static JFrame framePanel;
public static DiagonalImages diagTest;
public static void createAndInitGUI() {
diagTest = new DiagonalImages();
framePanel = new JFrame("Diagonal Testing");
framePanel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
framePanel.setPreferredSize(new Dimension(1020, 720));
framePanel.add(diagTest);
framePanel.pack();
framePanel.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndInitGUI();
} // public void run() Closing
}); // SwingUtilities Closing
}
}
// TODO Add in constructor for better image import
class DiagonalImages extends JPanel {
public static final String IMAGE_PATH_WHITESTREAK = "imageFolder/whiteBackgroundStreakOverlay.png";
public static final String IMAGE_PATH_BLACKSTREAK = "imageFolder/blackBackgroundStreakOverlay.png";
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
public static Image overlayStreak;
DiagonalImages() {
loadImages();
setVisible(true);
setOpaque(false);
};
public void loadImages() {
try {
whiteOverlayStreak = ImageIO.read(new File(IMAGE_PATH_WHITESTREAK));
blackOverlayStreak = ImageIO.read(new File(IMAGE_PATH_BLACKSTREAK));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Dimension size = this.getSize();
Insets insets = this.getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random randomInteger = new Random();
randomInteger.nextInt(900);
for (int i = 0; i < 3; i++) {
int x = randomInteger.nextInt() % w;
int y = randomInteger.nextInt() % h;
g2d.drawImage(blackOverlayStreak, x, y, null);
}
for (int i2 = 0; i2 < 5; i2++){
int x2 = randomInteger.nextInt() % w;
int y2 = randomInteger.nextInt() % h;
g2d.drawImage(whiteOverlayStreak, x2, y2, null);
}
}
}
The relevant part of the main code:
// Makes the Initial BorderLayout
allContent = new ImagePanel(image);
allContent.setLayout(new BorderLayout());
allContent.add(new DiagonalImages());
allContent.add(tabbedPane, BorderLayout.CENTER);
allContent.add(logoImage, BorderLayout.NORTH);
allContent.setVisible(true);
allContent.setOpaque(false);
// Add ScrollPane
scrollPane = new JScrollPane(allContent);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
scrollPane.setWheelScrollingEnabled(true);
// JFrame programFrame Constructors
programFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
programFrame.setLayout(new BorderLayout());
programFrame.add(scrollPane);
programFrame.pack();
programFrame.setVisible(true);
programFrame.setResizable(true);
programFrame.setSize(1280, 720);
programFrame.setLocationRelativeTo(null);
And here's the ImagePanel I have:
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
class ImagePanel extends JPanel {
private Image image;
private boolean tile;
ImagePanel(Image image) {
this.image = image;
this.tile = false;
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int iw = image.getWidth(this);
int ih = image.getHeight(this);
if (iw > 0 && ih > 0) {
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(image, x, y, iw, ih, this);
}
}
}
}
}
Thanks for the (future) help!
EDIT: Made a small change based on the answer given, and it's still not working.
Okay, so the problem is that the image that's supposed to be repeated isn't actually even showing up.
EDIT2: Rewrote my entire code for this, and it's still not working. Even setting the background color isn't working, which leads me to believe it's a problem with my paintComponent.
EDIT3: paintComponent is working thanks to help. My final problem is getting it to work correctly in my main method.
First JFrame.setVisible(true); should be done last, after pack() which does layouting.
framePanel.pack();
framePanel.setVisible(true);
The images maybe better reside in the application (jar) itself, then you can use getClass().getResource("...").
They should be loaded outside paint, say in the constructor. I guess, it was test code.
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
DiagonalImages() {
loadImages();
}
private void loadImages() {
whiteOverlayStreak = new ImageIcon(
getClass().getResource("/white.jpg")).getImage();
blackOverlayStreak = new ImageIcon(
getClass().getResource("/black.jpg")).getImage();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int x = r.nextInt(w);
int y = r.nextInt(h);
Your failure was not using #Override because then you would have seen, that you miswrote Graphics2D g instead of Graphics g. The function paintComponent never got called! LoL
Additional question: adding a second panel
framePanel.setLayout(new BorderLayout());
framePanel.add(diagTest, BorderLayout.CENTER);
framePanel.add(otherPanel, BorderLayout.SOUTH);
It wasn't really an SSCCE.
I haven't tested this fully, mainly because I didn't want to have to set up an entire Eclipse project just to point out the obvious mistake.
Separate the image process from the JPanel.
Only extend Swing components when you're modifying a component method.
Here's my version of your code. I had to modify your code to read an image to get it to work. You're going to have to figure out that part of the code yourself.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
class GUIImages {
private Image whiteDiagonal;
// private Image blackDiagonal;
public GUIImages() {
loadImages();
}
private void loadImages() {
try {
whiteDiagonal = ImageIO.read(new File(
"C:/Documents and Settings/BOP00082/" +
"My Documents/My Pictures/Places-icon.png"));
} catch (IOException e) {
e.printStackTrace();
}
// whiteDiagonal = new ImageIcon(this.getClass().getResource(
// "imageFolder/whiteBackgroundStreakOverlay.png")).getImage();
// blackDiagonal = new ImageIcon(this.getClass().getResource(
// "imageFolder/blackBackgroundStreakOverlay.png")).getImage();
}
public void doDrawing(JPanel panel, Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(createDiagonalImage(panel), 0, 0, null);
}
private Image createDiagonalImage(JPanel panel) {
BufferedImage buffImg = new BufferedImage(677, 856,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gbi = buffImg.createGraphics();
Dimension size = panel.getSize();
Insets insets = panel.getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random r = new Random();
for (int i = 0; i < 5; i++) {
int x = Math.abs(r.nextInt()) % w;
int y = Math.abs(r.nextInt()) % h;
gbi.drawImage(whiteDiagonal, x, y, null);
}
gbi.dispose();
return buffImg;
}
}
class Surface extends JPanel {
GUIImages images;
public Surface(GUIImages images) {
this.images = images;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
images.doDrawing(this, g);
}
}
public class RepeatDiagonals implements Runnable {
JFrame frame;
#Override
public void run() {
frame = new JFrame();
frame.setTitle("Repeat Diagonals");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Surface(new GUIImages()));
frame.setSize(350, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new RepeatDiagonals());
}
}
I have Line2D and Arc2D objects laid out on my JPanel by Graphics2D drawing. You can have a look a part of it on this question " How to make pixel perfect Line2D in - Graphics2D ". Now what I want to achieve is, I want to create two parallel lines and arcs for all Line2D and Arc2D objects. Visually,
Normal Line2D and Arc2D drawn currently,
Want to decorate it like this,
My Thoughts so far,
I might be able to achieve this by creating two different line and give an offset +gap and -gap from my normal line position. However This will make lots of objects which I don't want to.
Now, is it possible to make my normal line thicker like this,
and give them a border and delete middle bit from it?
Is it possible to achieve this? if yes, May I please have some direction.
Thank you for any kind of help.
Use a BasicStroke and draw it twice, thicker and thinner.
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.File;
class PaintThick {
public static void main(String[] args) throws Exception {
int size = 150;
final BufferedImage bi = new BufferedImage(
size,size,BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
double pad = 20;
Line2D.Double line1 = new Line2D.Double(
pad,pad,(double)(size-pad),(double)(size-pad));
int cap = BasicStroke.CAP_BUTT;
int join = BasicStroke.JOIN_MITER;
BasicStroke thick = new BasicStroke(15,cap,join);
BasicStroke thinner = new BasicStroke(13,cap,join);
g.setColor(Color.WHITE);
g.fillRect(0,0,size,size);
g.setColor(Color.BLACK);
g.setStroke(thick);
g.draw(line1);
g.setColor(Color.WHITE);
g.setStroke(thinner);
g.draw(line1);
ImageIO.write(bi,"png",new File("img.png"));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(
null, new JLabel(new ImageIcon(bi)));
}
});
}
}
You can implement the Stroke interface to create a CompositeStroke, as shown here.
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;
/**
* #see http://www.jhlabs.com/java/java2d/strokes/
* #see http://stackoverflow.com/questions/7342979
*/
class StrokeTest {
private static final int SIZE = 200;
private static final double PAD = 20d;
private static class CompositeStroke implements Stroke {
private Stroke stroke1, stroke2;
public CompositeStroke(Stroke stroke1, Stroke stroke2) {
this.stroke1 = stroke1;
this.stroke2 = stroke2;
}
#Override
public Shape createStrokedShape(Shape shape) {
return stroke2.createStrokedShape(
stroke1.createStrokedShape(shape));
}
}
public static void main(String[] args) throws Exception {
final BufferedImage bi = new BufferedImage(
SIZE, SIZE, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Arc2D.Double shape = new Arc2D.Double(PAD, 2 * PAD,
(SIZE - 2 * PAD), (SIZE - 2 * PAD), 0, 180d, Arc2D.OPEN);
g.setColor(Color.white);
g.fillRect(0, 0, SIZE, SIZE);
BasicStroke s1 = new BasicStroke(16f);
BasicStroke s2 = new BasicStroke(1f);
g.setStroke(new CompositeStroke(s1, s2));
g.setColor(Color.black);
g.draw(shape);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JLabel(new ImageIcon(bi)));
f.pack();
f.setVisible(true);
}
});
}
}