I want to make an overlay window that has a transparent frame with non transparent children. I was successful when making the transparent window and even was successful when adding a test child to see if it work. But as soon as I replace that test code with my paintComponent... I get a white background. Anyone know why?
package blahh;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;;
public class LoadingFrame {
public static void main(String[] args) {
LoadingFrame Class = new LoadingFrame();
Class.frameChar();
}
public void frameChar(){
JFrame frame = new JFrame();
B b = new B();
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setAlwaysOnTop(true);
frame.setPreferredSize(new Dimension(500, 500));
frame.getContentPane().setLayout(new java.awt.BorderLayout());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//frame.getContentPane().add(new JLabel("test code");
frame.add(b);
frame.pack();
}
public class B extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawRect(0, 0, 100, 100);
}
}
}
JPanel is opaque by default, combined with BorderLayout, this will make it cover the entire frame, making it appear opaque. You need to call setOpaque(false) on it to make it see through
JFrame frame = new JFrame();
B b = new B();
b.setOpaque(false);
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setAlwaysOnTop(true);
// I'd prefer to override getPreferredSize of B
frame.setPreferredSize(new Dimension(500, 500));
frame.setLocationRelativeTo(null);
frame.add(b);
frame.pack();
frame.setVisible(true);
ps- You should also call setVisible last where possible, it just reduces the possibility of your components not showing up randomly
Related
I'm dealing with a very specific issue. When I remove all the components of a transparent JPanel (background color with 0 alpha) and add new components, the removed elements are still displayed in the JPanel. Here is an example of the behavior.
And here is the code to generate it:
class MyPanel extends JPanel {
public MyPanel() {
this.setLayout(new FlowLayout());
this.setBackground(new Color(0, 0, 0, 0));
}
public void updateComponents() {
this.removeAll();
this.revalidate();
int n = new Random().nextInt(10);
for (int i = 0; i < n; i++) {
this.add(new JButton("Dummy Button"));
}
}
}
public class Runner {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1280, 720);
MyPanel panel = new MyPanel();
JButton btUpdate = new JButton("Update");
btUpdate.addActionListener(actionEvent -> {
panel.updateComponents();
});
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(btUpdate, BorderLayout.NORTH);
frame.getContentPane().add(panel, BorderLayout.SOUTH);
frame.setVisible(true);
}
}
Can somebody help me?
this.revalidate();
The point of invoking revalidate() is to invoke the layout manager.
You need to invoke that method AFTER you add all the components to the panel.
You also need to make sure the components are painted so the code should be:
this.revalidate();
this.repaint();
I have even tried using the AlphaContainer
How? Post your code showing what you attempted.
The usage should be:
//frame.getContentPane().add(panel, BorderLayout.SOUTH);
frame.getContentPane().add(new AlphaContainer(panel), BorderLayout.SOUTH);
When I run the below code, I am unable to see the background color as red. It's showing default one. Is there anything that I have to add to these lines?
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
public class gfix extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(80, 100, 150, 75);
}
public static void main(String[] args){
gfix gg=new gfix();
JFrame frame = new JFrame("RISK");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(null);
frame.add(panel);
JButton button = new JButton("test");
button.setBounds(100, 100, 150, 150);
panel.add(button);
frame.setVisible(true);
}
}
Your are overriding painGraphics() in gfix class so add gfix class object into your frame not Java provided JPanel class object.
gfix gg=new gfix();
JFrame frame = new JFrame("RISK");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//JPanel panel = new JPanel(); Not needed
//panel.setLayout(null);
frame.add(gg);
JButton button = new JButton("test");
button.setBounds(100, 100, 150, 150);
gg.add(button);
frame.setVisible(true);
for g.fillRect(80, 100, 150, 75); give proper panel bounds to fill complete panel background. OR use int width = getWidth();
int height = getHeight(); in paintGraphics to get actual height and width.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class gfix {
public static void main(String[] args) {
JFrame frame = new JFrame("RISK");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBackground(Color.RED);
frame.add(panel);
JButton button = new JButton("test");
// adjust numbers as needed
button.setMargin(new Insets(20,40,20,40));
panel.add(button);
// adjust numbers as needed
panel.setBorder(new EmptyBorder(10,40,50,200));
frame.pack();
frame.setVisible(true);
}
}
Other tips:
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space.
Provide ASCII art or a simple drawing of the intended layout of the GUI at minimum size, and if resizable, with more width and height - to show how the extra space should be used.
Please learn common Java nomenclature (naming conventions - e.g. EachWordUpperCaseClass, firstWordLowerCaseMethod(), firstWordLowerCaseAttribute unless it is an UPPER_CASE_CONSTANT) and use it consistently.
When I change a JLabel's font size or contents in a translucent JFrame, then call pack() on the frame, a ghosted version of the previous contents is visible. This only happens on macOS. The same code works fine on Windows.
Here's an enlarged example of what happens:
Here is code to reproduce the problem; make sure the JFrame is on top of a white background to better see the problem, then click the "Bigger" and "Smaller" buttons:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class ScratchSpace {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Test Transparent Frame");
frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", true);
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 25));
JPanel contentPane = new JPanel(new FlowLayout());
contentPane.setOpaque(false);
contentPane.setBackground(new Color(0, 0, 0, 25));
JLabel label = new JLabel("Hello cruel world");
label.setForeground(Color.WHITE);
contentPane.add(label);
contentPane.add(new JButton(new AbstractAction("Bigger") {
#Override
public void actionPerformed(ActionEvent e) {
label.setFont(label.getFont().deriveFont(label.getFont().getSize() + 1f));
frame.pack();
}
}));
contentPane.add(new JButton(new AbstractAction("Smaller") {
#Override
public void actionPerformed(ActionEvent e) {
label.setFont(label.getFont().deriveFont(label.getFont().getSize() - 1f));
frame.pack();
}
}));
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
I've tried changing all components to non-opaque. I've tried revalidating the content pane after packing. What do I need to do to solve this?
Swing doesn't know how to paint transparent backgrounds properly so you need to do the painting yourself.
Check out Background With Transparency for more information and a couple of solutions.
But to set a frame transparent you should be using the setOpacity(...) method of the frame. Check out the section from the Swing tutorial on How to Create Translucent Windows;
So I set the setSize(500,500).. add some panels, the sum of panels Y is 500 like the JFrame but executing it shows an count Y of 525 am I missing something?
JPanel panel = new JPanel();
panel.setLayout(null);
getContentPane().add(panel);
//--------------------
JPanel top_panel = new JPanel();
top_panel.setLayout(null);
top_panel.setBackground(Color.blue);
top_panel.setBounds(0, 0, 500, 40);
panel.add(top_panel);
//------------------------------
JPanel middle_panel = new JPanel();
middle_panel.setLayout(null);
middle_panel.setBackground(Color.yellow);
middle_panel.setBounds(0, 40, 500, 385);
panel.add(middle_panel);
//-----------------------------
JPanel bottom_panel = new JPanel();
bottom_panel.setLayout(null);
bottom_panel.setBackground(Color.black);
bottom_panel.setBounds(0, 425, 500, 75);
panel.add(bottom_panel);
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
40+385+75 = 500 but to show all the panels i must
setSize(500,525);
then it fits
here's an image:
The frame size is the light blue rectangle outside bounds including the title bar. Your panels are appearing in the inner bounds which is frame size less than the frame border and frame title bar. Do you see how your marked space at the bottom is strangely the same height as the title bar?
After adding your panels/component to the frame and just before calling frame.setVisible(true), call frame.pack().
It would be also preferable if you embrace a layout manager (such as FlowLayout) and when necessary call setPreferredSize and let the layout manager do the layout. Normally one would call setPreferredSize over setBound, setSize, setMininumSize, setMaximumSize.
import javax.swing.*;
import java.awt.*;
public class FrameSize {
private JFrame frame;
FrameSize create() {
frame = createFrame();
frame.getContentPane().add(createContent());
return this;
}
private JFrame createFrame() {
JFrame frame = new JFrame(getClass().getName());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}
void show() {
// frame.setSize(500, 500);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private Component createContent() {
JPanel panel = new JPanel(null);
JPanel topPanel = new JPanel(null);
topPanel.setBackground(Color.blue);
topPanel.setBounds(0, 0, 500, 40);
panel.add(topPanel);
JPanel middlePanel = new JPanel(null);
middlePanel.setBackground(Color.yellow);
middlePanel.setBounds(0, 40, 500, 385);
panel.add(middlePanel);
JPanel bottomPanel = new JPanel(null);
bottomPanel.setBackground(Color.black);
bottomPanel.setBounds(0, 425, 500, 75);
panel.add(bottomPanel);
panel.setPreferredSize(new Dimension(500, topPanel.getBounds().height + middlePanel.getBounds().height + bottomPanel.getBounds().height));
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new FrameSize().create().show();
}
});
}
}
You shouldn't be setting size or calling setSize(...) or setBounds(...) as that's setting you up for similar problems in the future, or worse problems when you try to show your GUI on a different platform. Instead let the preferredSizes of your components and the layout managers do this work for you. If you absolutely must set the size of a component, then override getPreferredSize() and return a Dimension that is calculated to work for you. And yes, as per javajon, you should call pack() on the JFrame before displaying it.
For more discussions on the null layout, please read what one of the best Swing experts on this site, MadProgrammer, has to say in his answer here.
void setUpGUI() {
JFrame frame = new JFrame();
frame.setContentPane(new Board());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
class Board extends JPanel {
#Override
public void paintComponent(Graphics g) {
setLayout(new GridLayout(10, 9));
JButton b = new JButton("hello");
add(b);
g.setColor(Color.orange);
g.fillRect(20, 50, 100, 100);
}
}
For some reason the code only shows the rectangle, not the JButton. What am I doing wrong? Thanks!
The paintComponent() method is for painting only. You never create and add components to a panel in a painting method. Get rid of that code.
Also add a super.paintComponent() at the start of the method.
To add components to a panel you do something like:
Board board = new Board();
board.setLayout(...)
board.add(...);
or in the constructor of the board class you can set the layout and add components.