org.eclipse.swt.widgets.Monitor获取第二台显示器数据值异常求助
问题
我想要获取所有显示器的尺寸和缩放比例,编写了如下ApplicationMonitorsManager代码:
package root.viewer.rcp.util; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Monitor; import org.eclipse.ui.PlatformUI; public class ApplicationMonitorsManager { public Monitor[] monitors; //public Display display = new Display(); public ApplicationMonitorsManager() { } public Monitor[] getMonitors() { //Display display = Display.getCurrent(); Display display = PlatformUI.createDisplay(); monitors = display.getMonitors(); return monitors; } }
主显示器返回的数据正确:
clientHeight 2070 clientWidth 3840 clientX 0 clientY 0 handle 200823 height 2160 width 3840 x 0 y 0 zoom 225
第二台显示器与主显示器分辨率相同,但缩放比例为125%,获取到的数据却异常:
clientHeight 3798 clientWidth 6912 clientX 6912 clientY 0 handle 200517 height 3888 width 6912 x 6912 y 0 zoom 225
尝试使用Display display = Display.getCurrent()或Display display = PlatformUI.createDisplay()均无效果,使用Display display = new Display()时应用会崩溃,抛出SWTException: Invalid thread access异常。
问题分析与解决
核心问题原因
- 错误创建Display实例:
PlatformUI.createDisplay()会生成新的Display实例,而非复用RCP应用已绑定UI线程的Display。新实例无法正确识别系统多显示器的DPI缩放配置,导致第二台显示器的尺寸被错误套用主显示器的缩放比例计算,出现异常数值。 - 线程访问限制:SWT规定所有UI操作必须在UI线程执行,
new Display()在非UI线程调用会直接触发Invalid thread access异常;Display.getCurrent()在非UI线程调用会返回null,同样无法正常获取显示器数据。
正确实现方案
- 复用已有Display实例:在RCP应用中,通过
PlatformUI.getWorkbench().getDisplay()获取应用主Display,该实例已绑定UI线程,能正确读取所有显示器的DPI缩放配置。 - 确保UI线程执行:如果需要在非UI线程获取显示器数据,必须通过
Display.syncExec()或asyncExec()将操作切换到UI线程执行。
修改后的代码示例:
package root.viewer.rcp.util; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Monitor; import org.eclipse.ui.PlatformUI; public class ApplicationMonitorsManager { public Monitor[] getMonitors() { // 获取RCP应用已有的UI线程Display Display display = PlatformUI.getWorkbench().getDisplay(); if (display == null || display.isDisposed()) { throw new IllegalStateException("无法获取有效的UI Display实例"); } return display.getMonitors(); } }
额外说明
Monitor.getZoom()返回的是缩放比例的千分比(比如225代表225%,125代表125%),转换为百分比时除以10即可。- 获取显示器区域时,要区分
getBounds()(包含任务栏的整个屏幕区域)和getClientArea()(可用工作区域),按需选择对应方法。
内容的提问来源于stack exchange,提问作者know
相关产品推荐
相关产品推荐

