spacevil icon indicating copy to clipboard operation
spacevil copied to clipboard

Is there a show and wait window function in the framework?

Open SWayfarer opened this issue 5 years ago • 9 comments

Hi!

I am writing a dialog box and I need the current thread to wait for the dialog to finish working. For this, for example, in Java FX there is a method to showAndWait. Is there an analog here?

SWayfarer avatar Apr 11 '20 14:04 SWayfarer

Hi! In such situations, I use a slightly different approach. You have two ways to create dialog (modal) boxes.

  1. Create build-in dialog box:
public class MyDialogBox extends Prototype {

    // dialog window
    public ResizableItem window = null;

    public MyDialogBox() {
        setPassEvents(false); // this prevent pass events through MyDialogBox
        setStyle(Style.getFrameStyle()); // Frame style is Ok
        setBackground(0, 0, 0, 150); // transparent background

        // inside window we will add all another items (buttons, labels, titlebar and
        // etc.)
        window = new ResizableItem();
    }

    @Override
    public void initElements() {
        // window appearance
        window.setBackground(55, 55, 55);
        window.setShadow(5, 3, 3, new Color(0, 0, 0, 180));
        window.setSize(400, 300);
        window.setAlignment(ItemAlignment.HCENTER, ItemAlignment.VCENTER);

        // add window
        addItem(window);

        // add titlebar and button to the window
        TitleBar title = new TitleBar("MyDialogBox:");
        ButtonCore okButton = new ButtonCore("Ok");
        okButton.setWidth(100);
        okButton.setAlignment(ItemAlignment.BOTTOM, ItemAlignment.HCENTER);
        okButton.setMargin(0, 0, 0, 20);
        window.addItems(title, okButton);

        // change actions of titlebar close button
        title.getMinimizeButton().setVisible(false); // hides button
        title.getMaximizeButton().setVisible(false); // hides button
        title.getCloseButton().eventMouseClick.clear();
        title.getCloseButton().eventMouseClick.add((sender, args) -> {
            close(); // now it closes the MyDialogBox not entire window
        });

        // Ok button will set the result
        okButton.eventMouseClick.add((sender, args) -> {
            _result = true; //set result
            close(); // close
        });
    }

    // event which will invoked when MyDialogBox is closed to perform actions.
    public EventCommonMethod onCloseDialog = new EventCommonMethod();

    // handler for self distaction after closing.
    private CoreWindow _handler = null;

    // show the MyDialogBox.
    public void show(CoreWindow handler) {
        _result = false;

        _handler = handler;
        _handler.addItem(this);
        this.setFocus();
    }

    // close the MyDialogBox.
    public void close() {
        // perform assigned actions
        if (onCloseDialog != null)
            onCloseDialog.execute();

        // and remove MyDialogBox
        _handler.removeItem(this);
    }

    // getting result
    boolean _result = false;
    boolean getResult() {
        return _result;
    }
}
  1. Create separate window with com.spvessel.spacevil.DialogWindow:
public class MyDialogBox extends DialogWindow {

    public MyDialogBox() { }

    @Override
    public void initWindow() {
        // window appearance
        setParameters("MyDialogBox:", "MyDialogBox:", 400, 300, false);
        setBackground(55, 55, 55);
        setSize(400, 300);
        isCentered = true;

        // add titlebar and button to the window
        TitleBar title = new TitleBar("MyDialogBox:");
        ButtonCore okButton = new ButtonCore("Ok");
        okButton.setWidth(100);
        okButton.setAlignment(ItemAlignment.BOTTOM, ItemAlignment.HCENTER);
        okButton.setMargin(0, 0, 0, 20);
        addItems(title, okButton);

        // change actions of titlebar close button
        title.getMinimizeButton().setVisible(false); // hides button
        title.getMaximizeButton().setVisible(false); // hides button
        title.getCloseButton().eventMouseClick.clear();
        title.getCloseButton().eventMouseClick.add((sender, args) -> {
            close(); // now it closes the MyDialogBox
        });

        // Ok button will set the result
        okButton.eventMouseClick.add((sender, args) -> {
            _result = true; //set result
            close(); // close
        });
    }

    // event which will invoked when MyDialogBox is closed to perform actions.
    public EventCommonMethod onCloseDialog = new EventCommonMethod();

    // show the MyDialogBox.
    public void show(CoreWindow handler) {
        _result = false;

        super.show();
    }

    // close the MyDialogBox.
    public void close() {
        super.close();

        // perform assigned actions
        if (onCloseDialog != null)
            onCloseDialog.execute();
    }


    // getting result
    boolean _result = false;
    boolean getResult() {
        return _result;
    }
}

And the call of such windows is the same:

ButtonCore btn = new ButtonCore();
btn.eventMouseClick.add((sender, args) -> {
    MyDialogBox myBox = new MyDialogBox();
    // describe onCloseDialog event
    myBox.onCloseDialog.add(() -> {
        System.out.println("Ok is clicked? Result: " + myBox.getResult());
    });
    // show dialog
    myBox.show(this);
});

spvessel avatar Apr 11 '20 18:04 spvessel

Hi!

I meant the ability to interrupt the current thread before closing the window. I wrote simple code that should do this, but it does not work as I expected. The result is "magically" not predictable.

It must be something like: %some code% dialog.showAndWait(); %another code%

where %another code% runs after dialog close.

https://pastebin.com/Uahxre8S

SWayfarer avatar Apr 15 '20 13:04 SWayfarer

Hi! Good. I just compiled a new version, and you need to test it first (but be aware that this version not only solved your “dialog box” problem, but also contains many improvements that have not been properly tested yet). link: spacevil-jvm-0.3.5.5

And you can do that things: DialogBox example with showAndWait() method:

public class MyDialogBox extends DialogWindow {

    public MyDialogBox() {
    }

    @Override
    public void initWindow() {
        // window appearance
        setParameters("MyDialogBox:", "MyDialogBox:", 400, 300, false);
        setBackground(55, 55, 55);
        setSize(400, 300);
        isAlwaysOnTop = true;

        // add titlebar and button to the window
        TitleBar title = new TitleBar("MyDialogBox:");
        ButtonCore okButton = new ButtonCore("Ok");
        okButton.setWidth(100);
        okButton.setAlignment(ItemAlignment.BOTTOM, ItemAlignment.HCENTER);
        okButton.setMargin(0, 0, 0, 20);
        addItems(title, okButton);

        // change actions of titlebar close button
        title.getMinimizeButton().setVisible(false); // hides button
        title.getMaximizeButton().setVisible(false); // hides button
        title.getCloseButton().eventMouseClick.clear();
        title.getCloseButton().eventMouseClick.add((sender, args) -> {
            close(); // now it closes the MyDialogBox
        });

        // Ok button will set the result
        okButton.eventMouseClick.add((sender, args) -> {
            _result = true; // set result
            close(); // close
        });
    }

    CoreWindow _handler = null;

    // show the MyDialogBox.
    public void show(CoreWindow handler) {
        _handler = handler;
        _result = false;
        super.show();
    }

    // close the MyDialogBox.
    public void close() {
        try {
            synchronized (_handler) {
                _handler.notify();
            }

        } catch (Exception e) {
        }
        super.close();
    }

    // getting result
    boolean _result = false;

    boolean getResult() {
        return _result;
    }

    void showAndWait(CoreWindow handler) {
        show(handler);
        try {
            synchronized (handler) {
                handler.wait();
            }
        } catch (Exception e) {
        }
    }
}

And you can use it in your way:

btn.eventMouseClick.add((sender, args) -> {
    MyDialogBox msg = new MyDialogBox();
    msg.showAndWait(this);
    // Do some after msg is closed
    System.out.println("try get value " + msg.getResult());
});

PS. Tell me if it works for you.

spvessel avatar Apr 15 '20 15:04 spvessel

Unfortunately, this did not help, the result is the same. Sometimes it works correctly, and sometimes it hangs on a lock.

https://pastebin.com/BKRDZFjV

Upd: Those. if you call the dialog many times, then you can catch the lock

SWayfarer avatar Apr 15 '20 16:04 SWayfarer

Ok. I will continue to investigate the problem further. Why don't you want to use the "onCloseDialog" event?

spvessel avatar Apr 15 '20 17:04 spvessel

I use dialogs as built-in to other programs, where they represent the implementation of some interface for interaction. In most cases, I / O stops the process until it is completed, so the use of a reactive approach will lead to the use of crutches specifically for UI on spacevil.

In addition, sometimes it is necessary to collect information from several windows in a row, then from a code point of view the reactive approach would look awful

SWayfarer avatar Apr 15 '20 21:04 SWayfarer

Ok. I understand you point of view. In most cases, I am very limited due to the use of GLFW in SpaceVIL. That's why the dialogs in SpaceVIL work like this. I have another version for you. link: spacevil-jvm-t2 I added 2 methods for CoreWindow: hold() and proceed(). You should use them exactly as shown below. Tell me if it works. Usage:

btn.eventMouseClick.add((sender, args) -> {
    hold(); // important!!! 
    // if you describe `eventMouseClick` inside non-CoreWindow class use this approach:
    // btn.getHandler().hold();
    MyDialogBox msg = new MyDialogBox();
    msg.showAndWait(this);
    // Do some after msg is closed
    System.out.println("try get value " + msg.getResult());
});

MyDialogBox (see showAndWait() method)

public class MyDialogBox extends DialogWindow {

    public MyDialogBox() { }

    @Override
    public void initWindow() {
        // window appearance
        setParameters("MyDialogBox:", "MyDialogBox:", 400, 300);
        setBackground(55, 55, 55);
        setSize(400, 300);
        isAlwaysOnTop = true;

        // add titlebar and button to the window
        ButtonCore okButton = new ButtonCore("Ok");
        okButton.setWidth(100);
        okButton.setAlignment(ItemAlignment.BOTTOM, ItemAlignment.HCENTER);
        okButton.setMargin(0, 0, 0, 20);
        addItems(okButton);
        eventClose.clear();
        eventClose.add(() -> {
            close();
        });
        // Ok button will set the result
        okButton.eventMouseClick.add((sender, args) -> {
            _result = true; // set result
            close(); // close
        });
    }

    CoreWindow _handler = null;

    // show the MyDialogBox.
    public void show(CoreWindow handler) {
        _handler = handler;
        _result = false;
        super.show();
    }

    // close the MyDialogBox.
    public void close() {
        try {
            synchronized (_handler) {
                _handler.notify();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.close();
    }

    // getting result
    boolean _result = false;

    boolean getResult() {
        return _result;
    }

    void showAndWait(CoreWindow handler) {
        try {
            synchronized (handler) {
                show(handler);
                handler.wait();
                handler.proceed(); // important!!
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

spvessel avatar Apr 15 '20 22:04 spvessel

Yes, it seems to work. Thank you! =)

And... In the process of analyzing the framework, I tried to look at the insides to understand the cause of the problem, but the code turned out to be obfuscated. Why obfuscate MIT-licensed code?

SWayfarer avatar Apr 16 '20 10:04 SWayfarer

For now I kinda not ready to give the source code now... but I do not limit any use of examples and SpaceVIL binary.

spvessel avatar Apr 16 '20 10:04 spvessel