13
votes

I have a legacy swing application that I need to add touch gestures to,specifically pinch to zoom and touch and drag.

I tried the SwingNode of JDK 8 and I can run the swing application there, but the display performance was cut by more than 50% which won't work. SwingTextureRenderer in MT4J has the same issue and that is without even trying to redispatch touch events as mouse events.

I thought about a glass pane approach using a JavaFX layer on top and capturing the touch events and attempting to dispatch them as mouse events to the Swing app underneath.

Does anyone have an alternative approach? The target platform is windows 8.

Bounty coming as soon as Stackoverflow opens it up. I need this one pretty rapidly.

EDIT:

Here is what I tried with SwingNode (the mouse redispatch didn't work). The SwingNode stuff might be a distraction from the best solution so ignore this if you have a better idea for getting touch into swing:

@Override
public void start(Stage stage) {
    final SwingNode swingNode = new SwingNode();
    createAndSetSwingContent(swingNode);

    StackPane pane = new StackPane();
    pane.getChildren().add(swingNode);

    stage.setScene(new Scene(pane, 640, 480));
    stage.show();
}

private void createAndSetSwingContent(final SwingNode swingNode) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            UILib.setPlatformLookAndFeel();

            // create GraphViewTouch
            String datafile = null;
            String label = "label";

            final JPanel frame = GraphView.demoFrameless(datafile, label);
            swingNode.setContent(frame);
            swingNode.setOnZoom(new EventHandler<ZoomEvent>() {
                @Override public void handle(ZoomEvent event) {
                    MouseWheelEvent me = new MouseWheelEvent(frame, 1, System.currentTimeMillis(), 0, (int)Math.round(event.getSceneX()), (int)Math.round(event.getSceneY()), (int)Math.round(event.getScreenX()), (int)Math.round(event.getScreenY()), (int)Math.round(event.getZoomFactor()), false, MouseWheelEvent.WHEEL_UNIT_SCROLL, (int)Math.round(event.getZoomFactor()), (int)Math.round(event.getZoomFactor()), event.getZoomFactor());
                    frame.dispatchEvent(me);
                    System.out.println("GraphView: Zoom event" +
                        ", inertia: " + event.isInertia() + 
                        ", direct: " + event.isDirect());

                    event.consume();
                }
            });
        }
    });
}
3
Please provide code for a minimal sample which demonstrates the performance reduction using SwingNode.jewelsea
I updated the question with my SwingNode attemptdavidethell
@jewelsea suggested to supply a MCTaRE (Minimal Complete Tested and Readable Example). Please follow the link and read about it. It is not 'uncompilable code snippets' and it can be very useful to prepare one.Andrew Thompson
Yeah, I get the concept and usually I wouldn't mind but do you think the SwingNode/redispatch concept is really going to be workable? Just don't want to continue down that path unless some of you really see it being a petformant option.davidethell

3 Answers

1
votes

You can use JNA to parse the messages from Windows.

Some documentation on the multi touch events from Microsoft: https://docs.microsoft.com/en-us/windows/desktop/wintouch/wm-touchdown

Some documentation on how to do it in Java and sample code: https://github.com/fmsbeekmans/jest/wiki/Native-Multitouch-for-AWT-component-(Windows)

0
votes

hmm... this is a tough one, but there is a chance.

What I would do is make multiple MouseListener classes (relative to the number of mouse events you want to pick up), and than create some sort of system to detect certain adjustments, eg. (zoom)

1st listener:

    public void mousePressed(MouseEvent e){
    //Set click to true
    clk = true;
    //set first mouse position
    firstPos = window.getMousePosition();
    }

    public void mouseReleased(MouseEvent e){

    //set second mouse position
    secondPos = window.getMousePosition();
    }

Second Listener

    public void mousePressed(MouseEvent e){
    //set clicked to true
    clk = true;
    //set first mouse position (listener 2)
    firstPos = window.getMousePosition();
    }

    public void mouseReleased(MouseEvent e){

    //set second mouse position
    secondPos = window.getMousePosition();
    }

Main handler

    if(Listener1.get1stMousePos() < Listener1.get2ndMousePos() &&    Listener2.get1stMousePos() < Listener2.get2ndMousePos() && Listener1.clk && Listener2.clk){
    zoomMethod((Listener1.get1stMousePos - Listener1.get2ndMousePos()) +           (Listener1.get1stListener2.get2ndMousePos());

    }

And than just do this to add it to the window:

    window.addMouseListener(Listener1);
    window.addMouseListener(Listener2);

Hope you find a way.

0
votes

For the pinch-to-zoom:

Try the GestureMagnificationListener by guigarage.com. It provides a method:

public void magnify(GestureMagnificationEvent me){...}