Searching stackoverflow for the answer to this question only led me to other questions asking how to accomplish transparency on one or the other, none that came up had the issue of transparency functioning on one, but not the other.
I'm sure by now you've been able to figure out the issue, but i'll explain in a little more depth... A friend and I are working on a java application and on running, a launcher is brought up. He uses a mac, and the JFrame was gotten to be transparent, however when I sync'd the project to my computer; A windows PC, The background of the JFrame was visible and the graphics on top flashed, kind of like a strobe light.
If anyone could provide any kind of insight it would be greatly appreciated, and if more information needs to be provided, I will try to go through program more deeply, and get more info.
private void setUpWindow(int width, int height) {
setIconImage(images.get(1));
setSize(width, height);
setUndecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(new Color(0,255,0,0));
setLayout(new BorderLayout());
addMouseListener(this);
setResizable(false);
setLocationRelativeTo(null);
addComponents();
requestFocus();
setVisible(true);
}
private void addComponents() {
setContentPane(new BackPanel());
getContentPane().setBackground(Color.BLACK);
setLayout(new BorderLayout());
panel.setSize(screenSize);
add(panel);
}
Window size is 1000x600
public class BackPanel extends JPanel {
public BackPanel() {
setOpaque(false);
setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D overGraphics2D = (Graphics2D)g.create();
overGraphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
overGraphics2D.setColor(Color.BLACK);
overGraphics2D.fill(getBounds());
overGraphics2D.dispose();
}
}
public class DrawingPanel extends JPanel
{
public DrawingPanel()
{
setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
refreshTimer.schedule(new refreshTimer(), 1);
}
}
The referred refresh timer has a delay of '1' so that it is started when the launcher is drawn.
Also, ideas from this; how to set JFrame background transparent but JPanel or JLabel Background opaque? were used in setting up the transparency.
The referred refresh timer has a delay of '1' so that it is started when the launcher is drawn.
This is a problem with cross platform drawing because different operating systems have different "resolutions". You need to draw/call the method to draw inside that paintComponent() method. You also need to make the window full screen (or kinda fake full screen) by getting the screen size then setting the window full screen. Like this:
//in the constructor after declaring the frame undecorated
setSize(Toolkit.getDefaultToolkit().getScreenSize());
Hope that helps!
Related
I have noticed some weird behaviour with setting an image as a background for my JFrames. I want to have a background image for both Frames display when they are created.
When i create Window1 inside my main method it only shows the background after i manually resize the window. When i click the button in Window1 and create window2 inside Window1, Window2 displays the background image correctly. When i create Window2 inside my main method the background image also does not show correctly.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestStart {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window1();
}
});
}
}
public class Window1 extends JFrame {
Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Tim\\Desktop\\water.jpg");
public Window1() {
super("gridtest");
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
new Window2();
}
});
pack();
setVisible(true);
}
}
public class Window2 extends JFrame {
Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Tim\\Desktop\\water.jpg");
public Window2() {
super("gridsecond");
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
pack();
setVisible(true);
}
}
I tried adding in revalidate()/repaint() calls and calling the paint method at different points in my code, but except for the weird behaviour i described above, i cant get the background image to show without resizing my window.
Disclaimer: I know it's not good practice to create a new JFrame for every window, but i am not able to change the whole project structure, so im stuck with this.
So, a series of issues that might be causing your issue...
First, using Toolkit.getDefaultToolkit().getImage
Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Tim\\Desktop\\water.jpg");
The problem with this is, the image loading is down on a seperate thread. This means that when getImage returns the image may or may not have actually been loaded
Second, when calling drawImage, you pass null as the ImageConsumer, so the component won't be notified of changes to the images "loaded" state and won't be able to schedule updates to the component accordingly...
this.setContentPane(new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img,0,0,getWidth(),getHeight(),null);
}
});
Three, this is more of a side effect, but, you've set the contentPane manually using a JPanel, which by default uses a FlowLayout, so using BorderLayout constraints is actually kind of pointless.
setLayout(new BorderLayout());
this.setContentPane(new JPanel(){
//...
JButton btn = new JButton("klick");
add(btn, BorderLayout.CENTER);
Besides, BorderLayout is the default layout manager used by window based components ;)
So, how would you fix this issue? Well, immediately, you could pass this as the ImageConsumer...
g.drawImage(img,0,0,getWidth(),getHeight(),this);
This will allow the component to monitor the loading state of the image and trigger repaints as required.
A longer term solution would be to stop using Toolkit.getDefaultToolkit().getImage (and by extension, ImageIcon), as they can be annoying, and start using ImageIO instead.
Apart from supporting a wider range of image formats, the API won't return till the image is fully loaded or an error occurred (try diagnose loading issues with the other APIs 🙄)
See Reading/Loading images for more details
I'm back with a problem about java-graphics by swing... I want to paint some stuff at a jframe, here is the code:
PaintUtil-class:
public class PaintUtil extends JPanel{
public PaintUtil(){
this.setFocusable(true);
this.requestFocus();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println("Repainted");
g.drawstuff...
}
}
Main-class:
public static PaintUtil util = new PaintUtil();
JFrame frame = new JFrame();
frame.setSize(500,600);
frame.setRezisable(false);
frame.add(util);
frame.setDefaultCloseOperation( 3 );
frame.getContentPane().setColor(Color.BLACK);
setup(); //This add some buttons
frame.setVisible(true);
util.repaint(); //not working
util.paintComponent(frame.getGraphics()); //works
Can you guys help me?
There is no error, no message in the console, just nothing
frame.setLayout(null);
Don't use a null layout. Swing was designed to be used with layout managers. Get rid of that statement.
By default the size of your panel is (0, 0) so there is nothing to paint.
You will need to override the getPreferredSize() method of your panel so the layout manager can do its job.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
I have a custom JLayeredPane, and I am repainting it in my game loop. There are two custom JPanels added into the JLayeredPane. These are foreground and background JPanels. How do I successfully only draw my background JPanel once, (And repaint when window is re-sized or any other reason) to reduce impact on system resources, while continuing to update my foreground JPanel constantly.
To re-iterate, I dont want to constantly repaint the background JPanel in a loop. I want to repaint it only when it is nessessary, as the background does not change. and is large.
In my attempt to do this, I have only drawn the background once. However. the background JPanel is simply not visible. while the foreground JPanel updates as normal. It is almost as if the foreground JPanel paints ontop of the background JPanel, even though I have both of the JPanels set to setOpaque(false)
I have made a mvce which shows my attempt at only drawing the background JPanel once, while updating the foreground JPanel constantly.
The problem with my code is that the background JPanel does not show.
Now. I know that if I were to draw it constantly it would show. But that defeats the purpose of what i'm trying to do. I am trying to only draw it once, and have be seen at the same time
My code successfully only draws the background JPanel once. The problem is that the background JPanel does not show. How do I fix THIS problem
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main extends JLayeredPane {
static JFrame frame;
static Main main;
static Dimension screenSize;
public Main() {
JPanel backPanel = new BackPanel();
JPanel frontPanel = new FrontPanel();
add(backPanel, new Integer(7));
add(frontPanel, new Integer(8));
new Thread(() -> {
while (true){
repaint();
}
}).start();
}
public static void main(String[] args) {
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frame = new JFrame("Game"); // Just use the constructor
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main = new Main();
frame.add(main, BorderLayout.CENTER);
frame.pack();
frame.setSize(screenSize);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class BackPanel extends JPanel{
public boolean drawn = false;
public BackPanel(){
setVisible(true);
setOpaque(false);
setSize(screenSize);
JLabel test1 = new JLabel("Test1");
JLabel test2 = new JLabel("Test2");
add(test1);
add(test2);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawOnce(g);
}
public void drawOnce(Graphics g){
if (!drawn){
g.setColor(Color.red);
g.fillRect(0, 0, screenSize.width, 200);
drawn=true;
}
}
}
public class FrontPanel extends JPanel{
public FrontPanel(){
setVisible(true);
setOpaque(false);
setSize(screenSize);
JLabel test = new JLabel("Test");
add(test);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(0+screenSize.width/2, 0, screenSize.width/4, 300);
}
}
}
Try RepaintManager.currentManager(component).markCompletelyClean(component). It will prevent the component from repainting. You might need to do this after each time you add new components.
http://docs.oracle.com/javase/6/docs/api/javax/swing/RepaintManager.html#markCompletelyClean%28javax.swing.JComponent%29
I don't know if this two lines of code
super.paintComponent(g);
drawOnce(g);
are the root of problem, I sincerly don't remember how paintComponent works (a test could help) but try to swap them :
drawOnce(g);
super.paintComponent(g);
maybe, on your original version, you tells JVM to paint the whole component and, only after the AWTEvent has been added to the queue, to draw what you need.
I guess that the awt's documentation will explain it.
I work with java and I want to make a translucent window (like a black with 80% alpha). The basis of my code is those in the following post: How to make a transparent JFrame but keep everything else the same?
The problem is that when I run my program, the window is translucent but as you may see on the following picture, the background color (magenta) appears only on the text, not on the white.
Even worse, when I choose a black with transparency Color(0,0,0,125) as drawing color, nothing appears on the screen.
Here is what I have so far :
public class DssWindow extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 2455172975892566000L;
/**
*
*/
public DssWindow()
{
super("My frame");
setUndecorated(true);
setBackground(new Color(0,0,0,0));
setAlwaysOnTop(true);
JPanel contentPane = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(!(g instanceof Graphics2D))
{
return;
}
Graphics2D gr = (Graphics2D)g.create();
gr.setColor(new Color(255,0,255,200));
gr.fillRect(0, 0, getWidth(), getHeight());
}
};
contentPane.setOpaque(false);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
contentPane.setPreferredSize(new Dimension(screen.width,screen.height));
setContentPane(contentPane);
pack();
}
}
Do someone knows/has a clue of what is the problem ?
I am working on Linux (may this is a part of the answer).
Thank you.
Ok, my problem is stated here: Java Window Translucency on Linux
Graphics drivers seems to be the cause of this behaviour.
I wan't to make my main JFrame become darken when the focus is on another window.
This is an example from the game Football Manager 2012. First the main window is selected and it looks like it should, then when it is loading, it turns darker and unselectable. I wan't to have this effects on my own application, but im not really sure how, not even sure what to google?
Im guessing its a JWindow that appears and the JFram becomes unselectable in the background. I'm planing to use it on a help-window in my application, that is a JWindow right now.
Andrew Thompson has the right idea, only it's easier to use the glass pane feature of your frame's JRootPane. Here's some working code: In your frame class, invoke
getRootPane().setGlassPane(new JComponent() {
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
});
Then, to show the "curtain", invoke
getRootPane().getGlassPane().setVisible(true);
In the code above, change the alpha transparency value of 100 in order to find the suitable darkness.
..wan't the JFrame to go back to normal after the new window is closed. I tried setVisible(false) but it didn't work.
It works in this example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ShadowedFrame extends JFrame {
ShadowedFrame() {
super("Shadowed Frame");
getRootPane().setGlassPane(new JComponent() {
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
});
JButton popDialog = new JButton("Block Frame");
popDialog.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
getRootPane().getGlassPane().setVisible(true);
JOptionPane.showMessageDialog(ShadowedFrame.this, "Shady!");
getRootPane().getGlassPane().setVisible(false);
}
});
setContentPane(popDialog);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationByPlatform(true);
setSize(350,180);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ShadowedFrame().setVisible(true);
}
});
}
}
(Untested, but..) Seems like a good task for a JLayeredPane. Create a JComponent that is set transparent and add that to the top level of the layered pane. In the paintComponent(Graphics) method of the component, set a semi-transparent color and fill the full area with it. In normal use (non-dimmed), call customComponent.setVisible(false).
Update
Or, as Ingo pointed out, use the glass pane.
I'm guessing its a JWindow that appears and the JFrame becomes unselectable in the background
It is more likely a modal JDialog. When a modal dialog is visible, the frame/window that is the owner becomes inaccessible (cannot be clicked on).