2

I am trying to create a transparent JFXPanel over a swing based UI. The problem is events are not forwarded through the "transparent" sections the way they are for normal swing components. I included a simple example below. Note that there are 3 layers, swing, swing, then the jfxpanel. If you comment out the

addItemToLayeredPanel(panel, createFXOverlay(), 7);

you can click both buttons even though they have jpanel layered above the bottom one. (Just demonstrating the effect works in swing only doesn't work with JFXPanel)

public class Main {
public static void main(String[] args) {
    JFrame frame = new JFrame();
    JLayeredPane panel = new JLayeredPane();
    JButton button = new JButton("Push me");
    JPanel overlay = createOverlay();

    addItemToLayeredPanel(panel, button, 5);
    addItemToLayeredPanel(panel, overlay, 6);
    addItemToLayeredPanel(panel, createFXOverlay(), 7);

    frame.getContentPane().add(panel);
    frame.setSize(500, 500);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

private static JPanel createOverlay() {
    JPanel panel = new JPanel();
    panel.add(new JButton("on top"));
    panel.setOpaque(false);
    return panel;
}

private static JFXPanel createFXOverlay() {
    JFXPanel panel = new JFXPanel();
    BorderPane root = new BorderPane();
    root.setStyle("-fx-background-color:transparent;");
    root.setCenter(new Button("root"));
    Scene scene = new Scene(root);

    scene.setFill(javafx.scene.paint.Color.TRANSPARENT);
    panel.setScene(scene);
    panel.setOpaque(false);
    return panel;
}

private static void addItemToLayeredPanel(JLayeredPane panel, JComponent item, int layer) {
    item.setBounds(0,0,500,500);
    panel.add(item);
    panel.setLayer(item, layer);
}

}

Ideas? I tried a couple of ways of forwarding the events (generically) to jcomponents underneath, but I was unable to get it to work. I did find a couple of similar questions, but no solutions here and here

Community
  • 1
  • 1
CodeMnke
  • 96
  • 4
  • You don't even have to setup a scene - even an empty JFXPanel will cause events to not get forwarded automatically. – Guillaume F. Apr 03 '20 at 08:17

1 Answers1

0

When Swings tries to see if a mouse event goes thru, it uses the JComponent method

public boolean contains(int x, int y) {
    return (ui != null) ? ui.contains(this, x, y) : super.contains(x, y);
}

The problem is that JFXPanel, unlike other Swing components, does not define a ui ComponentUI. Therefore, the check falls back to the super.contains(x,y), which returns true if a mouse event happens within the bounds of the object.

The solution is to use a class that extends JFXPanel and overrides the contains method:

public class MyJFXPanel extends JFXPanel{
    @Override
    public boolean contains(int x, int y) { return false; }
}

Where false can be replaced by a more sophisticated statement, such as a pixel transparency condition.

The mouse events will then be automatically forwarded to the element underneat the MyJFXPanel.

Guillaume F.
  • 1,010
  • 7
  • 21