Inner-Transparent Selection Window in Java using GlassPane - java

I am trying to achieve the following
http://www.qksnap.com/i/3hunq/4ld0v/screenshot.png
I am currently able to draw rectangles successfully on a semi-transparent glasspane background using the following code:
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.black); // black background
g.fillRect(0, 0, frame.getWidth(), frame.getHeight());
g2.setColor(Color.GREEN.darker());
if (getRect() != null && isDrawing()) {
g2.draw(getRect()); // draw our rectangle (simple Rectangle class)
}
g2.dispose();
}
Which works great, however, I would love to have the area within the rectangle be completely transparent while the outside was still darken much like the screenshot above.
Any ideas?

..have the area within the rectangle be completely transparent while the outside was still darken much like the screenshot above.
Create a Rectangle (componentRect) that is the size of the component being painted.
Create an Area (componentArea) of that shape (new Area(componentRect)).
Create an Area (selectionArea) of the selectionRectangle.
Call componentArea.subtract(selectionArea) to remove the selected part.
Call Graphics.setClip(componentArea)
Paint the semi-transparent color.
(Clear the clipping area if more paint operations are required).

As Andrew has suggested (just beat me while I was finishing off my example)
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g.setColor(Color.black); // black background
Area area = new Area();
// This is the area that will filled...
area.add(new Area(new Rectangle2D.Float(0, 0, getWidth(), getHeight())));
g2.setColor(Color.GREEN.darker());
int width = getWidth() - 1;
int height = getHeight() - 1;
int openWidth = 200;
int openHeight = 200;
int x = (width - openWidth) / 2;
int y = (height - openHeight) / 2;
// This is the area that will be uneffected
area.subtract(new Area(new Rectangle2D.Float(x, y, openWidth, openHeight)));
// Set up a AlphaComposite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
g2.fill(area);
g2.dispose();
}

Related

BufferedImage fill rectangle with transparent pixels

I have a BufferedImage and I am trying to fill a rectangle with transparent pixels. The problem is, instead of replacing the original pixels, the transparent pixels just go on top and do nothing. How can I get rid of the original pixel completely? The code works fine for any other opaque colors.
public static BufferedImage[] slice(BufferedImage img, int slices) {
BufferedImage[] ret = new BufferedImage[slices];
for (int i = 0; i < slices; i++) {
ret[i] = copyImage(img);
Graphics2D g2d = ret[i].createGraphics();
g2d.setColor(new Color(255, 255, 255, 0));
for(int j = i; j < img.getHeight(); j += slices)
g2d.fill(new Rectangle(0, j, img.getWidth(), slices - 1));
g2d.dispose();
}
return ret;
}
public static BufferedImage copyImage(BufferedImage source){
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
Using AlphaComposite, you have at least two options:
Either, use AlphaComposite.CLEAR as suggested, and just fill a rectangle in any color, and the result will be a completely transparent rectangle:
Graphics2D g = ...;
g.setComposite(AlphaComposite.Clear);
g.fillRect(x, y, w, h);
Or, you can use AlphaComposite.SRC, and paint in a transparent (or semi-transparent if you like) color. This will replace whatever color/transparency that is at the destination, and the result will be a rectangle with exactly the color specified:
Graphics2D g = ...;
g.setComposite(AlphaComposite.Src);
g.setColor(new Color(0x00000000, true);
g.fillRect(x, y, w, h);
The first approach is probably faster and easier if you want to just erase what is at the destination. The second is more flexible, as it allows replacing areas with semi-transparency or even gradients or other images.
PS: (As Josh says in the linked answer) Don't forget to reset the composite after you're done, to the default AlphaComposite.SrcOver, if you plan to do more painting using the same Graphics2D object.

Restricting the drawing area on a JPanel and saving graphics states

The purpose of the black JPanel is drawing.
How can I restrict the drawing to the radius of the circle formed by the lines?
Is there a way to save the graphics object state so that more drawing can be added to it as well as adding an undo function?
public void paintComponent(Graphics g)
{
super.paintComponent(g);
sectors = 12;
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
sector = new Line2D.Double(getWidth()/2, 0, getWidth()/2, getHeight());
//g2d.setClip(new Ellipse2D.Double(getWidth()/2,getHeight()/2, radius, radius));
//draws the sectors on the screen
for(int i=0; i<sectors; i++)
{
g2d.draw(sector);
g2d.rotate(Math.toRadians(30),getWidth()/2,getHeight()/2);
}
//draws the doily
if(dragging)
{
for(int i=0; i<sectors; i++)
{
g2d.fillOval((int) draw.getX(), (int) draw.getY(),20, 20);
g2d.rotate(Math.toRadians(30), getWidth()/2, getHeight()/2);
}
//saves the current drawing in a stack
graphics.push(g2d);
}
}
For your first question,
You would need to read up on Java's Custom Painting http://docs.oracle.com/javase/tutorial/uiswing/painting/
Not to discourage you but this is a tricky process,
To answer your question there is a similar post here
Java Change shape of JPanel

How to use graphics2D from BufferedImage object, with "getGraphics()" method?

I'm trying to make a 2D game, but I can't figure out why my graphics from precedent frames are still there. The effect is when moving a rectangle on x with 1 pixel / frame, I get a long bar drawn on my screen.
In the class body I declared the objects beneath like that:
private int x, y;
private BufferedImage image;
private Graphics2D g;
This is how I'm initializing:
x = 10, y = 25;
image = new BufferedImage(300, 300, BufferedImage.TYPE_INT_BGR);
g = (Graphics2D) image.getGraphics();
r = new Rectangle(x, y, 10, 10);
I have method where I draw graphics:
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.draw(r);
g2.dispose();
I also have a tick method where I move the rectangle:
x++;
The class extends Canvas and implements Runnable for the game loop and I use a JFrame object .
This is the result of 10x10 rectangle movement:
capture

How to remove original object after rotation in java graphics2D?

Specifically, I am trying to display only the rotated object. I have a drawn rectangle and I rotate it.
How to I display only the rotated rectangle and dispose of the old one?
EDITED:
The following is the code to rotate my rectangle:
private void rotateRectangle(Graphics g, Rectangle rect, Color c){
Graphics2D g2d = (Graphics2D) g.create();
x = rect.x;
y = rect.y;
g2d.setColor(c);
g2d.rotate(Math.PI/6, PANEL_WIDTH/2,PANEL_HEIGHT/2);
g2d.drawRect(PANEL_WIDTH/2-x/2, PANEL_HEIGHT/2-y/2, x, y);
}
And this is the paintComponent where I call it from:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setStroke(new BasicStroke(3));
//these are declared before
rect.x = x;
rect.y = y;
if(rotateClicked){
rotateRectangle(g2d,rect,squareColor);
rotateClicked = false;
}
drawRectangle(g2d, rect, squareColor);
getArea(x,y);
}
If custom rendering shapes with a Graphics object by overwriting paintComponent(Graphics g), ensure you use super.paintComponent(g) as the first line to clear the drawing area
From there draw your Rectangle/rotated Rectangle
Without using super.paintComponent(g), your previous drawings (the unrotated Rectangle) will remain visible
EDIT
With the update of source code: you are drawing both the new and the old rectangle because your if statement does not have an else clause
Try inserting an else clause so that it will draw one rectangle or the other, currently it maybe draws a rotated rectangle and then draws the unrotated rectangle
if(rotateClicked)
{
rotateRectangle(g2d,rect,squareColor);
rotateClicked = false;
}
else
drawRectangle(g2d, rect, squareColor);
You may or may not want a rotateClicked = true in the else so it will flip back and forth between rotated and unrotated

How to center align background image in JPanel

I wanted to add background image to my JFrame.
Background image means I can later add Components on the JFrame or JPanel
Although I coudn't find how to add background image to a JFrame,
I found out how to add background image to a JPanel from here:
How to set background image in Java?
This solved my problem, but now since my JFrame is resizable I want to keep the image in center.
The code I found uses this method
public void paintComponent(Graphics g) { //Draw the previously loaded image to Component.
g.drawImage(img, 0, 0, null);  //Draw image
}
Can anyone say how to align the image to center of the JPanel.
As g.drawImage(img, 0, 0, null); provides x=0 and y=0
Also if there is a method to add background image to a JFrame then I would like to know.
Thanks.
Assuming a suitable image, you can center it like this:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int x = (this.getWidth() - image.getWidth(null)) / 2;
int y = (this.getHeight() - image.getHeight(null)) / 2;
g2d.drawImage(image, x, y, null);
}
If you want the other components to move with the background, you can alter the graphics context's affine transform to keep the image centered, as shown in this more complete example that includes rotation.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.translate(this.getWidth() / 2, this.getHeight() / 2);
g2d.translate(-image.getWidth(null) / 2, -image.getHeight(null) / 2);
g2d.drawImage(image, 0, 0, null);
}

Categories