目的
使用SWT技术自定义数据表格,本文抛砖引玉,给出了SWT构建数据表格的基本思路和简单实现。更多特殊需求即表格功能实现待续……
思路
数据表格由表格头与表格体两边部分组成。
表格头部分是固定的,其字段右侧包含一个简单的表格工具–排序;
表格体部分重要用来展示数据,它需要支持滚动,本示例只实现了纵向滚动(横向滚动可参考纵向滚动自行完成)
技术方面。滚动可以使用 ScrolledComposite
滚动组件,数据表格布局使用 GridLayout
完成。
实现
在本例中,依然在编辑器中展示效果,具体步骤如下:
- plugin.xml 中定义编辑器
<!-- 编辑器-SWT自定义表格 --><editorclass="com.xzbd.editors.CustomTableEditor"default="false"extensions="ctb"icon="icons/20220417/chenggongtishi.png"id="com.xzbd.editor.CustomTableEditor"name="编辑器-SWT自定义表格"></editor>
- 编辑器实现类
package com.xzbd.editors;import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;import com.xzbd.views.CustomTableEditorViewer;public class CustomTableEditor extends EditorPart {public static String ID = "com.xzbd.editors.CustomTableEditor";public boolean isDirty = false;private CustomTableEditorViewer viewer;@Overridepublic void doSave(IProgressMonitor monitor) {clearDirty();}@Overridepublic void doSaveAs() {}@Overridepublic void init(IEditorSite site, IEditorInput input) throws PartInitException {this.setSite(site);this.setInput(input);}@Overridepublic boolean isDirty() {return isDirty;}@Overridepublic boolean isSaveAsAllowed() {return false;}@Overridepublic void createPartControl(Composite parent) {viewer = new CustomTableEditorViewer(parent, this);}@Overridepublic void setFocus() {}/*** 转换编辑器状态* * @param isDirty*/public void changeDirtyState(boolean isDirty) {this.isDirty = isDirty;firePropertyChange(PROP_DIRTY);}public void toDirty() {changeDirtyState(true);}public void clearDirty() {changeDirtyState(false);}
}
- 视图实现类
package com.xzbd.views;import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;import com.xzbd.editors.CustomTableEditor;
import com.xzbd.utils.LayoutUtil;
import com.xzbd.utils.SWTResourceManager;/*** * SWT-自定义数据表编辑器视图**/
public class CustomTableEditorViewer {private CustomTableEditor editor;private Composite parent;public CustomTableEditorViewer(Composite parent, CustomTableEditor editor) {this.parent = parent;// 缓存 EditorsetEditor(editor);// 绘制UIbuildPageUI();}// 创建UIprivate void buildPageUI() {// 设置 parent 布局parent.setLayout(new FillLayout());Composite contaniner = new Composite(parent, SWT.NONE);contaniner.setLayout(new GridLayout());Label descLabel = new Label(contaniner, SWT.NONE);descLabel.setText("这个表格是完全自定义的,虽然比较简单,但可以作为自定义表格原型");Label sepratorLine = new Label(contaniner, SWT.SEPARATOR | SWT.HORIZONTAL);sepratorLine.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));Composite header = new Composite(contaniner, SWT.NONE);header.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));header.setLayout(new GridLayout(4, false));for (int j = 0; j < 4; j++) {Composite col = new Composite(header, SWT.NONE);col.setLayout(new GridLayout(2, false));col.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));Label label = new Label(col, SWT.None);label.setText("列-00" + j + 1);Composite tools = new Composite(col, SWT.NONE);tools.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));tools.setLayout(LayoutUtil.clearMarin(new GridLayout()));Label asc = new Label(tools, SWT.NONE);asc.setImage(SWTResourceManager.getImage(CustomTableEditorViewer.class, "/icons/sort-up.png"));Boolean[] check = { false };Boolean[] line = { false };asc.addPaintListener(e -> {if (line[0] || check[0]) {GC gc = e.gc;Rectangle bounds = asc.getBounds();
// gc.setForeground(ColorConstant.MAIN_BLUE);gc.drawRectangle(0, 0, bounds.width - 1, bounds.height - 1);gc.dispose();}});asc.addListener(SWT.MouseEnter, e -> {line[0] = true;asc.redraw();});asc.addListener(SWT.MouseExit, e -> {if (check[0]) {return;}line[0] = false;asc.redraw();});asc.addListener(SWT.MouseDown, e -> {check[0] = !check[0];asc.redraw();});Label desc = new Label(tools, SWT.PUSH);desc.setImage(SWTResourceManager.getImage(CustomTableEditorViewer.class, "/icons/sort-down.png"));}Label seprator = new Label(contaniner, SWT.SEPARATOR | SWT.HORIZONTAL);seprator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));Composite scContaniner = new Composite(contaniner, SWT.NONE);scContaniner.setLayoutData(new GridData(GridData.FILL_BOTH));scContaniner.setLayout(new FillLayout());// 滑动面板ScrolledComposite sc = new ScrolledComposite(scContaniner, SWT.H_SCROLL | SWT.V_SCROLL);Composite content = new Composite(sc, SWT.None);content.setLayout(new GridLayout());
// content.setBackground(SWTResourceManager.getColor(SWT.COLOR_RED));Color activeColor = SWTResourceManager.getColor(SWT.COLOR_GRAY);Listener activeListener = e -> {Control widget = (Control) e.widget;widget.setBackground(activeColor);};Listener defaultListener = e -> {Control widget = (Control) e.widget;widget.setBackground(null);};for (int i = 0; i < 100; i++) {Composite row = new Composite(content, SWT.NONE);GridData gridData = new GridData(GridData.FILL_HORIZONTAL);row.setLayoutData(gridData);row.setLayout(new GridLayout(4, false));for (int j = 0; j < 4; j++) {Label label = new Label(row, SWT.None);label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));label.setText(i + "行" + j + "列 : " + i + " - " + j);// 事件绑定label.addListener(SWT.MouseEnter, activeListener);label.addListener(SWT.MouseExit, defaultListener);}Label rowSeprator = new Label(content, SWT.SEPARATOR | SWT.HORIZONTAL);rowSeprator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));// 事件绑定row.addListener(SWT.MouseEnter, activeListener);row.addListener(SWT.MouseExit, defaultListener);}sc.setExpandHorizontal(true);sc.setExpandVertical(true);sc.addControlListener(ControlListener.controlResizedAdapter(e -> {Rectangle r = sc.getClientArea();sc.setMinSize(content.computeSize(r.width, SWT.DEFAULT));}));// 设置滑动内容sc.setContent(content);content.setSize(content.computeSize(SWT.DEFAULT, SWT.DEFAULT));// sc 重新绘制,否则不显示 滑动内容sc.layout();}public CustomTableEditor getEditor() {return editor;}public void setEditor(CustomTableEditor editor) {this.editor = editor;}private void addDirtyListener(Widget com) {com.addListener(SWT.Modify, e->{editor.toDirty();});}}
其中使用到的工具类,请参考项目中相关源码,项目地址:https://gitee.com/xzbd/epx
效果
总结
本文使用 SWT 中的 ScrolledComposite
、 GridLayout
和 SWT 事件实现了一个简单的数据表格实现,表格功能相对比较简单,但有足够的启发性,读者可据此实现更复杂的表格。
-
项目地址:https://gitee.com/xzbd/epx
-
SWT测试实现
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;import com.xzbd.swt01.core.ColorConstant;
import com.xzbd.swt01.utils.LayoutUtil;
import com.xzbd.swt01.utils.SWTResourceManager;
import com.xzbd.swt01.utils.SWTTools;public class ScrolledCompositeTest {public static void main(String[] args) {final Display display = new Display();final Shell shell = new Shell(display);shell.setText("SWT 自定义数据表");shell.setLayout(new FillLayout());Composite contaniner = new Composite(shell, SWT.NONE);contaniner.setLayout(new GridLayout());Composite header = new Composite(contaniner, SWT.NONE);header.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));header.setLayout(new GridLayout(4, false));for (int j = 0; j < 4; j++) {Composite col = new Composite(header, SWT.NONE);col.setLayout(new GridLayout(2, false));col.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));Label label = new Label(col, SWT.None);label.setText("列-00" + j + 1);Composite tools = new Composite(col, SWT.NONE);tools.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));tools.setLayout(LayoutUtil.clearMarin(new GridLayout()));Label asc = new Label(tools, SWT.NONE);asc.setImage(SWTResourceManager.getImage(ScrolledCompositeTest.class, "/icons/sort-up.png"));Boolean[] check = { false };Boolean[] line = { false };asc.addPaintListener(e -> {if (line[0] || check[0]) {GC gc = e.gc;Rectangle bounds = asc.getBounds();
// gc.setForeground(ColorConstant.MAIN_BLUE);gc.drawRectangle(0, 0, bounds.width - 1, bounds.height - 1);gc.dispose();}});asc.addListener(SWT.MouseEnter, e -> {line[0] = true;asc.redraw();});asc.addListener(SWT.MouseExit, e -> {if (check[0]) {return;}line[0] = false;asc.redraw();});asc.addListener(SWT.MouseDown, e -> {check[0] = !check[0];asc.redraw();});Label desc = new Label(tools, SWT.PUSH);desc.setImage(SWTResourceManager.getImage(ScrolledCompositeTest.class, "/icons/sort-down.png"));}Label seprator = new Label(contaniner, SWT.SEPARATOR | SWT.HORIZONTAL);seprator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));Composite scContaniner = new Composite(contaniner, SWT.NONE);scContaniner.setLayoutData(new GridData(GridData.FILL_BOTH));scContaniner.setLayout(new FillLayout());// 滑动面板ScrolledComposite sc = new ScrolledComposite(scContaniner, SWT.H_SCROLL | SWT.V_SCROLL);Composite content = new Composite(sc, SWT.None);content.setLayout(new GridLayout());
// content.setBackground(SWTResourceManager.getColor(SWT.COLOR_RED));Color activeColor = SWTResourceManager.getColor(SWT.COLOR_GRAY);Listener activeListener = e -> {Control widget = (Control) e.widget;widget.setBackground(activeColor);};Listener defaultListener = e -> {Control widget = (Control) e.widget;widget.setBackground(null);};for (int i = 0; i < 100; i++) {Composite row = new Composite(content, SWT.NONE);GridData gridData = new GridData(GridData.FILL_HORIZONTAL);row.setLayoutData(gridData);row.setLayout(new GridLayout(4, false));for (int j = 0; j < 4; j++) {Label label = new Label(row, SWT.None);label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));label.setText(i + "行" + j + "列 : " + i + " - " + j);// 事件绑定label.addListener(SWT.MouseEnter, activeListener);label.addListener(SWT.MouseExit, defaultListener);}Label rowSeprator = new Label(content, SWT.SEPARATOR | SWT.HORIZONTAL);rowSeprator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));// 事件绑定row.addListener(SWT.MouseEnter, activeListener);row.addListener(SWT.MouseExit, defaultListener);}sc.setExpandHorizontal(true);sc.setExpandVertical(true);sc.addControlListener(ControlListener.controlResizedAdapter(e -> {Rectangle r = sc.getClientArea();sc.setMinSize(content.computeSize(r.width, SWT.DEFAULT));}));// 设置滑动内容sc.setContent(content);content.setSize(content.computeSize(SWT.DEFAULT, SWT.DEFAULT));// sc 重新绘制,否则不显示 滑动内容sc.layout();shell.setSize(800, 720);shell.open();while (!shell.isDisposed()) {if (!display.readAndDispatch())display.sleep();}display.dispose();}
}