How to create transluent window in Java swing? - java

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.

Related

How to put transparent JPanel over an opaque JPanel?

I have added webcam to my software using com.github.sarxos.webcam. It has a JPanel named WebcamPanel and has predefined webcam sizes while I need my custom size of pictures. I managed to crop the images taken from webcam at 640 x 480. I want to put a red rectangle over the WebcamPanel to show that this part of the image will be saved.
public class CardPanel {
Dimension panelDim = new Dimension(640, 480);
public Cardpanel(){
//....Button Defined earlier
btnTakePhoto.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
webcameFrame();
}
});
}
private void webcamFrame(){
imageFrame = new JFrame("Photo Capture");
// Did some calculations to put window at center
imageFrame.setBounds(screenSize.width / 2 - frameWidth / 2, screenSize.height / 2 - frameHeight / 2, frameWidth,
frameHeight);
imageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
imageFrame.setContentPane(contentPane);
JPanel webcamWindow = new JPanel();
RedHighlighter redHighlighter = new RedHighlighter();
Webcam webcam = Webcam.getDefault();
webcam.setViewSize(WebcamResolution.VGA.getSize());
webcamPanel = new WebcamPanel(webcam);
webcamPanel.setFillArea(true);
webcamPanel.setMirrored(false);
webcamPanel.setPreferredSize(panelDim);
webcamWindow.add(webcamPanel);
webcamWindow.add(redHighlighter);
hBox.add(webcamWindow);
}
// Sub Class just for drawing the rectangle
public class RedHighlighter extends JPanel{
public RedHighlighter() {
// If you delete the following line, nothing will appear
setPreferredSize(new Dimension(400, 400));
}
#Override
public void paint(Graphics g) {
g.setColor(Color.RED);
g.drawRect(100, 100, 200, 200);
}
}
}
I used JLayeredPanes but no matter what you do it will cover whole size and will show only one item at a time.
Overriding paint method helped me draw the rectangle but it's on side and not on top.
As you can see the rectangle has pushed WebcamPanel towards left. I want webcamPanel to remain in it's position while the rectangle on top of it at center. Please suggest an efficient approach to this problem. Thanks!
The one JPanel is being pushed over due to the layout managers that you are using. If you want one JPanel to overly another, you'll want to consider using a JLayeredPane, with the video images in the lower level, perhaps the JLayeredPane.DEFAULT layer, and the drawing JPanel above it.
Other options and issues:
You could potentially draw in the same JPanel that the image is being displayed in by displaying the image in a paintComponent method as well as the drawing (in lines of code after the image is displayed.
Look into use of a JLayer as a way of adding a drawing "decoration" over your image.
Always override paintComponent, not paint
Always call the super's painting method within your override.
It worked!
public class MyWebcamPanel extends WebcamPanel {
/**
*
*/
private static final long serialVersionUID = 2808353446021354508L;
public MyWebcamPanel(Webcam webcam) {
super(webcam);
}
#Override
protected void paintComponent(Graphics g) {
int x = 180;
int y = 87;
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(x, y, 640-2*x, 480-2*y);
}
}

Functional transparency on mac but not windows?

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!

How to properly work with transparent JPanel within a non-opaque JFrame?

I am working on some application designed to be not 100% opaque, so it basically darkens the desktop of the user and my Swing interface is shown on top of this "dark veil".
It seems to me that, when some Swing components are being moved over that veil, my JFrame would need to be repainted for my moving components not to leave a trail behind them. The thing is that repainting the JFrame is too slow and my application wouldn't run smoothly anymore.
For your convenience, I created a SSCCE class that illustrates my issue, here it is:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class TransparentFrameSSCCE extends JFrame {
private static final Dimension SCREEN_DIMENSIONS = Toolkit.getDefaultToolkit().getScreenSize();
private final JPanel movingPanel;
private TransparentFrameSSCCE() {
super();
this.setUndecorated(true);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(TransparentFrameSSCCE.SCREEN_DIMENSIONS);
// This makes my JFrame transparent (its alpha component is set to 0)
this.setBackground(new Color(0, 0, 0, 0));
this.movingPanel = new JPanel();
this.movingPanel.setBounds(0, 0, 50, 50);
this.movingPanel.setBackground(Color.RED);
final JPanel contentPane = new JPanel();
// This makes my panel semi-transparent (its alpha component is set to 128)
contentPane.setBackground(new Color(0, 0, 0, 128));
contentPane.setLayout(null);
contentPane.add(this.movingPanel);
this.setContentPane(contentPane);
}
#Override
public void setVisible(final boolean isVisible) {
super.setVisible(isVisible);
new Thread(new Runnable() {
#Override
public void run() {
int x, y;
for(;;) {
x = TransparentFrameSSCCE.this.movingPanel.getLocation().x;
y = TransparentFrameSSCCE.this.movingPanel.getLocation().y;
TransparentFrameSSCCE.this.movingPanel.setLocation(x + 5, y);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public static void main(final String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TransparentFrameSSCCE().setVisible(true);
}
});
}
}
Would anyone know any other way to do so?
UPDATE: Following #MadProgrammer's directions about Swing components transparency behavior, this is how to deal with my "dark veil". It works perfectly. Many thanks to him :)
final JPanel contentPane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(0, 0, 0, 128));
g2d.fill(new Area(new Rectangle(new Point(0, 0), getSize())));
g2d.dispose();
}
};
contentPane.setOpaque(false); // Instead of: contentPane.setColor(new Color(0, 0, 0, 128)
Java components don't have a concept of transparency, they are either opaque or fully transparent (alright, the new transparency support for top level windows is an exception ;))
What you need to do is create a custom component that is fully transparent and the override it's paintComponent and fill the area of the component with your translucent color.
Also, don't modify the state of Swing components outside of the context of the Event Dispatching Thread, strange things begin to happen. A better solution might be to use a javax.swing.Timer
For example
Create rectangle with mouse drag, not draw
Java Swing: Transparent PNG permanently captures original background
How to make a transparent JFrame but keep everything else the same?
You may also want to take a look at Concurrency in Swing
Check out Backgrounds With Transparency for a simple explanation of the problem. Basically, you need to make sure your custom component paints the background.
Or instead of doing the custom painting you can take advantage of the AlphaContainer class which will do the painting for you:
//this.setContentPane( contentPane);
this.setContentPane( new AlphaContainer(contentPane) );

Caret in transparent JTextPane

I have a transparent, editable JTextPane in a program I'm writing (to allow a background to show through), and everything works pretty well, except for the text caret.
The caret itself acts normally, but every time it's drawn, it breaks the transparency of the area right behind it, as seen in the image:
Is there any way to make the background of the caret transparent without repainting the whole frame? DefaultCaret doesn't have a setOpaque() method, so I'm not quite sure how to go about this.
Thanks!
EDIT: I can't answer my own question yet, but I ended up writing an SSCCE that works perfectly, so there is definitely something else wrong with my program. For future reference, this is the (working) code I wrote:
import java.awt.*;
import javax.swing.*;
class TransparentScrollPane extends JScrollPane {
public TransparentScrollPane(Component view) {
super(view);
this.setPreferredSize(new Dimension(540,480));
this.setOpaque(false);
this.viewport.setOpaque(false);
this.setBorder(null);
}
}
public class TextPaneExample extends JTextPane {
public TextPaneExample()
{
super();
this.setOpaque(false);
}
public void paintComponent(Graphics g)
{
g.setColor(new Color(255,255,255,128));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(640, 480);
JPanel panel = new JPanel();
panel.setBackground(new Color(255,128,255));
TextPaneExample textPane = new TextPaneExample();
TransparentScrollPane scroller = new
TransparentScrollPane(textPane);
textPane.setBackground(new Color(255,255,255,128));
frame.add(panel);
panel.add(scroller,BorderLayout.CENTER);
frame.setVisible(true);
}
}
See Backgrounds With Transparency for the problem and a couple of solutions.
Basically you can just use:
panel.add( new AlphaContainer(componentWithTransparency) );
For your first question you get one free answer :) Future questions should include a proper SSCCE that demonstrates the problem.

Turning a JFrame black when opening another window

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).

Categories

Resources