Super newbie here. I am trying to draw a Triangle on top of the Rectangles I draw but it does not appear. I know it is there because when I remove the 2 Rectangles and change the color to Yellow or something, it appears. I also need to put stars and sun on top of the Triangle... and yes it is a flag. I am not asking for the exact code. Hints for newbies will be appreciated. Please help!
import java.awt.*;
import java.awt.Polygon;
import java.awt.Graphics;
import javax.swing.*;
public class FlagShapes extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.WHITE);
//triangle of the flag
int[] xPoints={75, 75, 130};
int[] yPoints={75, 185, 130};
int nPoints=3;
g.setColor(Color.WHITE);
g.fillPolygon(xPoints, yPoints, nPoints);
//blue part of the flag
g.setColor(Color.BLUE);
g.fillRect(75, 75, 200, 55);
//red part of the flag
g.setColor(Color.RED);
g.fillRect(75, 130, 200, 55);
//pole drawing
g.setColor(Color.BLACK);
g.fillRect(72, 75, 2, 300);
}
}
So I found out the answer to my question (thanks Yahoo) Java's default rendering approach uses rasterisation. Just draw the two shapes in the same location Java will draw both even if they overlap. Whichever one is drawn first will be 'under' whichever one is drawn second.
Related
I'm currently working on a project with the theme of earth hour, and we are only allowed to use rectangles, circles and triangles. Here's the image i'm tring to create (not exactly, mine will be much more simplified!):
https://www.google.com/search?q=earth+hour&biw=1366&bih=586&source=lnms&tbm=isch&sa=X&ved=0ahUKEwj__5H0vtvQAhXLrlQKHTi8BagQ_AUIBygC#imgrc=fQkBxn0a8LnwbM%3A
(not sure if you could see the link)
But when i'm coding it, i'm running into trouble to rotate those rectangles to stand on the tangent line of the circle. I'm a student just learnt some basics of java, like loops and arrays. So my quesiton is that if there's some understandable way that doesn't involve some complex and exotic methods that could rotate those rectangles? I know it will probably involve some complicated solutions that is beyond my knowledge. But any help is much appreciated.
this is part of the code that i build the building standing perpendicularly to the circle(earth):
// create mid buildings
Color blc = new Color(0, 0, 0);
Rectangle midBld = new Rectangle(240, 220, 20, 40, blc);
midBld.draw(g);
Rectangle midBld1 = new Rectangle(242, 190, 16, 30, blc);
midBld1.draw(g);
Triangle midBld2 = new Triangle(250, 160, 8, 30, blc);
midBld2.draw(g);
Triangle midBld3 = new Triangle(250, 160, -8, 30, blc);
midBld3.draw(g);
A Rectangle cannot be rotated, its edges are always in parallel to the axis. But you can rotate and translate the coordinate system in witch you draw the shapes. From Graphics2D API doc.
All coordinates passed to a Graphics2D object are specified in a device-independent coordinate system called User Space, which is used by applications. The Graphics2D object contains an AffineTransform object as part of its rendering state that defines how to convert coordinates from user space to device-dependent coordinates in Device Space.
Graphics2D also provide two methods that are useful in this task: translate that moves the origin of the coordinates and rotate that, well, rotates the system.
package graphics;
import javax.swing.*;
import java.awt.*;
/**
* Earth Hour
*/
public class RotateRect extends JFrame {
private static final int WIDTH = 400;
private static final int HEIGHT = 400;
public RotateRect() {
this.setSize(WIDTH, HEIGHT);
this.setTitle("Rotate Rectangles");
this.setContentPane(new JPanel() {
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Background: White
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
// Draw "Earth": Center(200, 400), Radius=200
g2.setColor(Color.BLACK);
g2.fillOval(0, 200, 400, 400);
// Move origin to center of the canvas (surface of earth)
g2.translate(200, 200);
// Rotate the coordinate system, relative to the center of earth.
// note x, y are in the translated system
// Transforms are accumulative
g2.rotate(-Math.PI/6, 0, 200);
// Fill a rectangle with top-left corner at (-20, 80) in the rotated system
// It's important to make the rectangle symmetrical to the y-axis, otherwise the building looks
// funny.
// Also, make the building "sunk" a little, so that it's fully on the ground.
g2.fillRect(-20, -80, 40, 100);
g2.rotate(Math.PI/3, 0, 200);
g2.fillRect(-20, -80, 40, 100);
g2.rotate(-Math.PI/6, 0, 200);
g2.fill(new Rectangle(-20, -80, 40, 100));
}
});
}
public static void main(String [] args) {
RotateRect rr = new RotateRect();
rr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EventQueue.invokeLater(()->rr.setVisible(true));
}
}
It seems that stroking on sub-pixel coordinates became broken in Java 8.
I have three sets of cases, shown on screenshots (columns represent cases, rows represent different stroke widths) :
Java 7u51 (400% scale)
Java 8u60 (400% scale)
Fill and stroke on the same coordinates. Works as intended, stroked area is larger than the filling area.
Stroking is shrunk (by stroke width) and centered (by half of the width) to be inside bounds of the filling region. This part is broken in Java 8 for 1px stroke, where painting occurs on a sub-pixel coordinate (first row); 3px stroke doesn't have this problem (third row). It seems that 0.5 is rounded up for the 1px stroke.
Filling rectangle is shrunk an centered the same way of case 2. I need this on graphics, which support sub-pixel drawing, to make non-overlapping fill when cells are overlapping. Here you can see that fill operation rounds down 0.5 to 0, so it's only stroking problem.
The code is below:
import static java.awt.BasicStroke.*;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class TestCase
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Test case");
frame.setSize(115, 115);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new TestPanel());
frame.setVisible(true);
}
private static class TestPanel extends JPanel
{
TestPanel()
{
setOpaque(true);
}
#Override
protected void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
g2.fill(getBounds());
Rectangle2D rect = new Rectangle2D.Double();
Color background = new Color(0, 255, 255);
Color border = new Color(255, 0, 0, 128);
Stroke STROKE_1PX = new BasicStroke(1, CAP_SQUARE, JOIN_MITER);
Stroke STROKE_2PX = new BasicStroke(2, CAP_SQUARE, JOIN_MITER);
Stroke STROKE_3PX = new BasicStroke(3, CAP_SQUARE, JOIN_MITER);
g2.translate(10, 10);
/**
* Filling and stroking by original coordinates
*/
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_1PX);
g2.draw(rect);
g2.translate(0, 35);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_2PX);
g2.draw(rect);
g2.translate(0, 35);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_3PX);
g2.draw(rect);
/**
* Stroking is shrunk to be inside the filling rect
*/
g2.translate(35, -70);
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
rect.setRect(0.5, 0.5, 24, 24);
g2.setColor(border);
g2.setStroke(STROKE_1PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
rect.setRect(1, 1, 23, 23);
g2.setColor(border);
g2.setStroke(STROKE_2PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(0, 0, 25, 25);
g2.setColor(background);
g2.fill(rect);
rect.setRect(1.5, 1.5, 22, 22);
g2.setColor(border);
g2.setStroke(STROKE_3PX);
g2.draw(rect);
/**
* Filling rect is additionally shrunk and centered
*/
g2.translate(35, -70);
rect.setRect(0.5, 0.5, 24, 24);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_1PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(1, 1, 23, 23);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_2PX);
g2.draw(rect);
g2.translate(0, 35);
rect.setRect(1.5, 1.5, 22, 22);
g2.setColor(background);
g2.fill(rect);
g2.setColor(border);
g2.setStroke(STROKE_3PX);
g2.draw(rect);
}
}
}
As I tested, Java 7 doesn't have this problem (tried on 7u51), Windows (8u77) and Mac (8u60) too. Tried on Ubuntu (8u60 and 8u77) and Linux Mint (8u60) on different machines and the bug was here.
Did anyone faced such issue? Is there any general workaround?
I cannot simply handle 1px case in places where stroking is used. It's because there is a lot of places and I'm working with different Graphics2D implementations and it seems, that from what I've used the issue reproduces only on SunGraphics2D. This means I need to use instanceOf in these places to not break common logic.
From bug report discussion:
It is an xrender bug -Dsun.java2d.xrender=false cures it.
I haven't checked this solution myself as I didn't received any notifications from bug reporting system besides that it was reviewed. And as it was Linux-only problem it was decided to wait for official fixes as there was not so many Linux users among our customers.
I would suggest you extend Graphics2D and add correctional measures there on the places where needed.
That way you can keep your main flow consistent, and add all other "logic" errors can be handled where they need to be handled.
This saves you the overhead of modifying N files and undoing those changes if it gets fixed, and keeping the logic where it should be.
Okay I was wondering three things so right now my house background is white how do I make it part blue and green for the grass bottom part. Also my line is going downward how do I make go up toward northeast to make the triangle for the ceiling of the house? Last thing what about adding a tree do I make a bunch of arcs to get the "bush curviness" of the tree?
import java.awt.Color;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Polygon;
public class House extends Canvas {
public House() {
setBackground(Color.WHITE);
}
public void paint(Graphics window) {
window.setColor(Color.BLUE);
window.drawRect(250, 300, 50, 125);
window.fillRect(350, 300, 50, 135);
window.setColor(Color.PINK);
window.drawRect(200, 150, 350, 300);
window.fillRect(200, 150, 350, 300);
window.setColor(Color.GREEN);
Polygon poly = new Polygon();
poly.addPoint(100, 200);
poly.addPoint(200, 400);
poly.addPoint(300, 200);
window.fillPolygon(poly);
}
}
how do I make it part blue and green for the grass bottom part
Don't use "magic" numbers, use absolute known values, like getWidth and getHeight, for example:
window.setColor(Color.BLUE);
window.fillRect(0, 0, getWidth(), getHeight() / 2);
window.setColor(Color.GREEN);
window.fillRect(0, getHeight() / 2, getWidth(), getHeight() / 2);
Also my line is going downward how do I make go up toward northeast to make the triangle for the ceiling of the house?
It's doing exactly what you told it to, remember, the top/left corner is 0x0, meaning coordinates increase in size as the move right/down
Polygon poly = new Polygon();
poly.addPoint(100, 200);
poly.addPoint(200, 100);
poly.addPoint(300, 200);
Last thing what about adding a tree do I make a bunch of arcs to get the "bush curviness" of the tree?
You could just use a series of over lapping ovals, using Graphics#fillOval or Graphics#drawArc
I would strongly recommend that you have a look at 2D Graphics for techniques and ideas when using Graphics.
I'd also encourage you to have a look at Painting in AWT and Swing and Performing Custom Painting to understand how painting actually works in AWT/Swing
Hi I've searched the web for a while but the solves I've encountered don't work for me. So here's my issue:
I'm making some graphs on my GUI by using Graphics and drawLine(), which works perfectly fine for me - the first time. When I tell my program to redraw another graph on the same area it just messes things up.
public void paintComponent(Graphics g) {
super.paintComponent(g);
int max = 100;
g.clearRect(0, 0, 205, 200); <--
g.drawRect(10, 10, 200, 200);
g.drawString(""+max, 0, 10);
g.drawLine(5, 110, 10, 110);
g.drawString("0", 0, 275);
...Drawing the actual graph here...
}
Now the idea was that everytime I draw this I first lay out a white surface, so it removes anything drawn earlier. But it doesn't work.
I'm quite new to Graphics so please don't hesitate to comment if I'm doing it completely wrong.
Thanks in advance.
-Alex
(this is java) I have an oval, representing a unit. I want the colour of the oval to represent the unit's health. So a perfectly healthy unit will be all green. and with the unit's health decreasing the oval starts filling with red from the bottom. so, on 50% health the oval would be red in bottom half and green in the top half, and fully red when the unit's dead.
I'm sure the solution here must be obvious and trivial , but I just can't see it.
thanks a lot
You can draw a red oval in the background, then draw a green intersection of an oval and a rectangle, where the rectangle starts below the oval, then moves further to the top to reveal more of the red oval beneath.
You might like to read up on how to construct complex shapes out of primitives here
Override the paint method something like this:
public void paint(Graphics graphics)
{
super.paint(graphics);
Rectangle originalClipBounds = graphics.getClipBounds();
try
{
graphics.clipRect(100, 100, 100, 25);
graphics.setColor(Color.RED);
graphics.fillOval(100, 100, 100, 100);
}
finally
{
graphics.setClip(originalClipBounds);
}
try
{
graphics.clipRect(100, 125, 100, 75);
graphics.setColor(Color.BLUE);
graphics.fillOval(100, 100, 100, 100);
}
finally
{
graphics.setClip(originalClipBounds);
}
}
Might want to enhance it with some double buffering but you get the gist.
You can set the clip on the graphics when you draw the green. Only things within the clip actually get painted.
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setColor(Color.RED);
g2d.fillOval(10, 10, 200, 100);
g2d.setColor(Color.GREEN);
g2d.setClip(10, 10, 200, 50);
g2d.fillOval(10, 10, 200, 100);
}