Java Applet, make the background transparent - java

I watched a tutorial on YouTube on how to display an image in Java, and he used something called "Applet" and "Graphics" to display it, I've got it to work, and I am happy with it. Now what I was planning to make is a chrome logo in the center of my screen, transparent with no background, and then chrome opens. I've called the class CustomChrome cus you know. Custom and stuff. I just want a cool opening whenever I start chrome.
Here is the current code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
public class CustomChrome extends Applet {
/**
*
*/
private static final long serialVersionUID = 1L;
private Image logo = null;
public void paint(Graphics g) {
this.setSize(960, 540);
if (logo == null)
logo = getImage("/chromelgo.png");
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(logo, 0, 0, 960, 540, this);
}
public Image getImage(String path) {
Image tempImage = null;
try {
URL imageURL = CustomChrome.class.getResource(path);
tempImage = Toolkit.getDefaultToolkit().getImage(imageURL);
} catch (Exception e) {
System.out.println("An error occured - " + e.getMessage());
}
return tempImage;
}
}
What I want to do, however, is the make the background + the window to vanish, Once that's was done I will set the image and window size to 1920x1080. How do I go forward on making the window behind the image disappear? I've heard something about implementing ActionListener, but still I ain't sure what to do.
Keep in mind! I have no experience with java so sorry for upsetting you if you try to help me :P

Okay, let's start with the really obvious issue, applets are effectively deprecated and you should stop using them, see Java Plugin support deprecated and Moving to a Plugin-Free Web for more details.
paintXxx is for painting, you should never change the state of a component from within a paint method (and you should not be calling setSize in an applet anyway). See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works and how you can make use of it
As a general piece of advice, I'd recommend ImageIO.read over Toolkit#getImage or ImageIcon for loading images, apart from throwing an Exception when the image can't be read (instead of failing silently), it's also a blocking call, meaning that when it returns, the image is fully loaded.
See Reading/Loading an Image for more details
A word of warning - What you're trying to do is not difficult per se, but it's involved and requires a certain amount of knowledge about how the API works.
Now what I was planning to make is a chrome logo in the center of my screen, transparent with no background, and then chrome opens.
Okay, well, this was never going to work with applets, as applets are intended to be displayed inside a browser, so you can't control the window, instead, you need something like a JFrame, see How to Make Frames (Main Windows)
What I want to do, however, is the make the background + the window to vanish, Once that's was done I will set the image and window size to 1920x1080. How do I go forward on making the window behind the image disappear?
Now, this is where the real fun begins. You're going to want to start by having a look at How to Create Translucent and Shaped Windows. This will allow you control the opacity of the frame, making it disappear, but allowing the content to remain, there are some tricks you need to do to pull it off, but that's the basic idea
So, this example will make a transparent window and display and image centered within it.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
BufferedImage img = ImageIO.read(getClass().getResource("/Chrome.png"));
ImageIcon icon= new ImageIcon(img);
JLabel label = new JLabel(icon);
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}
In this is example, I make use of a JLabel to display the image, in most cases, it's all you really need, see How to Use Labels for more details.
What I want to do, however, is the make the background + the window to vanish
Well, it just comes down to what you mean by vanish. You could just all dispose or setVisible on the window, which would close it, all you could use some animation to make it fade away ... and because I like animation...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
BufferedImage img = ImageIO.read(getClass().getResource("/Chrome.png"));
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
float opacity = 1.0f;
float delta = 0.05f;
#Override
public void actionPerformed(ActionEvent e) {
opacity -= delta;
if (opacity < 0.0f) {
opacity = 0.0f;
((Timer)(e.getSource())).stop();
frame.dispose();
}
frame.setOpacity(opacity);
}
});
timer.setInitialDelay(2000);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
}
Okay, there is a lot going on here, you'll want to have a read through Concurrency in Swing and How to use Swing Timers for more details, needless to say, it's a little complicated to get started with.
Basically, all this does is, waits 2 seconds and then every 40 milliseconds, decreases the frames opacity by a factor or 0.05 till it reaches 0 and it then disposes of the window.
Now, I might use a mixture of these techniques, for example, I might show the logo frame (maybe set to display on top), I would then show the main frame and then trigger the logo frame to fade out. This could be done from a controller class to simplify the code, but, that's up to you.
A would also suggest having a look at Creating a GUI With JFC/Swing

Related

paint() can't draw gif but png works fine?

I'm using a JLabel in an attempt to draw an animated gif image onto it. I can use the constructor new JLabel(new ImageIcon(FML.class.getResource("giphy.gif"))); and that will work just fine however when I go override the paint method it just doesn't seem to want to draw it, at all. The image isn't still, it's not there! I should mention that both methods shown below work perfectly fine with a PNG but not a GIF. Am I missing something or is this a java bug?
(Using java 1.8)
Edit: I've been looking around and it seems that I'm not completely off point on what I need to be doing but I'm missing something. I've seen many posts Like this one but that doesn't seem to be working in this case.
I should note that there's literally nothing else going on in the class, it's a simple JPanel.
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FML {
public static void main(String[] args) {
new FML();
}
public FML() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private ImageIcon animatedGif;
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton(new ImageIcon(FML.class.getResource("FmDxW.png")));
btn.setSize(50, 50);
btn.setRolloverEnabled(true);
animatedGif = new ImageIcon(FML.class.getResource("giphy.gif"));
btn.setRolloverIcon(animatedGif);
add(btn);
btn.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
animatedGif.getImage().flush();
}
});
//I need this
final ImageIcon image = new ImageIcon(FML.class.getResource("giphy.gif"));
//To render over this
final ImageIcon image2 = new ImageIcon(FML.class.getResource("fmDxW.png"));
//I'm not understanding why I can add the gif into the constructor but the paint method fails.
JLabel label = new JLabel(image) {
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(image2.getImage(), 64, 64, this);
}
};
//setSize because I want to be 100% sure that it's loading the correct size.
//Removing it doesn't affect the problem at hand.
label.setSize(64, 64);
add(label);
}
}
}
g.drawImage(image2.getImage(), 64, 64, this);
Assuming the size of your image is 64, why are you trying to draw the second image outside the bounds of the label? When I change the location to (0, 0) the gif paints fine for me (but I'm not using an animated gif).
both methods shown below work perfectly fine with a PNG but not a GIF.
I don't see how for the reason I gave above. In any case, did you try it with a normal gif?
This is a reason why you should not be trying to manage the painting yourself since now you need to worry about location and hardcoding a location is not a good practice. Let your layout manager do this for you.
Again, why are you doing this. Why are you trying to override paint method to draw a second image?
Instead you should be doing something like:
Drawing both images in the paintComponent() method
Use a panel with an OverlayLayout, Then you can stack the two labels on top of one another.
You can even set the layout manager of the layout to something like a GridBagLayout and then when you add a JLabel to the label it will automatically be centered.
//setSize because I want to be 100% sure that it's loading the correct size.
You said you know how layout managers work. Well if you do then you know that this statement will do nothing since the layout manager will override any value you set, so using code like this wrong and shows a basic lack of understanding and should not be included in an MCVE since the point of the MCVE` is to simplify the problem as much as possible.

Why does theBufferedImage output look different than on screen in the JFrame window on Linux platform?

I am working on one project that requires to capture image data of on-screen GUI (e.g. JFrame). Somehow, my application is working for windows and Mac OS, but for Linux it's not giving same Image output as on-screen GUI.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.File;
class jframeExample {
public static BufferedImage getImageData(
Component component) {
BufferedImage image = new BufferedImage(
component.getWidth(),
component.getHeight(),
BufferedImage.TYPE_INT_RGB
);
component.printAll( image.createGraphics() );
return image;
}
public static void main(String[] args){
Runnable r = new Runnable() {
public void run() {
final JFrame f = new JFrame("JFrame Border");
f.setLayout(new BorderLayout());
f.setLocation(500,300);
f.setSize(560, 420);
f.getContentPane().setBackground(Color.BLUE);
JMenuItem screenshot =
new JMenuItem("TakeSnapshot");
screenshot.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae) {
BufferedImage imageOutput = getImageData(f);
try {
// write the image as a PNG
ImageIO.write(
imageOutput,
"png",
new File("CapturedImage.png"));
} catch(Exception e) {
e.printStackTrace();
}
}
} );
JMenu menu = new JMenu("Menu");
menu.add(screenshot);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
f.setJMenuBar(menuBar);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
Above code will give GUI with Menu option to capture it as an image output. You can see on-screen GUI and image output of it as attached files.Generated image is little different than on-screen GUI. See left/right edge of JFrame border, it overlap with contentPane blue color.
How to get exact same image as on-screen GUI OR tweak left/right border so that it don't overlap with contentPane area? I tried couple of options using LookAndFeel class but not getting any success yet. Any help/suggestion would be appreciated.
On-Screen GUI
CapturedImage
Swing doesn't paint the entire frame. The frame is a widget of the OS.
Try using Screen Image.
It will use the Robot class to take an image when a frame is specified as the component. Otherwise is will use the Swing painting.
Quick Fix
Try changing...
BufferedImage imageOutput = getImageData(f);
to
BufferedImage imageOutput = getImageData(f.getContentPane());
This might work on Linux too (I can't test it at the moment) and would be an easy fix to your problem.
Solution
Alternatively you can use the Robot class. Robot has a more compatible screen capture capability, but this means serious alterations to your code. You can find the code at the very bottom of my answer. Let me explain the reasons for all the changes...
Robot is the class needed to perform screen captures. It can capture either the full desktop or a part of the screen. In this case, we will let it capture the blue part of your application by finding out the respective XY coordinates on the desktop. Robot needs to be static in this case because you are trying to access it through the main() method. Therefore the Robot variable needs to be outside of the main() method so that the JMenuItem's ActionListener can access it.
If you perform the screen capture through the menu, the menu will appear in the screen capture because you haven't given the menu time to disappear. As a result, a delay needs to be added. Simultaneously, this delay needs to occur in a separate thread, otherwise your menu will just freeze... The way I created the new thread is called a Lambda expression. It's just an easy way to easily create a new thread that starts immediately, that's all. It works like this: new Thread(() -> { /* Do something */ }.start();
Next is to find the coordinates of the blue part of the screen. This is a simple getLocationOnScreen() on the context pane of the frame (or which-ever component you wish to capture).
Now the screen capture can be created by Robot and saved to file using your previous code.
That's all! If you have any questions just place a comment and I'll check back later.
Code
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.File;
class jframeExample {
public static BufferedImage getImageData(
Component component) {
BufferedImage image = new BufferedImage(
component.getWidth(),
component.getHeight(),
BufferedImage.TYPE_INT_RGB
);
component.printAll( image.createGraphics() );
return image;
}
static Robot robot = null;
public static void main(String[] args){
Runnable r = new Runnable() {
public void run() {
try {
if(robot == null) robot = new Robot();
} catch (AWTException e1) {
e1.printStackTrace();
}
final JFrame f = new JFrame("JFrame Border");
f.setLayout(new BorderLayout());
f.setLocation(500,300);
f.setSize(560, 420);
f.getContentPane().setBackground(Color.BLUE);
JMenuItem screenshot =
new JMenuItem("TakeSnapshot");
screenshot.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent ae) {
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
int screenshotX = f.getContentPane().getLocationOnScreen().x;
int screenshotY = f.getContentPane().getLocationOnScreen().y;
int screenshotWidth = f.getContentPane().getWidth();
int screenshotHeight = f.getContentPane().getHeight();
BufferedImage imageOutput = robot.createScreenCapture(new Rectangle(screenshotX, screenshotY, screenshotWidth, screenshotHeight));
try {
// write the image as a PNG
ImageIO.write(
imageOutput,
"png",
new File("CapturedImage.png"));
} catch(Exception e) {
e.printStackTrace();
}
}).start();
}
} );
JMenu menu = new JMenu("Menu");
menu.add(screenshot);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
f.setJMenuBar(menuBar);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}

Java Canvas repaint() is flickering

So I finally got a Canvas to work the way I want it but it flickers constantly, repaint() is run 20 times a second and the flicking does lessen when I make it run 10 times a second.
package pd.data;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import pd.areas.MainMenu;
#SuppressWarnings("serial")
public class Main extends JFrame implements Runnable {
private JPanel contentPane = new JPanel();
private Thread gameThread = new Thread(this);
public boolean running = false;
#SuppressWarnings("unused")
private int current = PDU.PD_MAIN_MENU;
private MainMenu mainmenu;
public Main() {main.setTitle("PD");
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setLocation(SPU.screenWidth / 2 - SPU.windowSize.width / 2,
SPU.screenHeight / 2 - SPU.windowSize.height / 2);
main.setResizable(false);
main.setVisible(true);
contentPane.setLayout(new BorderLayout(0, 0));
contentPane.setPreferredSize(SPU.windowSize);
main.setContentPane(contentPane);
main.pack();
mainmenu = new MainMenu();
contentPane.add(mainmenu, BorderLayout.CENTER);
this.gameThread.start();
}
#Override
public void run() {
running = true;
while (running) {
{
mainmenu.repaint();
}
try {
Thread.sleep(SPU.TSU);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Main();
}
}
And below is my MainMenu class:
package pd.areas;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
#SuppressWarnings("serial")
public class MainMenu extends Canvas{
BufferedImage img = null;
public MainMenu() {
this.setBackground(Color.BLACK);
}
public void paint(Graphics graphics){
try {
img = ImageIO.read(this.getClass().getResource(
"/image.png"));
} catch (IOException e1) {
e1.printStackTrace();
}
graphics.drawImage(img, this.getWidth() / 2 - img.getWidth()/2, 50, null);
}
}
Although the flicker is actually a nice effect, it's going to effect the whole canvas and not just the image I'm guessing, how can I fix the flicker?
Don't use java.awt.Canvas. Use a JPanel instead.
Draw in the JPanel's paintComponent method.
Don't forget to call your super's painting method which for paintComponent would be super.paintComponent(graphics)
Never try to read in an image from within any painting method. That will slow down painting and make your program seem unresponsive. Why keep reading in the same image over and over again anyway? Read it in once and save it to a variable.
Though this thread was opened 5 years ago, it's still going to be an issue for anyone new to Java SE.
I had the same problem with Canvas myself, but wasn't convinced enough to switch to javax components because I recalled a VLC project called JVLC which used Canvas to render videos flawlessly (granted jvlc uses some native code).
Tip 1: perhaps it's better to try JPanel instead.
Tip 2: in gaming systems, it's better to use a game engine (it'll save you lots of time).
Tip 3: in gaming systems, implement a fps mechanism rather than calling repaint() on every change.
Tip 4: if you have to call more than 10 lines of code in your paint() implementation you're going to slow it down. It's better to draw to a BufferedImage for every graphical change you need to make to your app, then have the paint() implementation itself draw just the image itself. This should play nicely with an fps mechanism and will reduce the chances of any flickering.

Move a JLabel to Front

I am placing two images. One is supposed to be the background picture and the other one a picture of a stick-figure. I'd like to get the stick figure in front of the background. I can accomplish this by inserting the code to put the background picture after the code to display the stick figure. I was wondering if there was anyway to accomplish the same thing, by inserting the stick figure code after the background code, so I could keep placing new JLabels on top of the background.
The code that works:
guy.setBounds(0,0,100,100);
panel.add(guy);
backgroundPic.setBounds(0,0,550,550);
panel.add(backgroundPic);
setVisible(true);
The code that I'd like to work:
backgroundPic.setBounds(0,0,550,550);
panel.add(backgroundPic);
guy.setBounds(0,0,100,100);
panel.add(guy);
setVisible(true);
If you are only worrying about one background image, then I would suggest to extend JPanel, override paintComponent and paint the background image.
If you have to care about the Z-order of several components, then JLayeredPane is your best alternative.
Here is a small snippet showing the first option:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test2 {
private static class PanelWithBackground extends JPanel {
private Image backgroundImage;
private Point backgroundLocation = new Point();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (getBackgroundImage() != null) {
g.drawImage(getBackgroundImage(), backgroundLocation.x, backgroundLocation.y, this);
}
}
public Image getBackgroundImage() {
return backgroundImage;
}
public void setBackgroundImage(Image backgroundImage) {
this.backgroundImage = backgroundImage;
repaint();
}
public Point getBackgroundLocation() {
return backgroundLocation;
}
public void setBackgroundLocation(Point backgroundLocation) {
this.backgroundLocation = backgroundLocation;
repaint();
}
}
protected static void initUI() throws MalformedURLException {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PanelWithBackground panelWithBackground = new PanelWithBackground();
panelWithBackground.setLayout(null);
panelWithBackground.setBackgroundImage(new ImageIcon(new URL(
"http://2.bp.blogspot.com/-PqKuKt5mRmc/Tvi-K-4FVVI/AAAAAAAACKg/YwzkME5gGvk/s1600/black+background.jpg")).getImage());
JLabel guy = new JLabel(new ImageIcon(new URL(
"http://www.clipproject.info/Cliparts_Free/Menschen_Free/Clipart-Cartoon-Design-04.gif")));
// Next 2 lines should rather be performed by a LayoutManager
panelWithBackground.setPreferredSize(new Dimension(1024, 768));
guy.setBounds(50, 200, guy.getPreferredSize().width, guy.getPreferredSize().height);
panelWithBackground.add(guy);
frame.add(panelWithBackground);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
initUI();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
You can use the Z order, to indicate the order the components should be rendered:
java.awt.Container.getComponentZOrder(Component)
According documentation:
Returns the z-order index of the component inside the container. The
higher a component is in the z-order hierarchy, the lower its index.
The component with the lowest z-order index is painted last, above all
other child components.
Parameters: comp the component being queried
Returns: the z-order
index of the component; otherwise returns -1 if the component is null
or doesn't belong to the container
I wont claim to be a java expert nor will i claim this is correct, just a guess, but try and remove the
.setBounds()
and if that has no effect, try using
.setSize()
best of luck :)

Pass mouse events to applications behind from a Java UI

The question I have is exactly same in requirement as How to pass mouse events to applications behind mine in C#/Vista? , but I need the same for a Transparent Java UI. I can easily create a transparent Java UI using 6.0 but couldn't get any info about passing events through the app to any applications(say a browser) behind.
I believe this will answer your question. To run it you will need Java 6 update 10 and above.
I tested it on Windows Vista
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ClickThrough {
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame f = new JFrame("Test");
f.setAlwaysOnTop(true);
Component c = new JPanel() {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
g2.setColor(Color.gray);
int w = getWidth();
int h = getHeight();
g2.fillRect(0, 0, w,h);
g2.setComposite(AlphaComposite.Clear);
g2.fillRect(w/4, h/4, w-2*(w/4), h-2*(h/4));
}
};
c.setPreferredSize(new Dimension(300, 300));
f.getContentPane().add(c);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
com.sun.awt.AWTUtilities.setWindowOpaque(f,false);
}
}
Note that you need to either have an undecorated window or one that is decorated by Java alone (not the default OS decoration) otherwise the code won't work.
Savvas' answer helped me perfectly even on MacOS X 10.7.3 using Java 1.6.0_31. Thanks!
The only thing: I additionally had to set
f.setUndecorated(true);
This is not answer, but an update which corrects dangerous issues to the accepted answer as well as providing an example compatible with Java 7+
Per-Pixel alphering checks each pixel in the window to determine if it's transparent or not. If it's transparent, then the mouse events are allowed to pass through it, if its is not transparent, the mouse events will be caught by the window. This is generally an OS level issue.
The example is you provide is actually doing some very dangerous things, first it's painting a translucent color onto a opaque component, this means that Swing doesn't know that it should actually be painting anything under the component and could also result in a number of very nasty paint artifacts, as Swing only knows about opaque and transparent component, it doesn't know about semi-transparent components, so you need to trick the API.
When performing custom painting, you should always call super.paintComponent to ensure that the Graphics context is setup correctly before painting. In your case, you should also make the component transparent using setOpaque and passing it false
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestFrame {
public static void main(String[] args) {
new TestFrame();
}
public TestFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setOpaque(false);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLUE);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2d.dispose();
}
}
}
You could try using the Robot Class http://java.sun.com/javase/6/docs/api/java/awt/Robot.html which allows you to specify system events to the low level operating system, specifically things like mouse events.

Categories