How to draw horizontal lines between those four lines and have same space between them like on image.
DrawPanel.java:
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int pieces = 5;
g.drawLine(0, height/2, width/2, 0);
g.drawLine(width/2, 0, width, height/2);
g.drawLine(0, height, width/2, height/2);
g.drawLine(width/2, height/2, width, height);
for (int i = 0; i < pieces; i++) {
int y = height * i/pieces;
if (y > height / 2)
g.drawLine(0, y, width / 2, y);
}
}
}
DrawPanelTest.java:
import javax.swing.JFrame;
public class DrawPanelTest {
public static void main(String[] args) {
DrawPanel panel = new DrawPanel();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(1280,720);
application.setVisible(true);
}
}
What i've got so far:
how to make those lines in bottom left corner fit between lines not in the for loop (something like show above)?
You could draw the bottom triangle to overwrite the lines, or you can calculate the distance away from the center that you need to start/end drawing the lines.
Since we know the height and width of the triangle (half the pyramid) you can calculate the top angle. Once you know the top angle, you can use that to calculate the width of the bottom side at each iteration of the line.
public class PyramidLinesTest {
public static void main(String[] args) {
DrawPanel panel = new DrawPanel();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize(1280,720);
application.setVisible(true);
}
static class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int pieces = 5;
drawPyramids(g, width, height);
drawLines(g, width, height, pieces);
}
private void drawPyramids(Graphics g, int width, int height) {
g.drawLine(0, height/2, width/2, 0);
g.drawLine(width/2, 0, width, height/2);
g.drawLine(0, height, width/2, height/2);
g.drawLine(width/2, height/2, width, height);
}
private void drawLines(Graphics g, int width, int height, int pieces) {
// Determine the size of the side and bottom (adjacent and opposite)
double halfY = height / 2;
double halfW = width / 2;
// Tan = O / A
// Tan = halfW / halfY
double tanTheta = halfW / halfY;
double theta = Math.atan(tanTheta); // Radians Math.toDegrees()
double dist = halfY / pieces;
for (int i = 0; i < pieces; i++) {
// Start at halfY and move down by I distance
int y = (int) (halfY + (i * dist));
// Calculate the distance away from halfX using theta
// tan(theta) = O / A
// O = tan(theta) * A
int fromHalfW = (int) (Math.tan(theta) * (i * dist));
// Draw the lines accordingly
g.drawLine(0, y, (int) (halfW - fromHalfW), y);
g.drawLine((int) (halfW + fromHalfW), y, width, y);
}
}
}
}
I would like to draw a line above a text in Java. I use Graphics and here is my code :
String s = a.getSequent().toString();
FontMetrics fm = getFontMetrics(getFont());
int textHeight = fm.getHeight();
int textWidth= fm.stringWidth(s);
//Text
g.drawString( s,
(int) ((jPanelWidth- textWidth) / 2),
(int) ((jPanelHeight- textHeight ) / 2));
//Draw line
int x1 = (jPanelWidth- textWidth) / 2;
int x2 = x1 + textWidth; //Problem
int y1 = (jPanelHeight- textHeight *4) / 2;
int y2 = y1;
g.drawLine(x1, y1, x2, y2);
Here is what I have :
I don't understand why the line don't have the same length as my text. The problem is on the value of x2, but why ? Could you help me ?
One of the more obscure concepts to come to grips with is understanding how text is actually rendered.
Rather than been rendered from x/y position down, text is rendered from the baseline up.
This means that the x/y position actually represents the baseline ... just take some time to read that again and if that doesn't help, have a read of Measuring Text
The basic concept is, you want take the x/y position, which represents the baseline and then subtract the ascent
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
String text = "This is a test";
FontMetrics fm = g2d.getFontMetrics();
int textHeight = fm.getHeight();
int textWidth = fm.stringWidth(text);
int xPos = (getWidth() - textWidth) / 2;
int yPos = ((getHeight() - textHeight) / 2) + fm.getAscent();
g2d.setColor(Color.BLACK);
g2d.drawString(text, xPos, yPos);
g2d.drawLine(xPos, yPos - fm.getAscent(), xPos + textWidth, yPos - fm.getAscent());
g2d.dispose();
}
}
}
As #luk2302 said, here is the solution :
I had : FontMetrics fm = getFontMetrics(getFont());
Now I have : FontMetrics fm = getFontMetrics(g.getFont());
I didn't use the right font.
I have created Star shape using drawPolygon() but I want to rotate it from the center point of the star as well as from center of the screen.
Here is my code to rotate star from its center:
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform origX = g2d.getTransform();
AffineTransform newX = (AffineTransform) origX.clone();
newX.rotate(Math.toRadians(angle), x, y + 62); // Rotate about center of the star
g2d.setTransform(newX);
g2d.drawPolygon(starX, starY, 5);
g2d.dispose();
g.dispose();
}
If i replace:
newX.rotate(Math.toRadians(angle), x, y + 62);
to
newX.rotate(Math.toRadians(angle), this.getWidth() / 2, this.getHeight() / 2);
I can able to rotate it from center of the screen.
However, I want to achieve both the effects simultaneously.
i.e.: Like the earth which rotate around the sun as well as its own axis.
I have tried creating another AffineTransform object but it overwrite the previous one when I set it using g2d.setTransform(newObj);
Any suggestions will be extremely helpful.
Thank you.
Here is my complete code if you want to see
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
public class Star extends Applet implements Runnable{
private int[] starX;
private int[] starY;
private Thread mainThread;
private int x;
private int y;
private int angleFromCenterShape;
#Override
public void init() {
this.setSize(800, 480);
x = 250;
y = 150;
angleFromCenterShape = 0;
starX = new int[5];
starY = new int[5];
mainThread = new Thread(this);
mainThread.start();
this.setBackground(Color.BLACK);
}
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform origX = g2d.getTransform();
AffineTransform newX = (AffineTransform) origX.clone();
newX.rotate(Math.toRadians(angleFromCenterShape), x, y + 65); //Rotate about center of the star
g2d.setTransform(newX);
g2d.setColor(Color.red);
g2d.fillPolygon(starX, starY, 5);
g2d.dispose();
g.dispose();
}
#Override
public void run() {
while(true){
angleFromCenterScreen = (angleFromCenterScreen + 1) % 360; // angle loop from 0 to 36o
initStar();
try{
Thread.sleep(30);
}catch(Exception e){}
repaint();
}
}
private void initStar(){
starX[0] = x;
starX[1] = x - 50;
starX[2] = x + 75;
starX[3] = x - 75;
starX[4] = x + 50;
starY[0] = y;
starY[1] = y + 130;
starY[2] = y + 50;
starY[3] = y + 50;
starY[4] = y + 130;
}
}
I have found a workaround for my problem but it is not an exact solution.
However adding another rotate() on the same AffineTransform object mimic the 2 rotations
Here is the code
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform origX = g2d.getTransform();
AffineTransform newX = (AffineTransform) origX.clone();
newX.rotate(Math.toRadians(angle), this.getWidth() / 2, this.getHeight() / 2); // Rotate from the center of screen
newX.rotate(Math.toRadians(angle), x, y + 65); // Rotate from the center of the shape
g2d.setTransform(newX);
g2d.setColor(Color.red);
g2d.fillPolygon(starX, starY, 5);
g2d.dispose();
g.dispose();
}
I can print any component smartly with a footer by this code. Its working smartly.
public class MultiPagePrintable implements Printable {
private JComponent component;
private int lastPage = 0;
private double yOffset;
private Font footerFont;
public MultiPagePrintable(JComponent component) {
this.component = component;
footerFont = new Font("Arial", Font.BOLD, 24);
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
int result = NO_SUCH_PAGE;
String name = "I be mighty!";
String page = Integer.toString(pageIndex);
FontMetrics fm = graphics.getFontMetrics(footerFont);
double footerHeight = fm.getHeight() + 4;
double height = pageFormat.getImageableHeight() - footerHeight;
component.setSize(component.getPreferredSize());
if (lastPage != pageIndex) {
lastPage = pageIndex;
yOffset = height * pageIndex;
if (yOffset > component.getHeight()) {
yOffset = -1;
}
}
if (yOffset >= 0) {
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate((int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY());
g2d.translate(0, -yOffset);
component.printAll(g2d);
g2d.translate(0, +yOffset);
Shape footerArea = new Rectangle2D.Double(0, height, pageFormat.getImageableWidth(), footerHeight);
g2d.setColor(Color.WHITE);
g2d.fill(footerArea);
g2d.setColor(Color.RED);
g2d.draw(footerArea);
g2d.setColor(Color.BLACK);
g2d.translate(0, (pageFormat.getImageableHeight() - footerHeight));
float x = 2;
float y = (float)((footerHeight - fm.getHeight()) / 2d);
g2d.drawString(name, x, y + fm.getAscent());
x = (float)(pageFormat.getImageableWidth() - fm.stringWidth(page) - 2);
g2d.drawString(page, x, y + fm.getAscent());
g2d.dispose();
result = PAGE_EXISTS;
}
return result;
}
}
But problem is, it can't scale component width to fit page. However i don't want to fit height. Because this code can already print multiple page. and i need it.
You want to scale the Graphics2D:
g2d.translate(0, -yOffset);
double width = pageFormat.getImageableWidth();
double scale = Math.min(width / component.getWidth(),
height / component.getHeight());
if (scale < 1) {
AffineTransform oldTransform = g2d.getTransform();
g2d.scale(scale, scale);
component.printAll(g2d);
g2d.setTransform(oldTransform);
} else {
component.printAll(g2d);
}
g2d.translate(0, +yOffset);
I'm not sure what you mean by "I don't want to fit height" but you can always ignore the height, if you want:
g2d.translate(0, -yOffset);
double width = pageFormat.getImageableWidth();
double scale = width / component.getWidth();
if (scale < 1) {
AffineTransform oldTransform = g2d.getTransform();
g2d.scale(scale, scale);
component.printAll(g2d);
g2d.setTransform(oldTransform);
} else {
component.printAll(g2d);
}
g2d.translate(0, +yOffset);
I am trying to draw a circle in side a square and having multiple square circles in java. I am almost done but my output isn't coming out as I wanted to. The picture is what I am trying to do but it's not working out.
Here is my code:
a.awt.*;
public class SquaredCircles {
public static final int WIDTH=400;
public static final int HEIGHT=400;
public static void main (String[] args) {
DrawingPanel panel = new DrawingPanel(WIDTH,HEIGHT);
Graphics g = panel.getGraphics ();
panel.setBackground(new Color(0, 255, 255 ) );
int x = 0;
int y = 0;
int size = 100;
int rows = 5;
int numSquares = 1;
drawManySquares ( g, numSquares, x, y, size, rows );
x = 10;
y = 120;
size = 24;
rows = 4;
numSquares = 4;
drawManySquares( g, numSquares, x, y, size, rows );
x = 150;
y = 20;
size = 40;
rows = 6;
numSquares = 5;
drawManySquares( g, numSquares, x, y, size, rows );
x = 130;
y = 275;
size = 36;
rows = 3;
numSquares = 3;
drawManySquares( g, numSquares, x, y, size, rows );
}
public static void drawManySquares( Graphics g, int numSquares, int x, int y, int size, int rows ) {
for ( int i = 0; i < numSquares; i++ ) {
for ( int j = 0; j < numSquares; j++ ) {
drawOneSquare( g, x + i size, y + j size, size, rows );
}
}
}
public static void drawOneSquare( Graphics g, int x, int y, int size, int rows ) {
g.setColor ( Color.GREEN);
g.fillRect(x , y, size, size);
g.setColor ( Color.YELLOW);
g.fillOval ( x, y, size, size);
g.setColor ( Color.BLACK);
g.drawLine(size / 2, x, size / 2, size);
g.setColor ( Color.BLACK);
g.drawLine(x, size / 2, size, size / 2);
for (int i = 0; i <= rows; i = i + 1) {
g.setColor ( Color.BLACK);
g.drawOval(x + (i* (size/rows)), y+ (i*(size/rows)), size - (i*(size/rows +10 )) , size - (i*(size/rows +10)));
}
}
}
Start by having a look at Painting in AWT and Swing and Performing Custom Painting to see how painting should be done in Swing
Break down your problem into manageable chunks. The first thing you need to be able to do is paint a circle of a given size at a specific location, something like
public void paintCircleAt(Graphics2D g2d, int radius, int centerX, int centerY, Color stroke, Color fill) {
Ellipse2D.Double circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
g2d.setColor(fill);
g2d.fill(circle);
g2d.setColor(stroke);
g2d.draw(circle);
}
So, this allows you to paint a circle of a given radius around the center points of x/y filled and outlined with the specified color, pretty simple.
Now, you need someway to paint a series of circles around the same center point, something like...
public void paintCirclesIn(Graphics2D g2d, int count, int radius, int centerX, int centerY, Color stroke, Color fill) {
System.out.println(radius + "; " + centerX + "; " + centerY);
int delta = radius / count;
int innerRadius = radius;
for (int index = 0; index < count; index++, innerRadius -= delta) {
paintCircleAt(g2d, innerRadius, centerX, centerY, stroke, fill);
}
}
Okay, this basically calculates the difference (delta) between each circle and the paints that many circles with that much difference in their radius from the previous one. Because of the way the painting is done, we start with the outer circle and paint in.
And finally, we need someway to paint a square and circles, something like...
public void paintCirclesInSquare(Graphics2D g2d, int count, int x, int y, int width, int height, Color squareStroke, Color squareFill, Color circleStroke, Color circleFill) {
int centerX = x + (width / 2);
int centerY = y + (height / 2);
int radius = Math.min(centerX, centerY);
Rectangle2D box = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(squareFill);
g2d.fill(box);
g2d.setColor(squareStroke);
g2d.draw(box);
paintCirclesIn(g2d, count, radius, centerX, centerY, circleStroke, circleFill);
g2d.drawLine(centerX, y, centerX, y + height);
g2d.drawLine(x, centerY, x + width, centerY);
}
This, again, simply reuses the existing code we already have and adds to it, painting the square, the circles in the square and finally the lines.
Now, from here, you could write a method which took the number of columns/rows you wanted, the x/y position to start from, the size of each of square, the number of circles you need and the colors and reuse this functionality, but I'll leave that up to you ;)
Runnable example for you to play with...
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 java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CirclesAndSquares {
public static void main(String[] args) {
new CirclesAndSquares();
}
public CirclesAndSquares() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#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 x = getWidth() / 2;
int y = getHeight() / 2;
// paintCircleAt(g2d, Math.min(x, y), y, y, Color.BLACK, Color.YELLOW);
// paintCirclesIn(g2d, 5, Math.min(x, y), x, y, Color.BLACK, Color.YELLOW);
paintCirclesInSquare(g2d, 5, 0, 0, getWidth() - 1, getHeight() - 1, Color.BLACK, Color.GREEN, Color.BLACK, Color.YELLOW);
g2d.dispose();
}
public void paintCirclesInSquare(Graphics2D g2d, int count, int x, int y, int width, int height, Color squareStroke, Color squareFill, Color circleStroke, Color circleFill) {
int centerX = x + (width / 2);
int centerY = y + (height / 2);
int radius = Math.min(centerX, centerY);
Rectangle2D box = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(squareFill);
g2d.fill(box);
g2d.setColor(squareStroke);
g2d.draw(box);
paintCirclesIn(g2d, count, radius, centerX, centerY, circleStroke, circleFill);
g2d.drawLine(centerX, y, centerX, y + height);
g2d.drawLine(x, centerY, x + width, centerY);
}
public void paintCirclesIn(Graphics2D g2d, int count, int radius, int centerX, int centerY, Color stroke, Color fill) {
System.out.println(radius + "; " + centerX + "; " + centerY);
int delta = radius / count;
int innerRadius = radius;
for (int index = 0; index < count; index++, innerRadius -= delta) {
paintCircleAt(g2d, innerRadius, centerX, centerY, stroke, fill);
}
}
public void paintCircleAt(Graphics2D g2d, int radius, int centerX, int centerY, Color stroke, Color fill) {
Ellipse2D.Double circle = new Ellipse2D.Double(centerX - radius, centerY - radius, radius * 2, radius * 2);
g2d.setColor(fill);
g2d.fill(circle);
g2d.setColor(stroke);
g2d.draw(circle);
}
}
}