SWT Tree控件整行悬停与选中颜色设置问题
SWT Tree 整行背景色覆盖需求
已为SWT Tree控件添加SWT.EraseItem监听器,用于自定义选中、悬停状态的颜色。目前颜色仅作用于树项的文本区域,需要修改为覆盖Tree控件的整行宽度。
参考效果:选中或悬停树项时,背景色填充Tree控件的整个横向范围,包含缩进区域在内的整行。
现有实现代码:
tree.addListener(SWT.EraseItem, new Listener() { @Override public void handleEvent(Event event) { if ((event.detail & SWT.SELECTED) != 0 && (event.detail & SWT.MouseHover) != 0) { int width = getBounds().width; GC gc = event.gc; gc.setForeground(new Color(Display.getCurrent(), 0, 0, 0)); gc.setBackground(new Color(Display.getCurrent(), 213, 215, 219)); gc.fillRectangle(0, event.y, width, event.height); event.detail &= ~SWT.MouseHover; event.detail &= ~SWT.SELECTED; } if ((event.detail & SWT.SELECTED) != 0 && !tree.isFocusControl()) { int width = tree.getClientArea().width; GC gc = event.gc; gc.setForeground(new Color(Display.getCurrent(), 0, 0, 0)); gc.setBackground(new Color(Display.getCurrent(), 230, 232, 235)); gc.fillRectangle(0, event.y, width, event.height); event.detail &= ~SWT.SELECTED; } if ((event.detail & SWT.MouseHover) != 0) { int width = tree.getClientArea().width; GC gc = event.gc; gc.setForeground(new Color(Display.getCurrent(), 0, 0, 0)); gc.setBackground(new Color(Display.getCurrent(), 213, 215, 219)); gc.fillRectangle(0, event.y, width, event.height); event.detail &= ~SWT.MouseHover; } if ((event.detail & SWT.SELECTED) != 0) { int width = tree.getClientArea().width; GC gc = event.gc; gc.setForeground(new Color(Display.getCurrent(), 0, 0, 0)); gc.setBackground(new Color(Display.getCurrent(), 192, 235, 237)); gc.fillRectangle(0, event.y, width, event.height); event.detail &= ~SWT.SELECTED; } Color previousForegroundColor = event.gc.getForeground(); event.gc.setForeground(previousForegroundColor); } });
问题原因及修复方案
核心问题
代码第一个条件分支中使用getBounds().width获取的是树项自身的文本区域宽度,而非Tree控件的整行宽度,导致背景色仅填充文本部分。
修复步骤
- 统一使用
tree.getClientArea().width作为填充矩形的宽度,确保覆盖Tree控件的整个横向范围。 - 优化Color资源管理:优先使用系统预设颜色避免资源泄漏,或手动创建Color后在控件销毁时统一释放。
- 保持填充起始x坐标为0,确保从Tree控件最左侧开始填充整行。
修复后代码
tree.addListener(SWT.EraseItem, new Listener() { @Override public void handleEvent(Event event) { Display display = Display.getCurrent(); GC gc = event.gc; int fullWidth = tree.getClientArea().width; int itemY = event.y; int itemHeight = event.height; // 选中且悬停状态 if ((event.detail & SWT.SELECTED) != 0 && (event.detail & SWT.MouseHover) != 0) { gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); gc.setBackground(new Color(display, 213, 215, 219)); gc.fillRectangle(0, itemY, fullWidth, itemHeight); event.detail &= ~(SWT.MouseHover | SWT.SELECTED); } // 无焦点时的选中状态 else if ((event.detail & SWT.SELECTED) != 0 && !tree.isFocusControl()) { gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); gc.setBackground(new Color(display, 230, 232, 235)); gc.fillRectangle(0, itemY, fullWidth, itemHeight); event.detail &= ~SWT.SELECTED; } // 单纯悬停状态 else if ((event.detail & SWT.MouseHover) != 0) { gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); gc.setBackground(new Color(display, 213, 215, 219)); gc.fillRectangle(0, itemY, fullWidth, itemHeight); event.detail &= ~SWT.MouseHover; } // 有焦点时的选中状态 else if ((event.detail & SWT.SELECTED) != 0) { gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); gc.setBackground(new Color(display, 192, 235, 237)); gc.fillRectangle(0, itemY, fullWidth, itemHeight); event.detail &= ~SWT.SELECTED; } // 注意:手动创建的Color需在Tree的SWT.Dispose事件中统一释放,或改用display.getSystemColor()获取系统颜色 } });
额外优化建议
- 避免重复创建Color对象:提前定义全局Color变量,在Tree销毁时释放;或直接使用
Display.getSystemColor()获取系统预设颜色,更安全高效。 - 使用
else if简化条件判断,避免多个分支同时触发。
内容的提问来源于stack exchange,提问作者user22061831
相关产品推荐
相关产品推荐

