Handling mouse events in new class CommandDialog

59 views
Skip to first unread message

P5music

unread,
Dec 28, 2020, 4:22:33 AM12/28/20
to CodenameOne Discussions
(Merry Christmas)

My app now features a new dialog class, I called it CommandDialog. It leverages both the features of InteractionDialog and Dialog, so the show() method now returns a Command.
This class has to be completed to be fully functional:
I subclassed InteractionDialog so now I need to prevent the mouse events from hitting the underlying components in the form.
I tried 
    form.setGrabsPointerEvents(false);
    form.setIgnorePointerEvents(true);
but they seem not to be working at all. Furthermore they seem to be the same instruction with negated boolean parameter.
Moreover I need the setDisposeWhenPointerOutOfBounds(value) feature that also seem not to be working.

I need a workaround if necessary. I have some ideas but maybe something simple is available.

This applies also to the InteractionDialog itself.

Thanks in advance

Shai Almog

unread,
Dec 28, 2020, 10:08:07 PM12/28/20
to CodenameOne Discussions
Hi,
these methods are methods ofcomponent not form so they're designed for a component to grab events in a hierarchy. It appears in form because of its hierarchy.
You can implement a pointer pressed/released/dragged listener and consume() all events that are out of bounds.

P5music

unread,
Dec 29, 2020, 5:19:51 AM12/29/20
to CodenameOne Discussions
Please have a look to this code snippet. I added it to the CommandDialog:

private void setMouseEventsListener()
{
actionListener=new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {

if (isMouseEventOutside(evt.getX(),evt.getY())) evt.consume();

}
};
form.addPointerDraggedListener(actionListener);
form.addPointerPressedListener(actionListener);
form.addPointerReleasedListener(actionListener);
form.addLongPressListener(actionListener);

}

It is not working as expected.
I can report this:

The layout is a table layout for a master/detail appearance.
In the left part there are some buttons and a large BrowserComponent.
In the right part there are some buttons and a small BrowserComponent.

Let's say a CommandDialog is called from the left container from a callback of the Javascript interface of the BrowserComponent when I long press an iFrame element.

The dialog appears.
-If I click inside the dialog, the mouse event is not processed. The dialog buttons do not work. (not OK)
-If I click outside:
            -if I click on the right container of the table layout nothing happens (OK)
            -if I click on the left container:
                          -if I click on a button the dialog disappear (OK but I will have to handle the behaviour according to a parameter)
                          -if I click on the BrowserComponent the mouse event reaches to it  (not OK)
                                 and
                                 the dialog does not disappears (OK)
                                 and
                                 the click is processed and the right part changes with the detail data (not OK).

What's the explanation and solution?
Thanks
         




Shai Almog

unread,
Dec 29, 2020, 11:09:14 PM12/29/20
to CodenameOne Discussions
Sorry about that. I forgot your app is mostly HTML. That's problematic as we don't have the same amount of control over native as we do over our code.
The reason is simple. All events go through the parent form and the previous code works well for our components.

But the HTML rendering runs in the native OS thread and so do their events. So the event needs to be processed there and can't be intercepted. The only workaround is to write JavaScript code that will disable the browser component explicitly.

P5music

unread,
Dec 30, 2020, 3:44:54 AM12/30/20
to CodenameOne Discussions
Ok, preventing the BC's from processing the events should not be difficult.
But the strange thing is that the right container in the table layout does not receive the events like the left one (except the small BC). And so happens to the FAB.
For example, if I click on a button in the left container the dialog goes away, whilst if I click on a button of the right container nothing happens.
(the left container is bound to the FAB, and the FAB is insensitive too)
Maybe unbinding the left container from FAB would lead to the entire layout being insensitive to mouse events? Or something similar? Would it be a possible workaround?
Regards

P5music

unread,
Dec 30, 2020, 5:08:48 PM12/30/20
to CodenameOne Discussions
The function isMouseEventOutside() was wrong. Now I fixed it.

Shai Almog

unread,
Dec 30, 2020, 9:25:09 PM12/30/20
to CodenameOne Discussions
I was wrong. There's a better way to do this.

The native OS code for handling events in Codename One checks first to see if there's a component on top.
You can just create.a transparent (or translucent) interaction dialog and show it on 0, 0, 0, 0. This way it will cover the entire screen. Then you can show another dialog on top of that.

You can even add a button to the transparent dialog and it will grab all pointer events so you know if a user clicked outside and you could dispose both dialogs. You then don't need the pointer listeners etc.

P5music

unread,
Jan 2, 2021, 4:04:55 AM1/2/21
to CodenameOne Discussions
If I put

        backgroundInteractionDialogRect.setX(0);
        backgroundInteractionDialogRect.setY(0);
        backgroundInteractionDialogRect.setWidth(0);
        backgroundInteractionDialogRect.setHeight(0);
        backgroundInteractionDialog.showPopupDialog(backgroundInteractionDialogRect);

I get a tiny rectangle in the top-left corner, not useful.

If I put
        int w=Display.getInstance().getDisplayWidth();
        int h=Display.getInstance().getDisplayHeight();

        backgroundInteractionDialogRect.setX(0);
        backgroundInteractionDialogRect.setY(0);
        backgroundInteractionDialogRect.setWidth(w);
        backgroundInteractionDialogRect.setHeight(h);
        backgroundInteractionDialog.showPopupDialog(backgroundInteractionDialogRect);

I get this exception:

java.lang.IllegalArgumentException: margin cannot be negative
at com.codename1.ui.plaf.Style.setMargin(Style.java:2405)
at com.codename1.ui.plaf.Style.setMargin(Style.java:2383)
at com.codename1.ui.plaf.Style.setMargin(Style.java:1425)
at com.codename1.components.InteractionDialog.show(InteractionDialog.java:346)
at com.codename1.components.InteractionDialog.showPopupDialog(InteractionDialog.java:807)

If I use other values I get a tiny rectangle with some horizontal positioning but very similar to the first one.
What's wrong?

Marisole Aromatherapy

unread,
Jan 2, 2021, 10:07:20 AM1/2/21
to codenameone...@googlegroups.com
Hi P5,

I took a similar path as yours some time ago. Instead of extending InteractionDialog, I created a separate class with similar functionality and tweaked part of its code. I recall that extending it wasn't working.

I am sending you my version of it, perhaps you will find it useful.. Sample usage:

Form f = getCurrentForm();
AnimatedDialog newDlg = new AnimatedDialog();
newDlg.setLayout(new BorderLayout());
Label titleLable = new Label("some title");
        titleLable.getAllStyles().setAlignment(Component.CENTER);
        Container myTitle = new Container(new BorderLayout());
        Border lineBorder = Border.createLineBorder(2, 0x33b5e5);
        Border emptyBorder = Border.createEmpty();
        Border newBorder = Border.createCompoundBorder(emptyBorder, lineBorder, emptyBorder, emptyBorder);
        myTitle.getAllStyles().setBorder(newBorder);
        myTitle.add(BorderLayout.CENTER, titleLable);
        newDlg.add(BorderLayout.NORTH, myTitle);
Button okBtn = new Button("OK");
        okBtn.getUnselectedStyle().setAlignment(4);
        okBtn.addActionListener(e -> {
            newDlg.disposeToTheTop();
        });
        FlowLayout centerLayout = new FlowLayout();
        centerLayout.setValign(CENTER);
        Container boxCenter = new Container(centerLayout);
        SpanLabel msgLbl = new SpanLabel("some msg");
        boxCenter.add(msgLbl);
        newDlg.add(CENTER, boxCenter);
        newDlg.add(BorderLayout.SOUTH, okBtn);
        int msgHeight = boxCenter.getPreferredH();
        int height = newDlg.getPreferredH();
        int width = newDlg.getPreferredW();
        int sideMargins = (f.getWidth() - width - 30) / 2;
        int verticalMargin = (f.getHeight() - height - f.getToolbar().getHeight()) /2;
        newDlg.setDisposeWhenPointerOutOfBounds(true);
        newDlg.setAnimationSync(true);
        newDlg.show(verticalMargin/2, verticalMargin + verticalMargin/2, sideMargins, sideMargins);
        int newMsgHeight = boxCenter.getPreferredH();
        if(newMsgHeight != msgHeight)
        {
            int newHeight = (newMsgHeight - msgHeight) + height;
            int newVerticalMargin = (f.getHeight() - newHeight - f.getToolbar().getHeight()) /2;
            newDlg.resize(verticalMargin/2, verticalMargin/2 + (newVerticalMargin - (verticalMargin - newVerticalMargin)), sideMargins, sideMargins, false);
        }



--
You received this message because you are subscribed to the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to codenameone-discu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/codenameone-discussions/dc0981af-019d-4433-8658-f8b39d326f3dn%40googlegroups.com.
AnimatedDialog.java

P5music

unread,
Jan 2, 2021, 10:53:26 AM1/2/21
to CodenameOne Discussions
Thanks
I tried to use the resize method as it seems to be useful in my case. 

backgroundInteractionDialog.resize(0,h,0,w); //w=2048 h=1534
makes it disappear completely (w,h are the screen dimensions).

instead
backgroundInteractionDialog.resize(0,100,0,100);
makes the backgroundInteractionDialog almost the size of the screen.
It seems that the values are not in pixels (?).

Regards

Marisole Aromatherapy

unread,
Jan 2, 2021, 5:41:05 PM1/2/21
to codenameone...@googlegroups.com
In the AnimatedDialog class that I shared resize should take pixels, but note that it's the margins, not the dimension

Shai Almog

unread,
Jan 2, 2021, 9:27:58 PM1/2/21
to CodenameOne Discussions
Use show(0, 0, 0, 0) to create a full screen interaction dialog. Not showPopup.

P5music

unread,
Jan 3, 2021, 12:20:30 PM1/3/21
to CodenameOne Discussions
Ok, now I've got the background.
I use this code to manage mouse events
actionListener=new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {

                if (isMouseEventOutside(evt.getX(),evt.getY())&&disposeOnMouseEventOutside) {
                evt.consume();
                latch.countDown();}
            }
        };
        backgroundInteractionDialog.addPointerDraggedListener(actionListener);
        backgroundInteractionDialog.addPointerPressedListener(actionListener);
        backgroundInteractionDialog.addPointerReleasedListener(actionListener);
        backgroundInteractionDialog.addLongPressListener(actionListener);

but only the dragged event triggers the actionPerformed method. If I click or long-press nothing happens.
How to fix this?
Thanks regards

Shai Almog

unread,
Jan 3, 2021, 11:56:45 PM1/3/21
to CodenameOne Discussions
I'm not sure what you're trying to do with the action listeners here?
These are no longer required if you use the two dialog approach. Just add a button to the parent dialog (in the CENTER border layout position). Then use an action listener there to detect clicking outside of the child dialog.
Reply all
Reply to author
Forward
0 new messages