spvessel / spacevil

Simple examples of SpaceVIL implementation for C# / .NET Framework, C# / .NET Core and Java.
https://spvessel.com
MIT License
55 stars 7 forks source link

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

Open SWayfarer opened 4 years ago

SWayfarer commented 4 years ago

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?

spvessel commented 4 years ago

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;
    }
    }
  2. 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);
});
SWayfarer commented 4 years ago

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

spvessel commented 4 years ago

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.

SWayfarer commented 4 years ago

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

spvessel commented 4 years ago

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

SWayfarer commented 4 years ago

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

spvessel commented 4 years ago

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();
        }
    }
}
SWayfarer commented 4 years ago

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?

spvessel commented 4 years ago

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