Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom window decoration works incorrectly in some cases #604

Open
mgarin opened this issue Jan 13, 2020 · 16 comments
Open

Custom window decoration works incorrectly in some cases #604

mgarin opened this issue Jan 13, 2020 · 16 comments

Comments

@mgarin
Copy link
Owner

mgarin commented Jan 13, 2020

Reported by @kovadam69 on gitter:

if I add JDialog.setDefaultLookAndFeelDecorated(true);, the dialog header is changed to system decoration

    public static void main ( String[] args )
    {
        SwingTest.run (new Runnable ()
        {
            public void run ()
            {
                NativeFonts.setUseNativeFonts ( false );
                WebLookAndFeel.install();
                JDialog.setDefaultLookAndFeelDecorated(true);

                final WebDialog loginForm = new WebDialog ( StyleId.dialogDecorated, (Window) null, "Sample dialog" );

                loginForm.getContentPane().add(new WebButton("Press me", (e) ->
                {
                    WebOptionPane.showConfirmDialog(loginForm, "confirm", "confirm", WebOptionPane.YES_NO_OPTION);
                }));

                loginForm.setSize ( 500, 500 );
                loginForm.setLocationRelativeTo ( null );
                loginForm.setVisible ( true );
            }
        } );
    }

image

    public static void main ( String[] args )
    {
        SwingTest.run (new Runnable ()
        {
            public void run ()
            {
                NativeFonts.setUseNativeFonts ( false );
                WebLookAndFeel.install();

                final WebDialog loginForm = new WebDialog ( StyleId.dialogDecorated, (Window) null, "Sample dialog" );

                loginForm.getContentPane().add(new WebButton("Press me", (e) ->
                {
                    WebOptionPane.showConfirmDialog(loginForm, "confirm", "confirm", WebOptionPane.YES_NO_OPTION);
                }));

                loginForm.setSize ( 500, 500 );
                loginForm.setLocationRelativeTo ( null );
                loginForm.setVisible ( true );
            }
        } );
    }

image

@mgarin mgarin added this to the v1.3.0 milestone Jan 13, 2020
@mgarin mgarin self-assigned this Jan 13, 2020
@mgarin
Copy link
Owner Author

mgarin commented Jan 13, 2020

The problem appears to be in recently modified part of WebDialog, WebFrame and WebWindow classes - the StyleId provided in their root pane constructor. It has to be undecorated at the first run for correct updates upon root pane addition on the Window.

There are a few solutions that can be applied to fix this (and this isn't actually the first time this problem appeared), in perfect case scenario - WebRootPaneUI should listen to it's ancestor and perform necessary updates upon being added into Window, but there are a lot of caveats with this approach and it will require a lot of testing. So I will be adding a quick workaround in next update, then I will move this issue to a future update for improvement.

mgarin added a commit that referenced this issue Jan 13, 2020
- WebDialog.java, WebFrame.java, WebWindow.java - Added workaround to fix decorated windows style application, added more informative JavaDoc
@mgarin
Copy link
Owner Author

mgarin commented Jan 13, 2020

I've added temporary workaround for this, it will be available in v1.3.0 snapshot version soon and in the final v1.3.0 update once it goes live.

@mgarin mgarin modified the milestones: v1.3.0, v1.5.0 Jan 13, 2020
@mgarin
Copy link
Owner Author

mgarin commented Jan 13, 2020

Added for v1.5.0 as planned improvement.

@mgarin mgarin removed this from the v1.5.0 milestone Apr 23, 2020
@mgarin mgarin added this to the v1.2.13 milestone May 15, 2020
@mgarin
Copy link
Owner Author

mgarin commented Jun 19, 2020

Just a small note - workaround be available in v1.2.13 update that will be going live shortly.
I will take some more time to polish v1.3.0 and meanwhile will release a few smaller updates.

@mgarin mgarin removed this from the v1.2.13 milestone Jul 27, 2020
@mgarin
Copy link
Owner Author

mgarin commented Jul 27, 2020

Workaround is available in v1.2.13, the remaining larger changes will be added in future updates.

@wyj3531
Copy link

wyj3531 commented Sep 29, 2021

微信图片_20210929133037
how can i custom a JDialog with round conner notitle and no controll button like this. and how can i set the font type int JDialog

@wyj3531
Copy link

wyj3531 commented Sep 29, 2021

and i fix it by code

` JDialog dialog = new JDialog();

            dialog.setUndecorated(true);

            dialog.setBackground(new Color(0, 0, 0, 0));

            dialog.setModal(true);

            dialog.setContentPane(new RoundedPane());

            dialog.setSize(640, 480);

            dialog.setLocationRelativeTo(null);

            dialog.setVisible(true);`

but the dialog can not drag move as normal dialog. how can this do ?

@mgarin
Copy link
Owner Author

mgarin commented Sep 29, 2021

@wyj3531

Before I proceed to offer a solution I must add a disclaimer:

Swing currently doesn't support subpixel font antialiasing in non-opaque (undecorated) windows under any OS (check #130). Also undecorated windows are only properly supported under Windows and Mac OS X operating systems, you will most probably encounter issues with undecorated windows on other OS. And there are generally some other problems with undecorated windows (example #466) that you may encounter. So I generally do not recommend using non-native window decoration unless your application's target audience is now Windows or Mac OS X and you are sure that issues mentioned above do not matter for your application.


Now, as for the solution - I would recommend simply using a custom dialog style:

    <!-- Undecorated control-less dialog -->
    <style type="rootpane" id="my-dialog" extends="dialog-undecorated">
        <painter>
            <decorations>
                <decoration>
                    <WebShape round="10" />
                </decoration>
            </decorations>
        </painter>
    </style>

This is enough to make it look exactly as you've shown on the screenshot. Also this style applies directly to JRootPane of the JDialog so you don't need to create any custom components between the dialog and it's content.

You can also further customize the style if you want to.
For instance add shadow that will become emphasized when dialog is focused:

    <!-- Undecorated control-less dialog -->
    <style type="rootpane" id="my-dialog" extends="dialog-undecorated">
        <painter>
            <decorations>
                <decoration>
                    <WebShape round="10" />
                    <WebShadow type="outer" opacity="0.3" width="20" />
                </decoration>
                <decoration states="focused">
                    <WebShadow type="outer" opacity="0.5" />
                </decoration>
            </decorations>
        </painter>
    </style>

You can customize background, border, shadow, add any supported elements in any supported states etc.

You can use the style directly in the WebDialog constructor:

final WebDialog dialog = new WebDialog ( StyleId.of ( "my-dialog" ) );

Or apply the style to JDialog's root pane:

final JDialog dialog = new JDialog ( parent );
dialog.getRootPane ().putClientProperty ( StyleId.STYLE_PROPERTY, StyleId.of ( "my-dialog" ) );

No other settings are necessary.

@wyj3531
Copy link

wyj3531 commented Oct 11, 2021

try you method i found the whole dialog font type not change but they all look not same as it is. wyh ?can any method fix it.

@mgarin
Copy link
Owner Author

mgarin commented Oct 11, 2021

As I've mentioned it in the disclaimer above - non-opaque windows have various issues, including text rendering. It's not the font that changes, it's the rendering - it changes from subpixel antialias to grayscale antialias which makes it look different and in most cases - worse.

Check #130 for more information.

Unfortunately this is a Java/Swing issue with subpixel text rendering on non-opaque destination and I don't have any way to workaround it yet.

@wyj3531
Copy link

wyj3531 commented Oct 13, 2021

learn it. can i custom WebPopup with round conner by xml? the following code can't .

    <style type="popup" id="element-choose" extends="undecorated">
        <painter>
            <decorations>
                <decoration>
                    <WebShape round="10" />
                </decoration>
            </decorations>
        </painter>
    </style>

@mgarin
Copy link
Owner Author

mgarin commented Oct 13, 2021

You can, but you will need to extend a style that has decoration to begin with.
Style like this should work:

    <style type="popup" id="custom">
        <painter>
            <decorations>
                <decoration>
                    <WebShape round="10" />
                </decoration>
            </decorations>
        </painter>
    </style>

Just in case, no extend is the same as extending default component's style.

You're extending undecorated popup style in your example which doesn't have any custom decoration.
So in your case you would have to specify all decoration settings and not just the shape and also make it non-opaque:

    <style type="popup" id="custom" extends="undecorated">
        <component>
            <opaque>false</opaque>
        </component>
        <painter>
            <decorations>
                <decoration>
                    <WebShape round="10" />
                    <WebShadow type="outer" width="2" />
                    <LineBorder color="20,20,20" />
                    <ColorBackground color="68,68,68" />
                </decoration>
            </decorations>
        </painter>
    </style>

Result should should look like this:
image

If you don't make in non-opaque - you will have the default window/root pane background visible:
image

Note that when you make popup non-opaque - window also becomes non-opaque, causing the same issues as non-opaque windows have. I've mentioned them in my reply before and they're fully described in #130.

@wyj3531
Copy link

wyj3531 commented Oct 19, 2021

got it.
can swing do this. dialog or popup floating a frame like this .
90Yfz

@mgarin
Copy link
Owner Author

mgarin commented Oct 19, 2021

Easy solution is to use a common modal JDialog. You can also decorate it using the styling to look similar to what you've shown on the screenshot. Making the cross float outside of the dialog might be more complicated though.

But if your goal is to block content of a JFrame with a semi-transparent cover and display some sort of a modal popup like on the screenshot - it is better to implement it in a different way. Currently it's not something that is available in WebLaF, but I might add something like that in the future.

In the meantime you can implement it yourself in your project for any JFrame or JDialog:

  1. Add glass pane with semi-transparent background with a custom layout. Glass pane can be any component, but in this case you can simply use a JPanel with a layout in which you can conveniently place your popup in.

  2. Create a custom popup component with specific styling (for example like the one shown on your screenshot) and place it on the glass pane you added previously. Popup can be anything - simple JPanel with some styling would work just fine.

  3. Add some custom listeners to your glass pane and/or popup components to close it on whichever interaction you prefer, for instance clicking on the glass pane outside of the popup.

  4. Place desired content on your popup to be displayed.

That is pretty much it, you can make some utility classes to simplify the whole operation. For instance your custom popup component may have a method that will take in a JFrame/JDialog and do all of the actions mentioned above on it's own.

Alternatively - you can use layered pane to place your popup instead of using popup as the glass pane. That might be a bit trickier, but generally I would recommend it over replacing glass pane.

If you aren't sure how you can use/access glass pane/layered pane on the window I recommend reading this Swing guide:
https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html


Also just a side note - I recommend creating new issues for questions/bugs/suggestions unrelated to the current issue topic. It will be easier for me to both track and answer such issues.

@wyj3531
Copy link

wyj3531 commented Nov 29, 2021

and how to create round conner with WebWindow? which xml is it?

@mgarin
Copy link
Owner Author

mgarin commented Dec 2, 2021

You can use decorated dialog style as an example:
https://github.com/mgarin/weblaf/blob/master/modules/ui/src/com/alee/skin/light/resources/dialog.xml#L9

Similar one can be used to style WebWindow since JDialog, JFrame and JWindow (WebWindow) all have JRootPane and can be styled in the same way.

There is also a separate wiki article on window decoration you can check:
https://github.com/mgarin/weblaf/wiki/Window-decoration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants