You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SWT中Shell关闭导致后续事件丢失的原因及解决方法咨询

关闭Shell导致后续事件丢失的原因与解决方案

问题复现

示例代码

public class Test {
    
    private static Listener listener = e -> {
        String type = null ;
        switch ( e.type ) {
            case SWT.MouseDown -> type = "MouseDown" ;
            case SWT.Activate -> type = "Activate" ;
            case SWT.Deactivate -> type = "Deactivate" ;
        }
       System.out.println( type + " - " + e ) ; 
    } ;
    
    public static void main(String[] args) {
        Shell shell1 = new Shell() ;
        shell1.setText( "1" ) ;
        shell1.setSize( 300, 300 ) ;
        shell1.setLayout( new FillLayout() ) ;
        Composite composite1 = new Composite( shell1, SWT.NONE ) ;
        
        Shell shell2 = new Shell() ;
        shell2.setText( "2" ) ;
        shell2.setSize( 300, 300 ) ;
        shell2.setLayout( new FillLayout() ) ;
        Composite composite2 = new Composite( shell2, SWT.NONE ) ;
        
        addListeners( shell1 ) ;
        addListeners( composite1 ) ;
        addListeners( shell2 ) ;
        addListeners( composite2 ) ;
        // shell2.addListener( SWT.Deactivate, e -> shell2.close() ) ;
        
        shell1.open() ;
        shell2.open() ;
        
        Display display = shell1.getDisplay() ;
        
        while ( !shell1.isDisposed() ) {
            if ( !display.readAndDispatch() ) {
                display.sleep() ;
            }
        }
        display.dispose() ;
    }

    private static void addListeners( Control control ) {
        control.addListener( SWT.MouseDown, listener ) ;
        control.addListener( SWT.Activate, listener ) ;
        control.addListener( SWT.Deactivate, listener ) ;
    }

}

正常事件流(未添加关闭逻辑)

当shell2处于激活状态,点击composite1时,事件流完整:

Activate - Event {type=26 Composite {} [layout=null] time=483235453 data=null x=0 y=0 width=0 height=0 detail=3}
Deactivate - Event {type=27 Shell {2} [layout=FillLayout {type=SWT.HORIZONTAL}] time=483235453 data=null x=0 y=0 width=0 height=0 detail=0}
Deactivate - Event {type=27 Composite {} [layout=null] time=483235453 data=null x=0 y=0 width=0 height=0 detail=0}
Activate - Event {type=26 Shell {1} [layout=FillLayout {type=SWT.HORIZONTAL}] time=483235453 data=null x=0 y=0 width=0 height=0 detail=3}
MouseDown - Event {type=3 Composite {} [layout=null] time=483236000 data=null x=187 y=115 width=0 height=0 detail=0}

异常事件流(添加关闭逻辑)

添加shell2.addListener( SWT.Deactivate, e -> shell2.close() )后,执行相同操作,事件流被截断:

Activate - Event {type=26 Composite {} [layout=null] time=483714125 data=null x=0 y=0 width=0 height=0 detail=3}
Deactivate - Event {type=27 Shell {*Disposed*} [layout=null] time=483714125 data=null x=0 y=0 width=0 height=0 detail=0}

原因分析

  1. SWT事件同步派发特性:SWT的事件按顺序同步执行,在处理shell2的SWT.Deactivate事件时,直接调用shell2.close()会立即触发Shell销毁流程,包括释放资源、移除Display事件队列中的关联上下文。
  2. 事件链被打断:此时系统正处于窗口激活切换的事件序列中,Shell销毁会干扰Display的事件派发逻辑,导致后续已入队的事件(如shell1的Activate、MouseDown)因上下文被破坏而被丢弃。
  3. Dispose事件优先级:shell.close()会触发SWT.Dispose事件,该事件的处理会打断当前事件链,终止后续事件的执行。

解决方案

核心是延迟执行Shell关闭操作,让当前事件序列完整处理完毕后再执行销毁逻辑,避免干扰事件派发。

方法:使用Display.asyncExec()延迟关闭

将关闭操作放入异步执行队列,确保当前所有已入队的事件处理完成后再关闭Shell:

shell2.addListener(SWT.Deactivate, e -> {
    shell2.getDisplay().asyncExec(() -> {
        if (!shell2.isDisposed()) { // 避免重复销毁
            shell2.close();
        }
    });
});

修改后,事件流会恢复完整,shell2会在所有激活切换、鼠标点击事件处理完成后再关闭。


内容的提问来源于stack exchange,提问作者Bourbon_7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:35:12