Java graphics fill doesn't paint over graphics draw? - java

If you run the code below, you will see that there is a red square with a blue line along the bottom and right edges of the square. However, as you can see in the code, the parameters for the rectangle being drawn are the same as the rectangle being filled.
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.blue);
g.drawRect(50, 50, 100, 100);
g.setColor(Color.red);
g.fillRect(50, 50, 100, 100);
}
};
panel.setPreferredSize(new Dimension(200, 200));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
Does anyone know the reasoning behind this behavior? Or is this a bug in Java's codebase?
It seems like drawing the rectangle adds 1 to the width and height of the rectangle you specify. This seems like un-intuitive behavior for one, but in my case it is also causing some undesired effects for a gui I am building.
This behavior is also found when drawing polygons with horizontal/vertical lines. Is there a simple way of getting some consistency in what is painted between the graphics draw and fill functions? It would be great if there was a way for any arbitrary polygon to completely paint over a previously drawn polyline using the same points.
One approach I had thought of was to both draw and fill whenever I want to fill a polygon and then just draw when I want to draw the polygon.
This would actually work in cases of opaque polygons, but in my case I have both opaque and transparent polygons so this approach is not an option.

This is clearly documented in the Graphics API:
drawRect
public void drawRect(int x,
int y,
int width,
int height)
Draws the outline of the specified rectangle. The left and right edges of the rectangle are at x and x + width. The top and bottom edges are at y and y + height. The rectangle is drawn using the graphics context's current color.
and
fillRect
public abstract void fillRect(int x,
int y,
int width,
int height)
Fills the specified rectangle. The left and right edges of the rectangle are at x and x + width - 1. The top and bottom edges are at y and y + height - 1. The resulting rectangle covers an area width pixels wide by height pixels tall. The rectangle is filled using the graphics context's current color.
Note the difference in the calculation for the right and bottom edges. Although this difference is clearly documented, there is no justification for this difference.
Finally, note that the first line of paintComponent() should be super.paintComponent(g);. This will ensure that the super class has a chance to initialize things, including clearing the region where you will draw.

Related

How to fade out the edges of a Java2D Area object?

I have a method that creates shadows based on where things are on the screen and the final product of that method is an Area, which I then draw onto the screen and it contains all shadows on screen in the same Area. This is because the drawn shadows are a low opacity so if it is not all one thing they will overlap and the opacity will make it look weird.
The issue that I want the shadows to look like they fade out, but I have absolutely no idea how, or if that would even be possible. Is there a way to soften the edges of the Area or make them gradient fade out? I tried to do graphics2D.setPaint(new GradientPaint[a gradient effect]) but it did nothing.
Thanks in advance
EDIT: Here is a screenshot of the program making a shadow around a 'building' rectangle. The green rectangle is to show the effect of the shadow. The end result I want is instead of the shadow abruptly ending, it should fade out.
i guess you have problems setting up the proper colors for the gradient:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(30, 30, 50, 20);
Graphics2D g2d = (Graphics2D) g;
Polygon p = new Polygon(new int[]{10,20,50,50,40,10}, new int[]{10,10,40,50,50,20}, 6);
Area a = new Area(p);
Color b = new Color(0xFF000000, true); //using colors with transparency!!!
Color w = new Color(0x00FFFFFF, true); //using colors with transparency!!!
//try to use proper values for the x/y values - both, start and end
GradientPaint gradient = new GradientPaint(0, 0, b, 40, 40, w);
g2d.setPaint(gradient);
g2d.fill(a); // fill your area!
}
result is a gradient with alpha (Transparency) ...
Area drawn in red <==> Area drawn with Gradient
don't forget to set the alpha value 0xAARRGGBB to FF for 100% opaque (0xFF000000 is black 100%opaque) to 0 (0x00FFFFFF white, 100% transparent)

Set background color in java Graphics object

Good day,
Know that in Java Graphics object, we can user the setColor() method to set the object color. But this is only apply to the object border. Is it anyway to set color for the whole object? I means the background of the Graphics object.
void draw(Graphics g)
{
g.setColor(color);
g.drawRect(left, right, width, height);
}
Kindly advise.
use fillRect() method .
g.fillRect(left, right, width, height);
from javadoc
drawRect()
Draws the outline of the specified rectangle. The left and right edges of the rectangle are at x and x + width. The top and bottom edges are at y and y + height. The rectangle is drawn using the graphics context's current color.
fillRect()
Fills the specified rectangle. The left and right edges of the rectangle are at x and x + width - 1. The top and bottom edges are at y and y + height - 1. The resulting rectangle covers an area width pixels wide by height pixels tall. The rectangle is filled using the graphics context's current
color.
" this is only apply to the object border " because drawRect draw the outlines only.
" Is it anyway to set color for the whole object? " well you misunderstand . and setColor() set the color to what you draw if you draw a outline then you can see outline only and it's not because of setColor() set colors to border .

Translate/Rotate/Move a graphics object without messing up the whole screen

I'm coding a GUI that will be doing some graphics translations/rotations, etc.
My problem is that when I try to translate my graphics,
(a) The entire screen translates instead of my one little painted area
(b) The old paint stays there, leaving a big paint blob instead of a translated image
(c) If I use the clearRect method to allow me to avoid (b), the entire screen goes white and (a) is still a problem
my DrawPanel class (I called it "LaunchTubeImage" for whatever reason)
private class LaunchTubeImage extends JPanel {
private Color colour;
public LaunchTubeImage(Color color) {
super();
this.colour = color;
}
public void paintComponent(Graphics g) {
Graphics2D gg = (Graphics2D)g;
double theta = (double)angle.getValue();
theta = Math.toRadians(theta);
gg.rotate(theta,tubeImage.getSize().width/2 + 10,
tubeImage.getSize().height - 50);
g.setColor(colour);
g.clearRect(0,0,getWidth(),getHeight());
g.fillRect(tubeImage.getSize().width/2,
tubeImage.getSize().height - 100 , 10, 50);
}
}
where this is called in my code
tubeImage = new LaunchTubeImage(Color.MAGENTA);
angle.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e) {
tubeImage.repaint();
}
});
Case 1: Comment out clearRect in that 1st block of code I posted
http://i58.tinypic.com/2d1l5w2_th.png
Black background as desired. Not rotated yet. Looks good so far.
http://oi60.tinypic.com/1zw1sm.jpg
Rotated it with my JSpinner... you see that the previous location was not removed (and note how my buttons randomly doubled and put themselves at the top of the screen).
Case 2: Keeping in the clearRect method
oi57.tinypic.com/2s84307.jpg
Layout is fine so far, but I wanted the background to be black
oi57.tinypic.com/4rde8x.jpg
Yay! It rotated. But note the weird behavior of that random "15" that appeared in my top right corner
oi58.tinypic.com/vymljm.jpg
And finally... when I resize the window you see that my entire screen was rotated - not just the pink image I wanted to rotate
Tips/fixes/advice? Thanks!! I hope I've provided enough information
(P.s. if you insist on us asking clear/useful questions.... then DON'T limit the number of images you can post... :/ )
The first line of an overridden paintComponent method should usually be super.paintComponent(g). On a JPanel, this will cause the drawing area to be cleared with the background color. If you want to clear the background with a different color, you can do this by manually filling a rectangle (clearRect is discouraged, see the JavaDoc), but of course, this has to be done before applying any transform.
So your method should probably look like this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(colour);
g.fillRect(0,0,getWidth(),getHeight());
Graphics2D gg = (Graphics2D)g;
double theta = (double)angle.getValue();
theta = Math.toRadians(theta);
gg.rotate(theta,tubeImage.getSize().width/2 + 10,tubeImage.getSize().height - 50);
gg.fillRect(tubeImage.getSize().width/2,tubeImage.getSize().height - 100 , 10, 50);
}

JPanel Exact drawing size/Limit?

When drawing on my extended JPanel I want the size to be variable. I've worked out the code to always outline a 1 pixel margin. My code works but I don't understand why I must adjust the height and width and height of the dimension by -1 when drawing the rectangle.
If I draw a rectangle that has 1,1 as a size it draws a single pixel square so shouldn't drawing the width and the height work without the -1 modifier.
If any one can explain why there is a discrepancy between the size of my extended JPanel or explain a better way to get the exact dimensions of the drawing area I would appreciate it.
public class Engine extends JPanel {
Engine(){
}
#Override
public void paintComponent(Graphics g){
Dimension a = this.getSize();
g.setColor(Color.RED);
g.drawRect(0, 0, a.width-1, a.height-1);
}
}
Remember, most values are 0 based. But instead of having to say, " I want the width of my panel to be 199" so you get a panel that is 200 pixels wide (0-199), Swing allows you to specify 1 based values and makes adjustments internally
If you create a rectangle of 1, 1, 1, 1, your actually creating a rectangle at position 1x1, whose width & height is 1 pixel (1 + 1 would be 2)
"or explain a better way to get the exact dimensions of the drawing area I would appreciate it."
Override getPreferredSize() in your JPanel class
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
When you you paint, make use of getWidth() and getHeight(), inherited from the JPanel class. Using these methods, your painting will resize dynamically with the resizing of the panel.
int width = getWidth();
int height = getHeight();
g.fillRect((int)(width * 0.9), (int)(height * 0.9),
(int)(width * 0.8), (int)(height * 0.8));
Side Note
You should call super.paintComponent inside the paintComponent method so as not to break the paint chain.
paintComponent should be protected not public
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
I've worked out the code to always outline a 1 pixel margin.
Don't do custom painting. Use a Swing Border. See How to Use Borders. You probably want a LineBorder.

How to scale an object according to window size?

I am trying to create a shape inside of a JPanel, and as the JPanel increases and decreases the size of the shape also changes accordingly.
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(0,100,50,0);
}
My problem is that I don't know how to scale it using something along the lines of this.getHeight() or this.getLength().
Besides the path outlined by #MadProgrammer, there are two other ways I can think of to scale graphics.
Swing components can generally rely on the Graphics object actually being a Graphics2D object.
We can then use Graphics2D.scale(sx,sy).
A scale instance of an AffineTransform (obtained using getScaleInstance(sx,sy). Set it to the Graphics2D before drawing.
Using either method, the original co-ordinates will be scaled as needed.
Assuming you mean you want to maintain a proportional ratio as the component size changes...
There are a few ways to do this...
You could start by determining the "default" values, that is, if the "preferred" width was 200, the line start point would 50% of the width and the end point would be 25% of the width.
This would allow you to do something like...
int width = getWidth();
int x1 = (int)(Math.round(width * 0.5d);
int x2 = (int)(Math.round(width * 0.25d);
g.drawLine(0, x1, x2, 0);

Categories