jbutton refuses to change transparency - java

I currently have a function which sets the background and have 1 button. The button is a PNG file and is transparent, I have done all the setOpaque stuff but the button still have a white background behind it. If anyone could help will be greatly appreciated! :)
I have attached my function below:
public JPanel createContentPane() throws IOException{
//Full back pane
JPanel fullGUI = new JPanel();
fullGUI.setLayout(null);
//background pane
JPanel backgroundPane = new JPanel() {
BufferedImage image = ImageIO.read(new File("UI/back2.jpg"));
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, 1200, 750, this);
}
};
backgroundPane.setLayout(null);
backgroundPane.setLocation(0,0);
backgroundPane.setSize(1200,750);
fullGUI.add(backgroundPane);
//button pane
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(null);
buttonPanel.setLocation(0, 250);
buttonPanel.setSize(1200, 500);
fullGUI.add(buttonPanel);
JButton playButton = new JButton(new ImageIcon(("UI/play.png")));
playButton.setLocation(399,47);
playButton.setSize(405,308);
playButton.setOpaque(false);
playButton.setContentAreaFilled(false);
playButton.setBorderPainted(false);
playButton.setFocusPainted(false);
buttonPanel.add(playButton);
fullGUI.setOpaque(true);
return fullGUI;
}

Have you tried setting the color to transparent?
try this:
playButton.setBackground(new Color(0.0f, 0.0f, 0.0f, 0.3f);
This sets the R to 0, G to 0, B to 0, and alpha(transparency) to 0.3.
Make sure to use float values to set the colours. the numbers can be tweaked to whatever you like. If you want to change the transparency, change the last number to higher for more opaque, and lower for less.
Good Luck!

Related

Making Multi-Coloured Buttons in Java

I want to create a grid of squares in my Java Swing GUI. I need to toggle their state so I'm thinking a JToggleButton is appropriate for each of the squares.
The problem that I have is that I want to partially colour each toggle button according to given percentages. e.g. if 50% and 50% I want the left half of the button to be green and the right to be red. If 25%,25%,50% I'd need 3 colours. I also need to use the button Text field so hiding that isn't allowed in the solution.
Is it possible to do something like this with a JToggleButton? Is there a better element to use? Or how might I go about it?
I apologise for not posting my work so far but I can't find anything close to an example of this type of thing.
I want to end up with something like this where each square is a button.
You can construct a button with changeable 2-color background as required by overriding
paintComponent:
import java.awt.*;
import javax.swing.*;
public class TwoColorsButton extends JButton{
private final Color leftColor, rightColor;
private int percentOfLeftColor;
public TwoColorsButton(String text) {
this(text,Color.RED, Color.GREEN, 50);
}
public TwoColorsButton(String text, Color leftColor,Color rightColor, int percentOfLeftColor) {
super(text);
this.leftColor = leftColor;
this.rightColor = rightColor;
this.percentOfLeftColor = percentOfLeftColor;
//make button transparent
setOpaque(false);
setContentAreaFilled(false);
setBorderPainted(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
int leftWidth = getWidth() * percentOfLeftColor/100;
g2.setColor(leftColor);
g2.fillRect(0, 0, leftWidth , getHeight());
g2.setColor(rightColor);
g2.fillRect(leftWidth, 0, getWidth() -leftWidth, getHeight());
g2.setPaint(Color.BLACK);
super.paintComponent(g2); //button is transparent so super paints text only
g2.dispose();
}
public void setPercentOfLeftColor(int percentOfLeftColor) {
this.percentOfLeftColor = percentOfLeftColor;
repaint();
}
public int getPercentOfLeftColor() {
return percentOfLeftColor;
}
public static void main(String[] args) {
//run button test
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel topPanel = new JPanel();
TwoColorsButton twoColorBtn = new TwoColorsButton("Some Text");
topPanel.add(twoColorBtn);
frame.add(topPanel, BorderLayout.PAGE_START);
JPanel bottomPanel = new JPanel();
JButton runTestBtn = new JButton("Run test");
runTestBtn.addActionListener(e->{
runTestBtn.setEnabled(false);
new Timer(1000, e1 ->{
int percent = twoColorBtn.getPercentOfLeftColor() +25;
percent = percent > 100 ? 0 : percent;
twoColorBtn.setPercentOfLeftColor(percent);
}).start();
});
bottomPanel.add(runTestBtn);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setVisible(true);
}
}
The code can easily be modified to allow 3 colors, if needed.
(Test it online here)
(See a basic 3 colors toggle button here)

How does the opaque property work in Swing?

This a simple application I got from here this answer to How to set a Transparent Background of JPanel
that's supposed to explain how setOpaque() works.
public class TwoPanels {
public static void main(String[] args) {
JPanel p = new JPanel();
// setting layout to null so we can make panels overlap
p.setLayout(null);
CirclePanel topPanel = new CirclePanel();
// drawing should be in blue
topPanel.setForeground(Color.blue);
// background should be black, except it's not opaque, so
// background will not be drawn
topPanel.setBackground(Color.black);
// set opaque to false - background not drawn
topPanel.setOpaque(false);
topPanel.setBounds(50, 50, 100, 100);
// add topPanel - components paint in order added,
// so add topPanel first
p.add(topPanel);
CirclePanel bottomPanel = new CirclePanel();
// drawing in green
bottomPanel.setForeground(Color.green);
// background in cyan
bottomPanel.setBackground(Color.cyan);
// and it will show this time, because opaque is true
bottomPanel.setOpaque(true);
bottomPanel.setBounds(30, 30, 100, 100);
// add bottomPanel last...
p.add(bottomPanel);
// frame handling code...
JFrame f = new JFrame("Two Panels");
f.setContentPane(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// Panel with a circle drawn on it.
private static class CirclePanel extends JPanel {
// This is Swing, so override paint*Component* - not paint
protected void paintComponent(Graphics g) {
// call super.paintComponent to get default Swing
// painting behavior (opaque honored, etc.)
super.paintComponent(g);
int x = 10;
int y = 10;
int width = getWidth() - 20;
int height = getHeight() - 20;
g.fillArc(x, y, width, height, 0, 360);
}
}
}
The thing the I don't get is how come he is adding the opaque layer on top of transparent layer? shouldn't be the other way around?
The way that I picture how it should work is by adding the transparent layer on top of the opaque one, kinda of like how you put a screen protector over a phone(sorry for the dumb example)
Can someone please explain how transparency works in java?
I apologize of my question is a bit naive but this has been bothering me for a while!
Yes, the example reliest on the fact that with a null layout, the child components are indeed drawn in reverse order. An implementation dependency. That at least deserves mention. Adding a visible border would make it more evident:
private static class CirclePanel extends JPanel {
CirclePanel() {
setBorder(BorderFactory.createLineBorder(Color.RED));
}

Gradient background in a JFrame

I have googled this and read a lot but did not find an answer that suits my needs, so I'll ask here:
I would like to have a gradient background in my JFrame. Currently the background is a single colour. My code looks something like this:
//imports
public class Game {
//some other irrelevant instance variables
JFrame frame = new JFrame("Game");
public Game() {
frame.getContentPane().setBackground(new Color(200,220,200));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setPreferredSize(new Dimension(frameX,frameY)); //frameX and frameY are instance variables
getMenu(); //method that adds a few JLabels to the JFrame and so on
}
}
The methods that I have read about apply to classes that extend JPanel or JFrame (and then use GradientPaint or something like that), but as you can see I use JFrame as an instance variable. Can someone help me out?
Edit: Picture:
Now, obviously, your example image above does not specify buttons and does not add a label for the message at the bottom. But since it was obvious you intended the user to select those options, I used buttons. The label at the bottom is just to show proof they are buttons (with an action listener attached, to show the message).
The advantage of using actual buttons is that they are also keyboard accessible (press Enter to see the first message, press Tab to navigate to the next one...
If the game does not need to be keyboard accessible, you can swap those out for labels and add a mouse listener. I'll leave that to you.
The code has a lot of comments containing the word 'adjust'. Look at them closely, check the JavaDocs, adjust them as needed..
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class GradientPaintBackground {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
JPanel gui = new JPanel(new BorderLayout(15, 15)) {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Point point1 = new Point(10, 10);
Point point2 = new Point(
getWidth() - 10,
getHeight() - 10);
final GradientPaint gp = new GradientPaint(
point1, Color.YELLOW,
point2, new Color(255, 225, 100),
true);
// we need a Graphics2D to use GradientPaint.
// If this is Swing, it should be one..
final Graphics2D g2 = (Graphics2D) g;
g2.setPaint(gp);
g.fillRect(0, 0, getWidth(), getHeight());
}
};
// adjust size to need.
gui.setBorder(new EmptyBorder(20, 20, 20, 20));
// Start: Add components
// adjust size to size of logo
BufferedImage logo = new BufferedImage(
100, 40, BufferedImage.TYPE_INT_RGB);
JLabel logoLabel = new JLabel(new ImageIcon(logo));
gui.add(logoLabel, BorderLayout.NORTH);
// adjust spacing to need
JPanel menuPanel = new JPanel(new GridLayout(0, 1, 20, 20));
menuPanel.setBorder(new EmptyBorder(5, 55, 5, 5));
// allow the BG to show through..
menuPanel.setOpaque(false);
gui.add(menuPanel);
String[] actionTexts = new String[]{
"Play Game", "Tutorial", "Other"
};
final JLabel messages = new JLabel("Ready to play? "
+ "Select an option");
gui.add( messages, BorderLayout.PAGE_END );
ActionListener al = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
JButton b = (JButton)e.getSource();
messages.setText(b.getText() + " selected!");
}
}
};
for (int ii = 0; ii < actionTexts.length; ii++) {
JButton b = new JButton(actionTexts[ii]);
b.setContentAreaFilled(false);
b.setHorizontalAlignment(SwingConstants.LEADING);
b.setBorder(null);
b.addActionListener(al);
menuPanel.add(b);
}
// End: Add components
JFrame f = new JFrame("Gradient Background in JFrame");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
f.setMinimumSize(f.getSize());
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
General Tip
Java GUIs might have to work on a number of platforms, on different screen resolutions & using different PLAFs. As such they are not conducive to exact placement of components. This is why you are continually seeing the types of problems you see. Toss layouts out the window, and all hell breaks loose.
To organize the components for a robust GUI, instead use layout managers, or combinations of them1, along with layout padding & borders for white space2.

JButtons in JPanel don't display properly until repainted through resize or action

I've had this problem for a while now, searched many forums and sites (including this one), and still did not find an answer to my question.
This is my problem:
I am building a visual calendar. I have a parent panel with multiple panels in it. I repaint the parent panel, and make the 3 overlaying opaque(false). The paint of the parent panel is not showing until I resize the frame (or use the buttons that overlay one of the 3, but those are left out in this example because it makes the code longer)
Anyway, here is the code, I simplified it to the problem part:
public class Calendar extends JPanel{
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(1600,150);
frame.add(new Calendar());
frame.setVisible(true);
}
public Calendar(){
setLayout(new GridBagLayout());
GridBagConstraints cc = new GridBagConstraints();
cc.weightx = 1;
cc.weighty = 1;
cc.gridx = 0;
cc.fill = GridBagConstraints.BOTH;
//Initiate Panels
JPanel yearpanel = new JPanel();
JPanel monthpanel = new JPanel();
JPanel daypanel = new JPanel();
yearpanel.setLayout(new GridBagLayout());
monthpanel.setLayout(new GridBagLayout());
daypanel.setLayout(new GridBagLayout());
// Set sizes
int width = (int) this.getPreferredSize().getWidth();
int height = (int) (this.getPreferredSize().getHeight() / 3);
yearpanel.setSize(width,height);
daypanel.setSize(width,height);
monthpanel.setSize(width,height);
//make transparent
yearpanel.setOpaque(false);
monthpanel.setOpaque(false);
daypanel.setOpaque(false);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Image image = Toolkit.getDefaultToolkit().getImage("Images/CalendarBackground.jpg");
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
}
}
I have no idea why it does that + I could not find an answer online, only people with the same problem whose question got abandoned :/
Can anyone help me?
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image image = Toolkit.getDefaultToolkit().getImage("Images/CalendarBackground.jpg");
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), null);
}
The image should not be loaded in the paint method. Instead it should be declared as a class attribute and preloaded.
The Toolkit method is asynchronous, so it is even more important to use the component as the ImageObserver.
g.drawImage(image, 0, 0, this.getWidth(), this.getHeight(), this);
Here is a working SSCCE that is something like what you seem to be attempting.
check the return value of Graphics.drawImage(). I bet it's returning false, which means the image you're painting isn't fully loaded and scaled yet. Try loading the image somewhere other than your paintComponent method, like your Calendar constructor.

How to set a transparent background of JPanel?

Can JPanels background be set to transparent?
My frame is has two JPanels:
Image Panel and
Feature Panel.
Feature Panel is overlapping Image Panel.
The Image Panel is working as a background and it loads image from a remote URL.
On Feature Panel I want to draw shapes. Now Image Panel cannot be seen due to Feature Panel's background color.
I need to make Feature Panel background transparent while still drawing its shapes and I want Image Panel to be visible (since it is doing tiling and cache function of images).
I'm using two JPanel's, because I need to seperate the image and shape drawing .
Is there a way the overlapping Jpanel have a transparent background?
Calling setOpaque(false) on the upper JPanel should work.
From your comment, it sounds like Swing painting may be broken somewhere -
First - you probably wanted to override paintComponent() rather than paint() in whatever component you have paint() overridden in.
Second - when you do override paintComponent(), you'll first want to call super.paintComponent() first to do all the default Swing painting stuff (of which honoring setOpaque() is one).
Example -
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TwoPanels {
public static void main(String[] args) {
JPanel p = new JPanel();
// setting layout to null so we can make panels overlap
p.setLayout(null);
CirclePanel topPanel = new CirclePanel();
// drawing should be in blue
topPanel.setForeground(Color.blue);
// background should be black, except it's not opaque, so
// background will not be drawn
topPanel.setBackground(Color.black);
// set opaque to false - background not drawn
topPanel.setOpaque(false);
topPanel.setBounds(50, 50, 100, 100);
// add topPanel - components paint in order added,
// so add topPanel first
p.add(topPanel);
CirclePanel bottomPanel = new CirclePanel();
// drawing in green
bottomPanel.setForeground(Color.green);
// background in cyan
bottomPanel.setBackground(Color.cyan);
// and it will show this time, because opaque is true
bottomPanel.setOpaque(true);
bottomPanel.setBounds(30, 30, 100, 100);
// add bottomPanel last...
p.add(bottomPanel);
// frame handling code...
JFrame f = new JFrame("Two Panels");
f.setContentPane(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// Panel with a circle drawn on it.
private static class CirclePanel extends JPanel {
// This is Swing, so override paint*Component* - not paint
protected void paintComponent(Graphics g) {
// call super.paintComponent to get default Swing
// painting behavior (opaque honored, etc.)
super.paintComponent(g);
int x = 10;
int y = 10;
int width = getWidth() - 20;
int height = getHeight() - 20;
g.drawArc(x, y, width, height, 0, 360);
}
}
}
Alternatively, consider The Glass Pane, discussed in the article How to Use Root Panes. You could draw your "Feature" content in the glass pane's paintComponent() method.
Addendum: Working with the GlassPaneDemo, I added an image:
//Set up the content pane, where the "main GUI" lives.
frame.add(changeButton, BorderLayout.SOUTH);
frame.add(new JLabel(new ImageIcon("img.jpg")), BorderLayout.CENTER);
and altered the glass pane's paintComponent() method:
protected void paintComponent(Graphics g) {
if (point != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.3f));
g2d.setColor(Color.yellow);
g2d.fillOval(point.x, point.y, 120, 60);
}
}
As noted here, Swing components must honor the opaque property; in this variation, the ImageIcon completely fills the BorderLayout.CENTER of the frame's default layout.
In my particular case it was easier to do this:
panel.setOpaque(true);
panel.setBackground(new Color(0,0,0,0,)): // any color with alpha 0 (in this case the color is black
(Feature Panel).setOpaque(false);
Hope this helps.
To set transparent you can set opaque of panel to false like
JPanel panel = new JPanel();
panel.setOpaque(false);
But to make it transculent use alpha property of color attribute like
JPanel panel = new JPanel();
panel.setBackground(new Color(0,0,0,125));
where last parameter of Color is for alpha and alpha value ranges between 0 and 255 where 0 is full transparent and 255 is fully opaque
public void paintComponent (Graphics g)
{
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.0f)); // draw transparent background
super.paintComponent(g);
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f)); // turn on opacity
g.setColor(Color.RED);
g.fillRect(20, 20, 500, 300);
}
I have tried to do it this way, but it is very flickery
As Thrasgod correctly showed in his answer, the best way is to use the paintComponent, but also if the case is to have a semi transparent JPanel (or any other component, really) and have something not transparent inside. You have to also override the paintChildren method and set the alfa value to 1.
In my case I extended the JPanel like that:
public class TransparentJPanel extends JPanel {
private float panelAlfa;
private float childrenAlfa;
public TransparentJPanel(float panelAlfa, float childrenAlfa) {
this.panelAlfa = panelAlfa;
this.childrenAlfa = childrenAlfa;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getBackground());
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, panelAlfa));
super.paintComponent(g2d);
}
#Override
protected void paintChildren(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getBackground());
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_ATOP, childrenAlfa));
super.paintChildren(g);
}
//getter and setter
}
And in my project I only need to instantiate Jpanel jp = new TransparentJPanel(0.3f, 1.0f);, if I want only the Jpanel transparent.
You could, also, mess with the JPanel shape using g2d.fillRoundRect and g2d.drawRoundRect, but it's not in the scope of this question.

Categories