How to paint corners of a JButton with numbers? - java

I'm making a simple Kakuro application in Java Swing and I have used JButtons as cells. I've done everything from generating the grid (setBackground(Color.BLACK) and setBackground(Color.WHITE)) to filling with unique numbers.
But the problem is, I don't know how to paint the "clues" at the ends of JButtons. What I want is similar to:
Sometimes the numbers may appear on only 3 sides, 2 sides or even 1 side.
I thought of setting background images, but its not possible as the numbers are sums of dynamically generated numbers (the grid is dynamic).
So any idea how to get this kind of JButton? Or if its not possible, what other options do I have?
Thanks a lot in advance (I'm really stuck).

very simple and confortable way is add JLabels to the JButton by using BorderLayout,
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class FourLabelsInButton {
private JFrame frame;
private JButton myButton1;
private JLabel myButton1_Label_N;
private JLabel myButton1_Label_E;
private JLabel myButton1_Label_W;
private JLabel myButton1_Label_S = new JLabel();
public FourLabelsInButton() {
myButton1_Label_N = new JLabel("45");
myButton1_Label_N.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_N.setForeground(Color.red);
myButton1_Label_E = new JLabel("1");
myButton1_Label_E.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_E.setForeground(Color.red);
myButton1_Label_W = new JLabel("9");
myButton1_Label_W.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_W.setForeground(Color.red);
myButton1_Label_S = new JLabel("21");
myButton1_Label_S.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_S.setForeground(Color.red);
myButton1 = new JButton();
myButton1.setBackground(Color.black);
myButton1.setLayout(new BorderLayout());
myButton1.add(myButton1_Label_N, BorderLayout.NORTH);
myButton1.add(myButton1_Label_E, BorderLayout.EAST);
myButton1.add(myButton1_Label_W, BorderLayout.WEST);
myButton1.add(myButton1_Label_S, BorderLayout.SOUTH);
frame = new JFrame();
frame.add(myButton1);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
FourLabelsInButton ggg = new FourLabelsInButton();
}
});
}
}

I thought of setting background images, but its not possible as the numbers are sums of dynamically generated numbers (the grid is dynamic).
The images for the buttons can also be generated dynamically.

You may also use a custom component. For this case the painting can be implemented quite straightforward:
class KakuroComponent extends JComponent {
private final int[] numbers;
public KakuroComponent(int... numbers) {
this.numbers = numbers;
}
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getWidth();
g.setColor(Color.black);
g.fillRect(0, 0, w, h);
g.setColor(Color.white);
g.drawLine(0, 0, w, h);
g.drawLine(w - 1, 0, 0, h - 1);
if (numbers[0] > 0) // if there is a top number
drawStringCentered(g, String.valueOf(numbers[0]), w / 2, h / 6);
if (numbers[1] > 0) // if there is a left number
drawStringCentered(g, String.valueOf(numbers[1]), w / 6, h / 2);
if (numbers[2] > 0) // if there is a right number
drawStringCentered(g, String.valueOf(numbers[2]), w * 5 / 6, h / 2);
if (numbers[3] > 0) // if there is a bottom number
drawStringCentered(g, String.valueOf(numbers[3]), w / 2, h * 5 / 6);
}
void drawStringCentered(Graphics g, String s, int x, int y) {
Rectangle2D bounds = g.getFontMetrics().getStringBounds(s, g);
g.drawString(s, (int) (x - bounds.getCenterX()), (int) (y - bounds.getCenterY()));
}
}

There shouldn't be any reason you can't simply draw anything you want in the JButton by overwriting the paint() method.
public class KakuroSquare extends JButton
{
/* ... */
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
/* Your paint logic. */
}
}

Related

How to draw a triangle with border with Java Graphics

I'm trying to draw a triangle with a border using the Graphics.drawPolygon() method
The triangle is properly drawn, but how can I calculate the 3 points of the border?
I already did it with a circle, but I can't seem to find a solution for triangle.
A requirement of the instructor as that it cannot use Graphics2D.
My code:
if (xPoints != null && yPoints != null) {
int[] nXPoints = new int[] { xPoints[0] - borderThickness, xPoints[1] - borderThickness,
xPoints[2] - borderThickness };
int[] nYPoints = new int[] { yPoints[0] - borderThickness, yPoints[1] - borderThickness,
yPoints[2] - borderThickness };
g.setColor(borderColor);
g.fillPolygon(nXPoints, nYPoints, 3);
g.setColor(fillColor);
g.fillPolygon(xPoints, yPoints, 3);
}
Edit:
Expected result
Use the Graphics methods drawPolygon() to render the outline and fillPolygon() to fill its interior; both have the required signature, as shown here.
Because "operations that draw the outline of a figure operate by traversing an infinitely thin path between pixels with a pixel-sized pen," cast the graphics context to Graphics2D so that you can use draw() and fill() on the corresponding Shape. This will allow you to specify the outline using setStroke(), illustrated here.
I need it to have a custom thickness…I also don't want to use Graphics2D.
Custom thickness is not supported in the Graphics API. As suggested here, the actual graphics context received by paintComponent() is an instance of Graphics2D, which does support custom stroke geometry.
The things is teacher haven't taught me Graphics2D, so I'm not supposed to use it.
Then simply paint the larger triangle and then the smaller. If this isn't working, then you have an error in you calculation of the larger triangle, and you should edit your question to include a complete example.
I'm looking for a way to do it without Graphics2D…a guy has interpreted the question properly in this comment.
As #Marco13 observes, you need a triangle that is larger than the original one by the borderThickness. You can use AffineTransform to do the scaling. While Graphics can't fill() an arbitrary Shape, such as one created by AffineTransform, it can clip the rendering as required. In the example below, a unit triangle is translated and scaled to the center of an N x N panel; a copy is enlarged by delta. Note how rendering is clipped first to the larger background figure and then to the smaller foreground figure.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/39812618/230513
*/
public class GraphicsBorder {
private static class GraphicsPanel extends JPanel {
private static final int N = 256;
private static final Color FILL = new Color(0x990099);
private static final Color BORDER = new Color(0x66FFB2);
private final Shape fore;
private final Shape back;
public GraphicsPanel(Polygon polygon, int delta) {
AffineTransform a1 = new AffineTransform();
a1.translate(N / 2, N / 2);
a1.scale(N / 3, N / 3);
fore = a1.createTransformedShape(polygon);
AffineTransform a2 = new AffineTransform();
a2.translate(N / 2, N / 2 - delta / 3);
a2.scale(N / 3 + delta, N / 3 + delta);
back = a2.createTransformedShape(polygon);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(BORDER);
g.setClip(back);
g.fillRect(0, 0, N, N);
g.setColor(FILL);
g.setClip(fore);
g.fillRect(0, 0, N, N);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(N, N);
}
}
private void display() {
JFrame f = new JFrame("GraphicsBorder");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Polygon p = new Polygon();
p.addPoint(0, -1);
p.addPoint(1, 1);
p.addPoint(-1, 1);
f.add(new GraphicsPanel(p, 16));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new GraphicsBorder()::display);
}
}

Java JPanel Scaling

Hey Guys I have succesfully made a GUI in java that will scale polygons and circles using a slider. Everything works but I was wondering if there is a way to change the Origin point(Where it scales from). Right now it scales from the corner and I would like it to scale from the middle so I can start it in the middle and it scales out evenly. Also, If anyone could tell me an easy way to replace the Rectangle I have with an Image of some kind so you can scale the Picture up and down would be great! Thank you! Here is my code:
import javax.swing.*;
public class Fred
{
public static void main(String[] args)
{
TheWindow w = new TheWindow();
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //X wont close the window with out this line
w.setSize(375,375);
w.setVisible(true);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class TheWindow extends JFrame
{
private JSlider slider; //declare slider
private drawRect myPanel; //declare/ create panel
public TheWindow()
{
super("Slider Example"); //make title
myPanel = new drawRect();
myPanel.setBackground(Color.green); //change background color
slider = new JSlider(SwingConstants.VERTICAL, 0, 315, 10);// restrains the slider from scaling square to 0-300 pixels
slider.setMajorTickSpacing(20); //will set tick marks every 10 pixels
slider.setPaintTicks(true); //this actually paints the ticks on the screen
slider.addChangeListener
(
new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
myPanel.setD(slider.getValue()); //Wherever you set the slider, it will pass that value and that will paint on the screen
}
}
);
add(slider, BorderLayout.WEST); //similar to init method, adds slider and panel to GUI
add(myPanel, BorderLayout.CENTER);
}
}
import java.awt.*;
import javax.swing.*;
public class drawRect extends JPanel
{
private int d = 25; //this determines the beginning length of the rect.
public void paintComponent(Graphics g)//paints circle on the screen
{
super.paintComponent(g); //prepares graphic object for drawing
g.fillRect(15,15, d, d); //paints rectangle on screen
//x , y, width, height
}
public void setD(int newD)
{
d = (newD >= 0 ? newD : 10); //if number is less than zero it will use 10 for diameter(compressed if statement)
repaint();
}
public Dimension getPrefferedSize()
{
return new Dimension(200, 200);
}
public Dimension getMinimumSize()
{
return getPrefferedSize();
}
}
Changing the "origin point" so it becomes the center of the "zoom" is basically just the process of subtract half of d from the center point.
So, assuming the the center point is 28 ((25 / 2) + 15), you would simply then subtract d / 2 (25 / 2) from this point, 28 - (25 / 2) = 15 or near enough...
I modified the paintComponent method for testing, so the rectangle is always at the center of the panel, but you can supply arbitrary values in place of the originX and originY
#Override
public void paintComponent(Graphics g)//paints circle on the screen
{
super.paintComponent(g); //prepares graphic object for drawing
int originX = getWidth() / 2;
int originY = getHeight() / 2;
int x = originX - (d / 2);
int y = originY - (d / 2);
System.out.println(x + "x" + y);
g.fillRect(x, y, d, d); //paints rectangle on screen
//x , y, width, height
}
As for scaling an image, you should look at Graphics#drawImage(Image img, int x, int y, int width, int height, ImageObserver observer), beware though, this will scaling the image to the absolute size, it won't keep the image ratio.
A better solution might be to use a double value of between 0 and 1 and multiple the various elements by this value to get the absolute values you want

Checkerboard center and resizing in java

I wrote a checkerboard program (shown below). My problem is that I can't figure out how to center it with resize, and have it resize proportionately.
I added in a short statement. Int resize (shown below) I did something similiar with a previous program regarding a bullseye where I used a radius. I just haven't the slightest clue how to implement that in here.
import java.awt.*;
import javax.swing.JComponent;
public class CheckerboardComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
int s = 12;
int x = s;
int y = s;
// int resize = Math.min(this.getHeight(), this.getWidth()) / 8 ;
for (int i = 0; i < 8; i++) {
// one row
for (int j = 0; j < 8; j++) {
g2.fill(new Rectangle(x, y, 4 * s, 4 * s) );
x += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
x = s;
y += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
}
}
here is a viewer program
import javax.swing.*;
public class CheckersViewer {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(430, 450);
frame.setTitle("Checkerboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckerboardComponent component = new CheckerboardComponent();
frame.add(component);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Hmm... Here's one idea then, though it probably isn't a good one (I'm also not that good with jComponent and jFrame, so there's probably a better way and a more suited person)
I believe the component object has a built-in method called getSize(). If you can relate the size of the rectangle to the size of the window, then it could be resizable. Obviously there would be more code and arguments, but for example:
public void drawStuff(Component c)
{
...
Dimension size = c.getSize();
double RectWidth = (size.width)*(.05);
...
}
check this out for more complete examples:
http://www.javadocexamples.com/java/awt/Component/getSize().html
And I apologize I can't be of more help.

Java Graphics.fillPolygon: How to also render right and bottom edges?

When drawing polygons, Java2D leaves off the right and bottom edges. I understand why this is done. However, I would like to draw something that includes those edges. One thing that occurred to me was to follow fillPolygon with drawPolygon with the same coordinates, but this appears to leave a gap. (See the little triangular image at the bottom.) There are two possibilities, but I can't tell which. To enable antialiasing, I'm doing this:
renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
renderHints.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(renderHints);
One possibility is that the antialiasing is not being done on the alpha channel, so the gap is caused by overdraw. In that case, if the alpha channel were what was being antialiased, the edges would abut properly. The other possibility is that there is just a gap here.
How can I fix this?
Also, I'm not sure, but it appears that the polygon outline may actually be TOO BIG. That is, it may be going further out than the right and bottom edges that I want to include.
Thanks.
-- UPDATE --
Based on a very nice suggestion by Hovercraft Full of Eels, I have made a compilable example:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class polygon {
private static final int WIDTH = 20;
public static void main(String[] args) {
BufferedImage img = new BufferedImage(WIDTH, WIDTH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
int[] xPoints = {WIDTH / 3, (2*WIDTH) / 3, WIDTH / 3};
int[] yPoints = {0, WIDTH / 2, WIDTH};
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.green);
g2.drawLine(0, WIDTH-1, WIDTH, WIDTH-1);
g2.drawLine(0, 0, WIDTH, 0);
g2.drawLine(WIDTH/3, 0, WIDTH/3, WIDTH);
g2.drawLine((2*WIDTH/3), 0, (2*WIDTH/3), WIDTH);
g2.setColor(Color.black);
g2.drawPolygon(xPoints, yPoints, xPoints.length);
g2.setColor(Color.black);
g2.fillPolygon(xPoints, yPoints, xPoints.length);
g2.dispose();
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
JOptionPane.showMessageDialog(null, label);
}
}
If you leave the filled polygon red, you get the image below (zoomed by 500%), which shows that the polygon does not extend all the way to the right edge. That is, the vertical green line is corresponds to x=(2*WIDTH)/2, and although the red polygon includes that coordinate, it does not paint any pixels there.
To see the gap problem, I changed red in the program to black. In this image, you can see a subtle gap on the lower right side, where the outline drawn by drawPolygon does not quite meet up with what was drawn with fillPolygon.
Show us your code for your drawing in a simple compilable runnable program. For instance when I try to imitate your image and used RenderingHints, it seemed to produce an appropriate sized image with complete right/bottom edges:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Foo002 {
private static final int WIDTH = 20;
public static void main(String[] args) {
BufferedImage img = new BufferedImage(WIDTH, WIDTH,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
int[] xPoints = { WIDTH / 3, (2 * WIDTH) / 3, WIDTH / 3 };
int[] yPoints = { 0, WIDTH / 2, WIDTH };
g2.setColor(Color.black);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.fillPolygon(xPoints, yPoints, xPoints.length);
g2.dispose();
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
label.setBorder(BorderFactory.createLineBorder(Color.black));
JPanel panel = new JPanel();
panel.add(label);
JOptionPane.showMessageDialog(null, panel);
}
}
If you can show us a similar program that reproduces your problem, then we can give you better help.
I like the convenience of ImageIcon, shown by #HFOE, but this variation may make it a little easier to see what's happening. From the Graphics API,
Operations that draw the outline of a figure operate by traversing an
infinitely thin path between pixels with a pixel-sized pen that hangs
down and to the right of the anchor point on the path. Operations that
fill a figure operate by filling the interior of that infinitely thin
path.
In contrast, Graphics2D must follow more complex rules for antialiasing, which allow it to "draw outside the lines."
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/questions/7701097 */
public class PixelView extends JPanel {
private static final int SIZE = 20;
private static final int SCALE = 16;
private BufferedImage img;
public PixelView(Color fill) {
this.setBackground(Color.white);
this.setPreferredSize(new Dimension(SCALE * SIZE, SCALE * SIZE));
img = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
int[] xPoints = {SIZE / 3, (2 * SIZE) / 3, SIZE / 3};
int[] yPoints = {0, SIZE / 2, SIZE};
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.green);
g2.drawLine(0, SIZE - 1, SIZE, SIZE - 1);
g2.drawLine(0, 0, SIZE, 0);
g2.drawLine(SIZE / 3, 0, SIZE / 3, SIZE);
g2.drawLine((2 * SIZE / 3), 0, (2 * SIZE / 3), SIZE);
g2.setColor(Color.black);
g2.drawPolygon(xPoints, yPoints, xPoints.length);
g2.setColor(fill);
g2.fillPolygon(xPoints, yPoints, xPoints.length);
g2.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
private static void display() {
JFrame f = new JFrame("PixelView");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0));
f.add(new PixelView(Color.black));
f.add(new PixelView(Color.red));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
}
Sometimes "the graphics pen hangs down and to the right from the path it traverses", and sometimes it doesn't.
I don't have any clear idea how to predict when it will or won't, but I have observed that RenderingHints.VALUE_STROKE_PURE can sometimes be used to alter the behavior, by trial and error.
In particular, I found that if you turn on STROKE_PURE during your drawPolygon() calls in your program,
it will make them match up with your fillPolygon() calls, as you desire.
I did a little study showing the effect of the STROKE_CONTROL hint, which is one of:
STROKE_NORMALIZE (the default, on my system)
STROKE_PURE
on the following calls:
drawLine()
drawPolygon()
fillPolygon()
in both antialiasing modes:
ANTIALIASING_OFF
ANTIALIASING_ON
And there is one more annoying dimension that apparently matters as well:
rendered directly to a JComponent on the screen
rendered to a BufferedImage.
Here are the results when rendering directly to a visible JComponent:
And here are the results when rendering into a BufferedImage:
(Notice the two cases in which the two pictures differ, i.e. in which direct rendering differs from BufferedImage rendering:
ANTIALIAS_OFF/STROKE_NORMALIZE/fillPolygon and ANTIALIAS_OFF/STROKE_PURE/drawPolygon.)
Overall, there doesn't seem to be much rhyme or reason to the whole thing.
But we can make the following specific observations based on the above pictures:
Observation #1:
If you want your antialiased drawPolygon()s and antialiased fillPolygon()s to match up well
(the original question), then turn on STROKE_PURE during the antialiased drawPolygon() calls.
(It doesn't matter whether it's on during the antialiased fillPolygon() calls.)
Observation #2:
If you want your antialiased fillPolygon()s and non-antialiased fillPolygon()s
to match up (because, say, your app allows the user to switch antialiasing on and off,
and you don't want the picture to jump northwest and southeast each time they do that),
then turn on STROKE_PURE during the non-antialiased fillPolygon() calls.
Here is the program I used to generate the pictures above.
My results are from compiling and running it it with opensdk11 on linux;
I'd be interested to know if anyone gets any different results on different platforms.
/** Study the effect of STROKE_PURE. */
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
#SuppressWarnings("serial")
public final class AntiAliasingStudy {
// These can be fiddled with.
final static int patchWidth = 24; // keep this a multiple of 4 for sanity
final static int patchHeight = 20; // keep this a multiple of 4 for sanity
final static int borderThickness = 4;
final static int mag = 6;
// derived quantities
final static int totalWidth = 5*borderThickness + 4*patchWidth;
final static int totalHeight = 4*borderThickness + 3*patchHeight;
private static void drawLittleStudy(Graphics2D g2d,
int x00, int y00,
int patchWidth, int patchHeight, int borderThickness, int totalWidth, int totalHeight) {
g2d.setColor(new java.awt.Color(240,240,240));
g2d.fillRect(x00,y00,totalWidth, totalHeight);
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 4; ++col) {
int x0 = x00 + borderThickness + col*(patchWidth+borderThickness);
int y0 = y00 + borderThickness + row*(patchHeight+borderThickness);
int x1 = x0 + patchWidth;
int y1 = y0 + patchHeight;
g2d.setColor(java.awt.Color.WHITE);
g2d.fillRect(x0, y0, patchWidth, patchHeight);
boolean antialias = (col >= 2);
boolean pure = (col % 2 == 1);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antialias ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, pure ? RenderingHints.VALUE_STROKE_PURE : RenderingHints.VALUE_STROKE_NORMALIZE);
g2d.setColor(java.awt.Color.RED);
if (row == 0) {
// lines (drawLine)
// diagonals
g2d.drawLine(x0,y1, x1,y0);
g2d.drawLine(x0,y0, x1,y1);
// orthogonals
g2d.drawLine((x0+patchWidth/4),y0, (x0+patchWidth*3/4),y0);
g2d.drawLine((x0+patchWidth/4),y1, (x0+patchWidth*3/4),y1);
g2d.drawLine(x0,(y0+patchHeight/4), x0,(y0+patchHeight*3/4));
g2d.drawLine(x1,(y0+patchHeight/4), x1,(y0+patchHeight*3/4));
} else if (row == 1) {
// outlines (drawPolygon)
// A stopsign
g2d.drawPolygon(new int[] {x0+patchWidth/2-2, x0, x0, x0+patchWidth/2-2, x0+patchWidth/2+2, x1, x1, x0+patchWidth/2+2},
new int[] {y0, y0+patchHeight/2-2, y0+patchHeight/2+2, y1, y1, y0+patchHeight/2+2, y0+patchHeight/2-2, y0},
8);
} else if (row == 2) {
// fill (fillPolygon)
// A stopsign
g2d.fillPolygon(new int[] {x0+patchWidth/2-2, x0, x0, x0+patchWidth/2-2, x0+patchWidth/2+2, x1, x1, x0+patchWidth/2+2},
new int[] {y0, y0+patchHeight/2-2, y0+patchHeight/2+2, y1, y1, y0+patchHeight/2+2, y0+patchHeight/2-2, y0},
8);
}
}
}
} // drawLittleStudy
// Show a study, previously created by drawLittleStudy(), magnified and annotated.
private static void showMagnifiedAndAnnotatedStudy(Graphics g,
BufferedImage studyImage,
int x00, int y00,
int patchWidth, int patchHeight, int borderThickness, int totalWidth, int totalHeight, int mag,
ImageObserver imageObserver) {
// Magnify the image
g.drawImage(studyImage,
/*dst*/ x00,y00,x00+totalWidth*mag,y00+totalHeight*mag,
/*src*/ 0,0,totalWidth,totalHeight,
imageObserver);
// Draw annotations on each picture in black,
// in the highest quality non-biased mode
// (now that we know what that is!)
g.setColor(java.awt.Color.BLACK);
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 4; ++col) {
int x0 = borderThickness + col*(patchWidth+borderThickness);
int y0 = borderThickness + row*(patchHeight+borderThickness);
int x1 = x0 + patchWidth;
int y1 = y0 + patchHeight;
if (false) {
g.drawLine(x00+x0*mag,y00+y0*mag, x00+x1*mag,y00+y0*mag);
g.drawLine(x00+x1*mag,y00+y0*mag, x00+x1*mag,y00+y1*mag);
g.drawLine(x00+x1*mag,y00+y1*mag, x00+x0*mag,y00+y1*mag);
g.drawLine(x00+x0*mag,y00+y1*mag, x00+x0*mag,y00+y0*mag);
}
if (row == 0) {
// diagonals
g.drawLine(x00+x0*mag,y00+y1*mag, x00+x1*mag,y00+y0*mag);
g.drawLine(x00+x0*mag,y00+y0*mag, x00+x1*mag,y00+y1*mag);
// orthogonals
g.drawLine(x00+(x0+patchWidth/4)*mag,y00+y0*mag, x00+(x0+patchWidth*3/4)*mag,y00+y0*mag);
g.drawLine(x00+(x0+patchWidth/4)*mag,y00+y1*mag, x00+(x0+patchWidth*3/4)*mag,y00+y1*mag);
g.drawLine(x00+x0*mag,y00+(y0+patchHeight/4)*mag, x00+x0*mag,y00+(y0+patchHeight*3/4)*mag);
g.drawLine(x00+x1*mag,y00+(y0+patchHeight/4)*mag, x00+x1*mag,y00+(y0+patchHeight*3/4)*mag);
} else { // row 1 or 2
// A stopsign
g.drawPolygon(new int[] {x00+(x0+patchWidth/2-2)*mag, x00+x0*mag, x00+x0*mag, x00+(x0+patchWidth/2-2)*mag, x00+(x0+patchWidth/2+2)*mag, x00+x1*mag, x00+x1*mag, x00+(x0+patchWidth/2+2)*mag},
new int[] {y00+y0*mag, y00+(y0+patchHeight/2-2)*mag, y00+(y0+patchHeight/2+2)*mag, y00+y1*mag, y00+y1*mag, y00+(y0+patchHeight/2+2)*mag, y00+(y0+patchHeight/2-2)*mag, y00+y0*mag},
8);
}
}
}
FontMetrics fm = g.getFontMetrics();
{
String[][] texts = {
{"ANTIALIAS_OFF", "STROKE_NORMALIZE"},
{"ANTIALIAS_OFF", "STROKE_PURE"},
{"ANTIALIAS_ON", "STROKE_NORMALIZE"},
{"ANTIALIAS_ON", "STROKE_PURE"},
};
for (int col = 0; col < 4; ++col) {
int xCenter = borderThickness*mag + col*(patchWidth+borderThickness)*mag + patchWidth*mag/2;
{
int x = x00 + xCenter - fm.stringWidth(texts[col][0])/2;
int y = y00 + 3*(patchHeight+borderThickness)*mag + fm.getAscent();
g.drawString(texts[col][0], x,y);
x = xCenter - fm.stringWidth(texts[col][1])/2;
y += fm.getHeight();
g.drawString(texts[col][1], x,y);
}
}
}
{
String[] texts = {
"drawLine",
"drawPolygon",
"fillPolygon",
};
for (int row = 0; row < 3; ++row) {
int yCenter = y00 + borderThickness*mag + row*(patchHeight+borderThickness)*mag + patchHeight*mag/2;
int x = x00 + 4*(patchWidth+borderThickness)*mag + 10;
g.drawString(texts[row], x,yCenter);
}
}
} // showMagnifiedAndAnnotatedStudy
private static Dimension figureOutPreferredSize(FontMetrics fm) {
int preferredWidth = (totalWidth-borderThickness)*mag + 10 + fm.stringWidth("drawPolygon") + 9;
int preferredHeight = fm.getHeight() + totalHeight + (totalHeight-borderThickness)*mag + 2*fm.getHeight() + 2;
return new Dimension(preferredWidth, preferredHeight);
}
private static class IndirectExaminationView extends JComponent {
public IndirectExaminationView() {
setFont(new Font("Times", Font.PLAIN, 12));
setPreferredSize(figureOutPreferredSize(getFontMetrics(getFont())));
}
#Override public void paintComponent(Graphics g) {
FontMetrics fm = g.getFontMetrics();
g.setColor(java.awt.Color.BLACK);
g.drawString("through BufferedImage:", 0,fm.getAscent());
// The following seem equivalent
java.awt.image.BufferedImage studyImage = new java.awt.image.BufferedImage(totalWidth, totalHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB);
//java.awt.image.BufferedImage studyImage = (BufferedImage)this.createImage(totalWidth, totalHeight);
drawLittleStudy(studyImage.createGraphics(),
0,0,
patchWidth, patchHeight, borderThickness, totalWidth, totalHeight);
Graphics2D studyImageGraphics2D = studyImage.createGraphics();
g.drawImage(studyImage,
/*dst*/ 0,fm.getHeight(),totalWidth,fm.getHeight()+totalHeight,
/*src*/ 0,0,totalWidth,totalHeight,
this);
showMagnifiedAndAnnotatedStudy(g, studyImage,
0,fm.getHeight()+totalHeight,
patchWidth, patchHeight, borderThickness, totalWidth, totalHeight, mag, this);
}
} // DirectExaminationView
private static class DirectExaminationView extends JComponent {
public DirectExaminationView() {
setFont(new Font("Times", Font.PLAIN, 12));
setPreferredSize(figureOutPreferredSize(getFontMetrics(getFont())));
}
private BufferedImage imgFromTheRobot = null;
#Override public void paintComponent(Graphics g) {
final FontMetrics fm = g.getFontMetrics();
g.setColor(java.awt.Color.BLACK);
g.drawString("direct to JComponent:", 0,fm.getAscent());
drawLittleStudy((Graphics2D)g,
0,fm.getHeight(),
patchWidth, patchHeight, borderThickness, totalWidth, totalHeight);
if (imgFromTheRobot != null) {
System.out.println(" drawing image from robot");
showMagnifiedAndAnnotatedStudy(g, imgFromTheRobot,
0, fm.getHeight()+totalHeight,
patchWidth, patchHeight, borderThickness, totalWidth, totalHeight, mag, this);
imgFromTheRobot = null;
} else {
System.out.println(" scheduling a robot");
g.drawString("*** SCREEN CAPTURE PENDING ***", 0, fm.getHeight()+totalHeight+fm.getHeight()+fm.getHeight());
// Most reliable way to do it seems to be to put it on a timer after a delay.
Timer timer = new Timer(1000/2, new ActionListener() {
#Override public void actionPerformed(ActionEvent ae) {
System.out.println(" in timer callback");
Robot robot;
try {
robot = new Robot();
} catch (AWTException e) {
System.err.println("caught AWTException: "+e);
throw new Error(e);
}
Point myTopLeftOnScreen = getLocationOnScreen();
Rectangle rect = new Rectangle(
myTopLeftOnScreen.x, myTopLeftOnScreen.y + fm.getHeight(),
totalWidth,totalHeight);
BufferedImage img = robot.createScreenCapture(rect);
imgFromTheRobot = img;
repaint();
System.out.println(" out timer callback");
}
});
timer.setRepeats(false);
timer.start();
}
}
} // DirectExaminationView
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override public void run()
{
final JFrame directFrame = new JFrame("direct to JComponent") {{
getContentPane().add(new DirectExaminationView());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocation(0,0);
setVisible(true);
}};
new JFrame("through BufferedImage") {{
getContentPane().add(new IndirectExaminationView());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocation(directFrame.getWidth(),0);
setVisible(true);
}};
}
});
}
} // class AntiAliasingStudy

Draw a circle with a radius and points around the edge

I'm really stuck on how to go about programming this. How to draw a circle in Java with a radius and points around the edge?
I need to draw a circle within a JFrame with a radius and points around the circumference. i can mathematically calculate how to find the coordinates of the point around the edge but i cant seem to be able to program the circle. I am currently using a Ellipse2D method but that doesn't seem to work and doesn't return a radius, as under my understanding, it doesn't draw the circle from the center rather from a starting coordinate using a height and width.
My current code is on a separate frame but I need to add it to my existing frame.
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
public class circle extends JFrame {
public circle() {
super("circle");
setSize(410, 435);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Panel sp = new Panel();
Container content = getContentPane();
content.add(sp);
setContentPane(content);
setVisible(true);
}
public static void main (String args[]){
circle sign = new circle();
}
}
class Panel extends JPanel {
public void paintComponent(Graphics comp) {
super.paintComponent(comp);
Graphics2D comp2D = (Graphics2D) comp;
comp2D.setColor(Color.red);
Ellipse2D.Float sign1 = new Ellipse2D.Float(0F, 0F, 350F, 350F);
comp2D.fill(sign1);
}
}
Points on a circle may be specified as a function of the angle θ:
x = a + r cos(θ)
y = b + r sin(θ)
Here, increments of 2π/8 are shown.
Addendum: As suggested in a comment by #Christoffer Hammarström, this revised example reduces the number of magic numbers in the original. The desired number of points becomes a parameter to the constructor. It also adapts the rendering to the container's size.
/** #see https://stackoverflow.com/questions/2508704 */
public class CircleTest extends JPanel {
private static final int SIZE = 256;
private int a = SIZE / 2;
private int b = a;
private int r = 4 * SIZE / 5;
private int n;
/** #param n the desired number of circles. */
public CircleTest(int n) {
super(true);
this.setPreferredSize(new Dimension(SIZE, SIZE));
this.n = n;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.black);
a = getWidth() / 2;
b = getHeight() / 2;
int m = Math.min(a, b);
r = 4 * m / 5;
int r2 = Math.abs(m - r) / 2;
g2d.drawOval(a - r, b - r, 2 * r, 2 * r);
g2d.setColor(Color.blue);
for (int i = 0; i < n; i++) {
double t = 2 * Math.PI * i / n;
int x = (int) Math.round(a + r * Math.cos(t));
int y = (int) Math.round(b + r * Math.sin(t));
g2d.fillOval(x - r2, y - r2, 2 * r2, 2 * r2);
}
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new CircleTest(9));
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
}
Try something like this:
public class CirclePanel extends JPanel
{
public static void main(String[] args) throws Exception
{
JFrame f = new JFrame();
f.setContentPane(new CirclePanel());
f.setSize(700,500);
f.setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g);
//Draws the line
g.drawOval(0,0,this.getWidth(), this.getHeight());
//draws filled circle
g.setColor(Color.red);
g.fillOval(0,0,this.getWidth(), this.getHeight());
}
}
You can also override the paint method in the frame class, but then the you would have to calculate in the size of the window decorations and it gets dirty there...
I recommend to take some time to review the "midpoint circle algorithm or Bresenham's circle algorithm". The accepted solution is based on very costly math operations like float multiplication and trigonometric functions.

Categories

Resources