1

I have an undecorated JFrame with some contents on it (Labels, Images, etc.). I need the JFrame to pass all the events through it. For example: when a click is made on that JFrame, I want it to pass that click through, to the window/anything that is underneath the frame.

Problem Example:

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);
}
  • In this case, the JFrame has a border with close/minimize/fullscreen controls, and graphics on the JFrame still catch the events while just the transparent parts pass them through. I need both (transparent parts, and with graphics) to pass through the events.

Video Example of my goal: https://www.youtube.com/watch?v=irUQGDDSk_g

Similar question:

Pass mouse events to applications behind from a Java UI

  • This question tries to achieve a similar goal, but the JFrame is decorated (has close/minimize controls with an outer frame), and graphics still catch the user control events.

Question: How can I make a JFrame with graphics, that will not catch the events from the user controlling, but to pass in through?

Community
  • 1
  • 1
Victor2748
  • 4,149
  • 13
  • 52
  • 89
  • If you're painting directly to the frame, then, I would discourage it. There are ways you could do this, but it would be simpler to attach a MouseListenerer directly to the child components. Consider providing a runnable example which demonstrates you're problem – MadProgrammer Jan 11 '15 at 19:39
  • @MadProgrammer Ok, I will... – Victor2748 Jan 11 '15 at 19:40
  • @MadProgrammer I provided the runnable example with the problem, please answer the question if you can, thank you. – Victor2748 Jan 11 '15 at 19:43
  • Set the frame undecorated. It'd probably be easier to set the JPanel (c) to be transparent (setOpaque(false)) and there are now better ways to make the window transparent that don't rely on private APIs – MadProgrammer Jan 11 '15 at 19:43
  • @MadProgrammer When I set the frame undecorated 'f.setUndecorated(true)' it gives me an 'IllegalStageException'. (try running it and you will see the full error) – Victor2748 Jan 11 '15 at 19:44
  • The frame can't be visible/displayable when you set it undecorated – MadProgrammer Jan 11 '15 at 19:49
  • @MadProgrammer What do you mean by that? How can I reproduce the problem? – Victor2748 Jan 11 '15 at 19:50
  • I don't quite understand the question. Are you asking how to make a graphical overlay on top of other programs? – Radiodef Jan 11 '15 at 19:51
  • 1
    PerPixel alphering is testing each pixel for transparency, any thing you want to paint on the frame will block mouse events from passing through it, that's the point. Since Java can't raise events at the os level, there's no way you can pass the event on – MadProgrammer Jan 11 '15 at 19:52
  • 1
    @Radiodef Basically yes, My main goal is to display graphics on the screen just like on canvas, without letting them catch the user control events (Such as mouse clicks) – Victor2748 Jan 11 '15 at 19:52
  • @MadProgrammer Alright, is there any way to paint graphics on the screen like on canvas, without using swing? Or is there any other way to achieve this goal in Java? – Victor2748 Jan 11 '15 at 19:54
  • [There is an Oracle tutorial on Glass Panes here](http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html) which is strikingly similar. Note the `redispatchMouseEvent` method they use. – Obicere Jan 11 '15 at 19:57
  • Basically, I want to achieve this, but in Java: https://www.youtube.com/watch?v=irUQGDDSk_g – Victor2748 Jan 11 '15 at 20:05
  • AWT can't, as it doesn't have a concept of transparency, I don't know about JavaFX. The problem is, this is likely an OS restriction... – MadProgrammer Jan 11 '15 at 20:14
  • @Victor2748 it does that exactly, here is a gif of it in action http://i.imgur.com/DlfZttV.gif – Obicere Jan 11 '15 at 20:14
  • @Obicere The OP is trying to allow events to be passed through to areas beneath the window itself, passing the event back to the OS itself – MadProgrammer Jan 11 '15 at 20:14
  • @Obicere Now add some graphics to the window... – MadProgrammer Jan 11 '15 at 20:15
  • @Victor2748 Do you ever want the window to be focusable by the user? – MadProgrammer Jan 11 '15 at 20:17
  • @MadProgrammer No, I do not want the window to be focusable – Victor2748 Jan 11 '15 at 20:31
  • @MadProgrammer However, if it is required to be focused, then that is ok, but generally, I don't need it to be ever focused, but I need it to be 'alwaysOnTop' (which can be done with setAlwaysOnTop(true)) – Victor2748 Jan 11 '15 at 20:32
  • @Victor2748 I thought making the window non-focusable might make a difference, on MaxOS it had none – MadProgrammer Jan 11 '15 at 20:43
  • @Obicere Could you please provide a working example for your gif? Does your JavaFX solution work on MacOS aswell? – RootRaven Jan 24 '17 at 09:40

1 Answers1

1

This is not an answer, but a correction to the code example

The example you provide is actually doing some very dangerous things, first it's painting a translucent color onto an 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, for example...

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();
        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366