JavaFX 使用动画最小化和最大化未装饰的舞台

Posted

技术标签:

【中文标题】JavaFX 使用动画最小化和最大化未装饰的舞台【英文标题】:JavaFX Minimizing & Maximing undecorated stage with animations 【发布时间】:2018-06-24 09:09:43 【问题描述】:

我在这个问题中使用公认的答案:JavaFX Minimizing Undecorated Stage 来正确最小化我的应用程序。

然而,不幸的是,默认的 Windows 最小化和最大化 动画 根本没有显示(窗口只是出现然后消失)。

我知道可以使用未装饰的窗口显示动画,因为我有一个具有这种行为的应用程序 (PotPlayer)。

如何使动画与 JNA 一起出现?

编辑:这是一个有效的 Kotlin 代码片段,可以正确最小化 JavaFX 窗口,还增加了赏金。

fun makeMinimizable(stage: Stage) 
         val user32 = User32.INSTANCE
         val hWnd = user32.FindWindow(null, stage.title)
         val oldStyle = user32.GetWindowLong(hWnd, WinUser.GWL_STYLE)
         val newStyle = oldStyle or 0x00020000 // WS_MINIMIZEBOX
         user32.SetWindowLong(hWnd, WinUser.GWL_STYLE, newStyle)
    

【问题讨论】:

我刚刚在win7上测试过,它只有旧风格主题的动画。打开 aero 主题或关闭动画时,它不会动画。我可以建议的是找到你说的程序的窗口。然后让它打印出窗口样式并尝试在你的程序中设置它。 在你的代码中看起来你添加了样式 WS_BORDER 和 WS_MINIMIZEBOX 哦,是的,0x00080000 是我刚刚尝试过的,不小心把它留在了里面。我会尝试你的建议! @brian 嗯。我尝试将 oldStyle 变量设置为与 Potplayer 相同。我没有尝试解析单个样式,而只是将“oldStyle”设置为:-1764818944。 (你可以自己试试)。这实际上有效 - 窗口未装饰,并且确实出现了最小化动画,但是,一旦我恢复窗口,窗口就不再未装饰。有什么想法吗? 我刚刚用 potplayer 得到了同样的结果。还有 GWL_EXSTYLE 设置,但它们没有任何区别。 Javafx 必须做一些不同的事情,但我不知道是什么。 【参考方案1】:

在对 Windows 动画进行进一步研究后,似乎可以一起破解解决方案。这似乎更像是一个操作系统问题,而不仅仅是 JavaFX。

通过在 start() 中修改它,我能够使初始窗口保持未装饰,同时最小化并使用动画:

    int newStyle = oldStyle | 0x00020000 | 0x00C00000;

但是,在最小化并重新打开之后,Windows 边框看起来很奇怪。

然后,我尝试在图标化时使用 ChangeListener 来交换 Windows 样式。

stage.iconifiedProperty().addListener(new ChangeListener<Boolean>() 

        @Override
        public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) 
            if (t1.booleanValue() == true) 
                int newStyle = oldStyle | 0x00020000 | 0x00C00000;
                user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
             else if (t1.booleanValue() == false) 
                int newStyle = oldStyle | 0x00020000;
                user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
            
        
    );

这成功地使窗口取消最小化动画始终如一地正常工作,同时使(可见)舞台无边界。

一旦我找到重新应用的最佳方法,我似乎可以让最小化动画工作:

    int newStyle = oldStyle | 0x00020000 | 0x00C00000;
    user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);

就在舞台图标化之前,用户看不到边框。实施后,这可能类似于下面第一个链接中的 C# 解决方案。基本上,上面的 ChangeListener 做了相反的事情。

我认为我们需要另一个在后台监听的线程来完成这个解决方案,等待图标化事件发生。我觉得 stage.isIconified() == false 应该是触发事件的时候的情况,然后我们在后台线程中执行必要的任务来设置上面的代码。然后,(...有点工作)changeListener 将在取消最小化时将其重置回没有动画的非框架窗口,直到再次最小化。

有一个小错误,第一次取消最小化显示我的舞台底部部分被剪裁和复制了一点,但在后续操作后它消失了。我们可能需要尝试将第二个十六进制更改为触发动画的其他内容,并将所有内容设置在 ChangeListener 之外和另一个线程中。

我计划很快在我自己的 fx 程序中完成这项工作。我还是个学生,所以我对多线程和服务的经验不是很丰富,但我对如何去做有一个好主意,只需要几个小时的时间。

如果您在此期间取得任何进展,请告诉我!这是一个很好的起点。还没有人用 Java 解决这个问题。我正在阅读一些讨论,如 Steam 这样的无边界程序已经做到了这一点,但我认为没有人能完全弄清楚他们是如何完成它的,我怀疑是通过下面的 C# hack。但是,这对于我们的目的来说已经足够了。

解决无边界/未装饰动画的链接:

https://***.com/a/31489766/7234125

^ 我们需要实现这个答案,选项 #1,从 C# 到 Java

Borderless Window Using Areo Snap, Shadow, Minimize Animation, and Shake

http://pinvoke.net/default.aspx/Constants/Window%20styles.html

【讨论】:

以上是关于JavaFX 使用动画最小化和最大化未装饰的舞台的主要内容,如果未能解决你的问题,请参考以下文章

拖动功能无法正常工作! JavaFX VBox 拖动

flash中舞台外多余的部分怎么让看不见

在javafx中设置舞台和场景的高度和宽度

如何在 JavaFX 的控制器文件中调用舞台上的函数

自定义primaryStage标题:以图标为中心

如何在javafx中制作透明的场景和舞台?