与 Swing 同步:等待 UI

发布于 2024-09-19 16:47:11 字数 1399 浏览 4 评论 0原文

通常,人们会寻找一种在后台仍在运行的情况下更新 UI 的方法。我的方法是使用新线程或简单地使用 SwingUtilities.invokeLater。

然而,我现在的处境却完全相反。我有一个调用静态方法的按钮,该方法有一些魔力(这里并不重要)。按下该按钮还会在 UI 线程上启动动画(当前使用 Swing Timer 实现)。当魔术方法完成时,它首先向 UI 触发一个事件,然后继续执行其他操作。该事件告诉 UI 在一段延迟后停止动画(实际上 UI 应该在短时间内显示不同的动画)。

然而,这种延迟正是问题所在,因为我想阻止魔术方法在动画完成之前继续。事件监听器调用当前是同步实现的,因此事件监听器在完成之前不会返回。但由于动画是异步的,我不知道如何阻止当时的后台进程。我以为我可以使用 ReentrantLock 来使其同步,但是当我尝试从 UI 线程锁定它时,该锁被忽略了。

让后台进程等待 UI 的正确方法是什么?

编辑

下面的代码显示了极其简化的情况。 UI 只是实际侦听器之一(尽管是唯一的阻塞侦听器),因此我宁愿在事件处理的 UI 端产生一些阻塞效果。

public class Worker
{
    public static void magicMethod()
    {
        // do something
        // ...

        // fire event
        for ( ExampleEventListener listener : listeners )
            listener.onExampleEvent( new ExampleEvent() );

        // BLOCK until animation in UI completed
        nextStep();
    }

    public static void nextStep ()
    {
        // continue work
    }
}


public class MyWindow extends JFrame implements ExampleEventListener
{
    public void actionPerformed ( ActionEvent event )
    {
        // button clicked
        Worker.magicMethod();
    }

    public void onExampleEvent ( ExampleEvent event )
    {
        startAsynchronousAnimation();
    }

    private void completeAnimation ()
    {
        // animation completed
        animationPanel.setVisible( false );

        // UNLOCK
    }
}

Usually one is looking for a way to update the UI while something in the background is still working. My approach there would be either use a new thread or simply use SwingUtilities.invokeLater.

However, right now I'm in the completely opposite situation. I have a button that calls a static method which does some magic (not important here). Pressing the button also starts an animation on the UI thread (currently implemented using a Swing Timer). When the magic method is finished, it first fires an event to the UI and then continues doing something else. The event tells the UI to stop the animation - after some delay (actually the UI is supposed to show a different animation for a short time).

That delay however is exactly the problem, because I want to prevent the magic method from continuing before the animation has finished. The event listener call is currently implemented synchronizely, so the event listener won't return before it completes. But as the animation is asynchronous, I don't know how to block the background process for that time. I thought I could use a ReentrantLock to make it synchronized, but when I tried to lock it from the UI thread, that lock was ignored.

What is the correct way to make the background process wait for the UI?

edit

The code below shows extremely simplified what happens. The UI is just one of the actual listeners (the only blocking one though), so I would rather have some blocking effect on the UI side of the event handling.

public class Worker
{
    public static void magicMethod()
    {
        // do something
        // ...

        // fire event
        for ( ExampleEventListener listener : listeners )
            listener.onExampleEvent( new ExampleEvent() );

        // BLOCK until animation in UI completed
        nextStep();
    }

    public static void nextStep ()
    {
        // continue work
    }
}


public class MyWindow extends JFrame implements ExampleEventListener
{
    public void actionPerformed ( ActionEvent event )
    {
        // button clicked
        Worker.magicMethod();
    }

    public void onExampleEvent ( ExampleEvent event )
    {
        startAsynchronousAnimation();
    }

    private void completeAnimation ()
    {
        // animation completed
        animationPanel.setVisible( false );

        // UNLOCK
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

§普罗旺斯的薰衣草 2024-09-26 16:47:11

不确定这是否是最好的方法,但您可以使用共享布尔值来指示后台进程是否已准备好继续。使用 wait() 将导致线程释放同步块中对象的锁。类似于:

while(! ready){
    try{
        mySynchonizedObject.wait(); 
    }catch(InterruptedException ex){
        System.exit(1);
    }
}

“ready”是一个共享的布尔值。当您的 UI 准备就绪时,它会将 ready 设置为 true 并调用 notificationAll()。

Not sure if its the best way, but you could use a shared boolean value to signal if the background process is ready to continue. Using wait() will cause the thread to release the lock an object in a synchronized block. Something like:

while(! ready){
    try{
        mySynchonizedObject.wait(); 
    }catch(InterruptedException ex){
        System.exit(1);
    }
}

Where 'ready' is a shared boolean value. When you UI is ready it would then set ready to true and call notifyAll().

那片花海 2024-09-26 16:47:11

您可以让后台进程在事件调度线程中运行 - 与 Swing 执行的线程相同。然后,只需在对话框提示或其他任何内容后执行您的后台代码,一旦返回,您的后台代码就会执行,从而有效地使其等待 UI。

You could have your background process run in the Event Dispatch Thread - the same thread that Swing executes on. Then simply have your background code execute after a dialog prompt or whatever, and once that returns your background code will execute, effectively making it wait for the UI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文