Transparent JButton still painting its background - java

I have a translucent JPanel. I have created a custom JButton by extending JButton as I required a button with rounded corners and wanted to add some effects to it. I have made the button non-opaque. When I add this button to my translucent JPanel it apears fine. But on rollover a black patch is painted behind the button which looks really crappy. I searched the net for a solution but could'nt find a useful one . This problem is also described at http://www.java.net/node/661798 but i was not able really make kirillcool's suggestion work out.....Any help will be appreciated

I believe you need to add:
button.setContentAreaFilled( false );

not sure if someone is still interested...
you can fix the problem by overriding the paintComponent() method to let Java draw the JButton in any Shape you like. you just need to set the background of the Graphics object to transparent with setBackground() method. also you need to clear the Graphics object BEFORE drawing on it with clearRect() method and then fill it again with the alpha level of the background of your JButton. here is my piece of code.. it shows the overriden paintComponent(). by pasting it into your JButton you should get a JButton with rounded edges even if its on semi-transparant background
private int outerRoundRectSize = 10;
private int innerRoundRectSize = 8;
public void paintComponent(Graphics g)
{
int h = getHeight();
int w = getWidth();
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
Color GP = null;
//////////////get rid of the black background////////////////////////
g2d.setBackground(new Color(0,0,0,0.0f));
g2d.clearRect(0, 0, w, h);
g2d.setPaint(new Color(0,0,0,0.3f));
g2d.fillRect(0, 0, w, h);
//////////////get rid of the black background////////////////////////
ButtonModel model = getModel();
if(!model.isEnabled())
{
setForeground(Color.GRAY);
GP = new Color(0.5f,0.2f,0.6f);
}
else
{
setForeground(Color.WHITE);
if(model.isRollover())
{
GP = new Color(0.5f,0.2f,0.6f);
}
else
{
GP = new Color(0.0f,1.0f,0.0f);
}
}
g2d.setPaint(GP);
Color p1 = null;
Color p2 = null;
if(getModel().isPressed())
{
GP = new Color(1.0f,0.0f,0.0f);
g2d.setPaint(GP);
p1=new Color(0.12f,0.7f,0.3f);
p2=new Color(0.7f,0.5f,0.6f);
}
else
{
p1=new Color(0.0f,0.5f,0.7f);
p2=new Color(0.0f,1.0f,1.0f);
GP = new Color(0.0f,0.0f,1.0f);
}
RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(0, 0, w - 1, h - 1, outerRoundRectSize, outerRoundRectSize);
Shape clip = g2d.getClip();
g2d.clip(r2d);
//g2d.fillRect(0, 0, w, h);
g2d.fillRoundRect(0, 0, w, h, outerRoundRectSize, outerRoundRectSize);
g2d.setClip(clip);
g2d.setPaint(p1);
g2d.drawRoundRect(0, 0, w - 1, h - 1, outerRoundRectSize,outerRoundRectSize);
g2d.setPaint(p2);
g2d.drawRoundRect(1, 1, w - 3, h - 3, innerRoundRectSize,innerRoundRectSize);
g2d.dispose();
super.paintComponent(g);
}

Related

How to draw both graphics and buttons properly in Jframe?

I am having a hard time figuring out how to set up both graphics and buttons at thee same time without the buttons flickering.
I am trying to make a navigation program for my robot. I tried to add buttons to my program for the last week or two and nothing works out for me, thanks in advance!
Here is my code:
public static void main (String [] args) throws IOException{
image = ImageIO.read(new File("images/2020.jpg"));
double ratio = (double) image.getHeight() / (double) image.getWidth();
double Yscaled = (int) (Xscaled*ratio);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize((int) Xscaled+15 + 2*ButtonSpace + ButtonWidth,(int) Yscaled+34);
JButton clear = new JButton("Clear");
clear.setBounds((int)Xscaled+ButtonSpace, (int)Yscaled/4 - ButtonHeight/2, ButtonWidth, ButtonHeight);
window.add(clear);
cordList.add((int) Xs);
cordList.add((int) Ys);
JPanel painting = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
y1 = Math.sin(Math.toRadians(a))*c;
x1 = Math.cos(Math.toRadians(a))*c;
y2 = -Math.cos(Math.toRadians(a))*h;
x2 = -Math.sin(Math.toRadians(a))*h;
g.drawImage(image, 0, 0, (int) Xscaled, (int) Yscaled, null);
if (cordList.size() > 0){
if (cordList.get(cordList.size()-2) > Xscaled || cordList.get(cordList.size()-1) > Yscaled){
cordList.remove(cordList.size()-2);
cordList.remove(cordList.size()-1);
}
}
for (int i = 0; i < cordList.size(); i+=2){
int size = 5;
g.setColor(new Color(220, 242, 19));
g.fillOval(cordList.get(i)-size/2, cordList.get(i+1)-size/2, size, size);
g.setColor(new Color(0, 0, 0));
g.drawOval(cordList.get(i)-size/2, cordList.get(i+1)-size/2, size, size);
if(i < cordList.size()-2){
g.drawLine(cordList.get(i), cordList.get(i+1), cordList.get(i+2), cordList.get(i+3));
}
}
Triangle_Shape triangleShape = new Triangle_Shape(new Point2D.Double(Xs - x1, Ys - y1),
new Point2D.Double(Xs + x1, Ys + y1), new Point2D.Double(Xs - x2, Ys + y2));
Graphics2D g2d = (Graphics2D) g.create();
g2d.draw(triangleShape);
g2.setColor(new Color(19, 191, 15));
g2.fill(triangleShape);
repaint();
}
};
painting.setBounds(0, 0 ,(int) Xscaled ,(int) Yscaled);
window.add(painting);
window.getContentPane().addMouseListener(new Field());
window.setVisible(true);
}
I had the same problem a few years ago. JPanels can be pretty helpful, but drawing on your JFrame and adding buttons without flickering only works with JLabels for some reason. Just try replacing the JPanel with a JLabel as shown:
public static void main(String[] args) {
// init Frame
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(800, 600);
// !! add Buttons before you add the JLabel to the Frame !!!!
JButton clear = new JButton("Clear");
window.add(clear);
clear.setBounds(100, 100, 100, 100);
// !! change to JLabel!!
JLabel painting = new JLabel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// adds Antialising for rounded edges when adding text
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// test draw
g.setColor(Color.green);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.black);
g.setFont(new Font("Consolas", 0, 100));
g.drawString("Test123'*#", 100, 300);
repaint();
}
};
window.add(painting);
window.setVisible(true);
}
Working Window without flickering
SIDENOTE: You need to add the buttons and other Components before you add the JLabel to the JFrame!
Also added Antialising as a small trick you can use for better visuals.
I Hope it'll help you!

paintComponent removing text value of button

I am setting background image for JButton or say JTableHeader. When I do paintComponent on the same, it's removing text value set for that component.
Any idea where I am going wrong?
JButton btn = new JButton(){
#Override
public void paintComponent(Graphics g){
Dimension size = this.getSize();
g.drawImage(Toolkit.getDefaultToolkit().getImage("C:\\User\\Downloads\\MainMenu.jpg"), 0, 0, size.width, size.height, this);
}
};
btn.setText("TEST WITH ME");
btn.setOpaque(true);
I am setting background image for JButton
The is no need to do custom painting. You just add an Icon to the button and the button will paint the image.
If you want text on top of the image then you just use the properties of the button:
button.setHorizontalTextPosition(...);
button.setVerticalTextPosition(...);
I may have not specified that much correct what I really wanted. But I figured out answer for that.
#Override
public void paintComponent(Graphics g){
Dimension size = this.getSize();
g.drawImage(Toolkit.getDefaultToolkit().getImage("C:\\User\\Downloads\\MainMenu.jpg"), 0, 0, size.width, size.height, this);
FontMetrics fm = g.getFontMetrics();
int x = (getWidth() - fm.stringWidth("String Value To Set")) / 2;
int y = ( (getHeight() - fm.getHeight() ) / 2) + fm.getAscent() ;
g.drawString(String Value To Set, x, y);
}

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.

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

Inner-Transparent Selection Window in Java using GlassPane

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();
}

Categories