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

如何监听Shell标题栏点击?SWT双ON_TOP窗口层级变更事件检测

SWT ON_TOP Shell窗口层级变化捕获问题

问题场景

现有两个带SWT.ON_TOP样式的Shell窗口:

  • 状态1:A位于B上方,B处于激活状态(通过点击B的内容区域进入此状态)
  • 状态2:点击B的标题栏后,B被置于A上方,但此操作无法触发Activate、Deactivate或MouseDown事件,界面却已发生层级变化

需要捕获用户点击B标题栏切换到状态2的操作,测试代码如下:

public class ShellTest {

    public static void main(String[] args) {
        Shell shellA = new Shell( SWT.SHELL_TRIM | SWT.ON_TOP ) ;
        shellA.setSize( 300, 300 ) ;
        shellA.setText( "A" ) ;
        
        Shell shellB = new Shell( SWT.SHELL_TRIM | SWT.ON_TOP ) ;
        shellB.setSize( 300, 300 ) ;
        shellB.setText( "B" ) ;
        
        shellB.addListener( SWT.Activate, e -> {
            if ( shellA != null && !shellA.isDisposed() ) {
                shellA.moveAbove( null ) ;
            }
        } ) ;
        
        Display display = shellB.getDisplay() ;
        display.addFilter( SWT.Activate, e -> System.out.println( e ) ) ;
        display.addFilter( SWT.Deactivate, e -> System.out.println( e ) ) ;

        
        shellA.open() ;
        shellB.open() ;
        
        while ( !shellA.isDisposed() && !shellB.isDisposed() ) {
            if ( !display.readAndDispatch() ) {
                display.sleep() ;
            }
        }
        display.dispose() ;
    }
    
}

原因分析

SWT.ON_TOP窗口的层级调整由操作系统窗口管理器直接处理,未触发SWT的常规激活/鼠标事件,因此无法通过常规事件监听捕获。

解决方案

1. 监听SWT.Move事件

部分系统中,点击标题栏调整层级时会触发窗口的SWT.Move事件,可通过此事件触发层级检查:

// 给两个Shell添加Move事件监听
shellA.addListener(SWT.Move, e -> checkZOrder(shellA, shellB));
shellB.addListener(SWT.Move, e -> checkZOrder(shellA, shellB));

private static void checkZOrder(Shell a, Shell b) {
    if (a.isDisposed() || b.isDisposed()) return;
    // 判断B是否在A上方
    boolean bAboveA = b.isAbove(a);
    if (bAboveA) {
        System.out.println("检测到B被置于A上方");
    }
}

2. 全局监听SWT.ShellActivated事件

通过Display的全局过滤器监听SWT.ShellActivated,并延迟判断层级(确保系统完成层级调整):

Display display = shellB.getDisplay();
display.addFilter(SWT.ShellActivated, e -> {
    Shell target = (Shell) e.widget;
    if (target == shellB) {
        // 延迟100ms执行,避免系统层级调整未完成
        display.timerExec(100, () -> {
            if (!shellA.isDisposed() && !shellB.isDisposed()) {
                if (shellB.isAbove(shellA)) {
                    System.out.println("捕获到B标题栏点击操作,层级切换");
                }
            }
        });
    }
});

3. 定时轮询层级(兜底方案)

如果上述事件均无法触发,可通过定时任务轮询窗口层级状态:

boolean lastState = false; // 记录上次层级状态
Display display = shellB.getDisplay();

display.timerExec(200, new Runnable() {
    @Override
    public void run() {
        if (shellA.isDisposed() || shellB.isDisposed()) return;
        
        boolean currentState = shellB.isAbove(shellA);
        if (currentState != lastState) {
            lastState = currentState;
            if (currentState) {
                System.out.println("检测到B切换到A上方");
            }
        }
        // 继续定时轮询
        display.timerExec(200, this);
    }
});

关键说明

  • isAbove(Shell)方法是SWT提供的直接判断窗口层级关系的API,返回目标窗口是否在当前窗口的视觉上方
  • 延迟执行和定时轮询的时间可根据系统响应速度调整,建议在100-300ms区间

内容的提问来源于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 04:57:40