SWT/Jface(2): 表格的编辑

news2024/9/24 18:34:14

前言

上节说到, 创建和渲染表格需要如下几个步骤:

  1. 接收源数据数组(也可以是单个对象或者其他集合类型): TableViewer.setInput(Object)
  2. 渲染接收的数据
    1. 渲染表头: TableViewer.setLabelProvider(IBaseLabelProvider)
    2. 渲染内容: TableViewer.setContentProvider(IContentProvider)

在实际应用中我们往往需要编辑表格并实现双向绑定, 本节内容主要集中讲如何对表格单元格添加编辑支持.

需求

当双击单元格时进入编辑模式

步骤

添加编辑支持

Jface提供了EditingSupport抽象类, 可以很方便的实现, 不过需要配合TableViewerColumn使用, 上节我们根据表头数组创建了列:

        String[] titles = {"ID", "姓名", "性别", "年龄"};
        // 创建列头信息, 并最终绑定到table
        Arrays.stream(titles).forEach(title -> TableColumnFactory.newTableColumn(SWT.NONE).width(80).text(title).create(table));

如需添加编辑支持可以直接根据TableColumn创建TableViewerColumn并将每一列对应的EditingSupport实现赋值给TableViewerColumn即可.
实现EditingSupport需要覆写的方法简介:

  1. CellEditor getCellEditor(Object): 当前列对应的编辑器类型, 主要有:
    1. TextCellEditor: 文字编辑器, 非常通用
    2. CheckboxCellEditor: 复选编辑器
    3. ComboBoxCellEditor: 下拉列表编辑器
    4. ColorCellEditor: 颜色编辑器
    5. DialogCellEditor: 对话编辑器, 这是高级用法, 可以实现个性定制
  2. boolean canEdit(Object): 当前列是否支持编辑
  3. Object getValue(Object): 编辑初始状态显示的值
  4. void setValue(Object oldValue, Object newValue): 编辑结束时需要赋值的逻辑, 第一个参数为编辑前对应的值, 第二个为编辑后对应的新值, 值类型取决于编辑器, 比如TextCellEditor对应的就是String类型.

需要注意的是, 当我们接受新值后, 要刷新下当前表格, 否则界面展示依然是之前的值, 也就是说我们在setValue方法的最后需要加上一行

tableViewer.update(o, null);

此时我们丰富一下创建表头的逻辑, 这里列出空实现:

// 创建列头信息, 并最终绑定到table
Arrays.stream(titles).forEach(title -> {
    TableColumn tableColumn = TableColumnFactory.newTableColumn(SWT.NONE).width(80).text(title).create(table);
    // 创建TableViewerColumn关联到当前列并添加编辑支持
    new TableViewerColumn(tableViewer, tableColumn).setEditingSupport(new EditingSupport(tableViewer) {
        @Override
        protected CellEditor getCellEditor(Object o) {
            return null;
        }
        @Override
        protected boolean canEdit(Object o) {
            return false;
        }
        @Override
        protected Object getValue(Object o) {
            return null;
        }
        @Override
        protected void setValue(Object o, Object o1) {
        	// 赋值逻辑...
            tableViewer.update(o, null);
        }
    });
});

添加触发条件

仅仅添加编辑支持是不够的, 因为系统不知道什么时候切换为编辑状态, 比如我们只希望在双击当前单元格时开启编辑状态, Jface提供了ColumnViewerEditorActivationStrategy来控制策略:

ColumnViewerEditorActivationStrategy activationStrategy = new ColumnViewerEditorActivationStrategy(tableViewer) {
    @Override
    protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
        // 只有双击事件才激活编辑器
        return event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION;
    }
};

此时打开界面发现单击表格也进入了编辑状态, 并且一次性就高亮显示整行, 这和需求不符, 我们需要借助TableViewerEditor来强制激活此策略, 并集成TableViewerFocusCellManager来高亮显示本单元格而不是整行:

TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(tableViewer, new FocusCellOwnerDrawHighlighter(tableViewer));
TableViewerEditor.create(tableViewer, focusCellManager, activationStrategy, ColumnViewerEditor.DEFAULT);

此时我们只需要将之前的EditingSupport根据实际业务完善下基本就OK了, 整体源码见下一小节, 先看下效果.

在这里插入图片描述

数据校验

实际业务中可能对某些数据有特殊要求, 此时就要对输入的数据进行校验, 并给出提示, 我们可以借助MessageBox来实现提示, 将校验逻辑放在EdittingSupport.setValue方法中.
比如对年龄的校验可以这样写:

@Override
protected void setValue(Object o, Object o1) {
	String newValue = String.valueOf(o1);
	if (o instanceof People people) {
		switch (title) {
			case "年龄" -> {
				try {
					people.setAge(Integer.parseInt(newValue));
				} catch (Exception e) {
					MessageBox messageBox = new MessageBox(shell);
					messageBox.setText("输入不合法");
					messageBox.setMessage("必须是数字");
					messageBox.open();
				}
			}
			// 其他逻辑
		}
	}
	tableViewer.update(o, null);
}

看下效果:
在这里插入图片描述

源码

import org.eclipse.jface.viewers.*;
import org.eclipse.jface.widgets.TableColumnFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        final Display display = Display.getDefault();
        final Shell shell = new Shell();
        shell.setLayout(new FillLayout());
        shell.setSize(500, 375);
        shell.setText("SWT Application");

        //注意这里,SWT.MULTI代表可以选择多行,SWT.FULL_SELECTION代表可以整行选择,SWT.BORDER边框,SWT.V_SCROLL ,SWT.H_SCROLL滚动条
        TableViewer tableViewer = new TableViewer(shell, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);

        Table table = tableViewer.getTable();
        // 表格边框线是否可见
        table.setLinesVisible(true);
        // 表头是否可见
        table.setHeaderVisible(true);
        // 设置表格大小
        table.setBounds(97, 79, 373, 154);
        String[] titles = {"ID", "姓名", "性别", "年龄"};
        // 创建列头信息, 并最终绑定到table
        Arrays.stream(titles).forEach(title -> {
            TableColumn tableColumn = TableColumnFactory.newTableColumn(SWT.NONE).width(80).text(title).create(table);
            new TableViewerColumn(tableViewer, tableColumn).setEditingSupport(new EditingSupport(tableViewer) {
                @Override
                protected CellEditor getCellEditor(Object o) {
                    return new TextCellEditor(tableViewer.getTable());
                }

                @Override
                protected boolean canEdit(Object o) {
                    return !"ID".equalsIgnoreCase(title);
                }

                @Override
                protected Object getValue(Object o) {
                    if (o instanceof People people) {
                        return switch (title) {
                            case "ID" -> String.valueOf(people.getId());
                            case "姓名" -> people.getName();
                            case "性别" -> people.getSex();
                            case "年龄" -> String.valueOf(people.getAge());
                            default -> "";
                        };
                    }
                    return "";
                }

                @Override
                protected void setValue(Object o, Object o1) {
                    String newValue = String.valueOf(o1);
                    if (o instanceof People people) {
                        switch (title) {
                            case "年龄" -> {
                                try {
                                    people.setAge(Integer.parseInt(newValue));
                                } catch (Exception e) {
                                    MessageBox messageBox = new MessageBox(shell);
                                    messageBox.setText("输入不合法");
                                    messageBox.setMessage("必须是数字");
                                    messageBox.open();
                                }
                            }
                            case "姓名" -> people.setName(newValue);
                            case "性别" -> people.setSex(newValue);
                        }
                    }
                    tableViewer.update(o, null);
                }
            });
        });


        ColumnViewerEditorActivationStrategy activationStrategy = new ColumnViewerEditorActivationStrategy(tableViewer) {
            @Override
            protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
                // 只有双击事件才激活编辑器
                return event.eventType == ColumnViewerEditorActivationEvent.MOUSE_DOUBLE_CLICK_SELECTION;
            }
        };
        table.setHeaderBackground(display.getSystemColor(SWT.COLOR_TITLE_BACKGROUND));
        table.setHeaderForeground(display.getSystemColor(SWT.COLOR_TITLE_FOREGROUND));
        TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(tableViewer, new FocusCellOwnerDrawHighlighter(tableViewer));
        TableViewerEditor.create(tableViewer, focusCellManager, activationStrategy, ColumnViewerEditor.DEFAULT);


        tableViewer.setContentProvider(ArrayContentProvider.getInstance());
        tableViewer.setLabelProvider(PeopleLabelProvider.getInstance());

        People people = new People();
        people.setId(1);
        people.setName("张三");
        people.setSex("男");
        people.setAge(10);
        tableViewer.setInput(new People[]{people});


        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }
}

其他方案

实现编辑支持还有其他方式, 比如实现ICellModifier, 不过这种方式需要额外指定properties用来指定和列名的对应关系, 个人不是很喜欢这种, 有兴趣可以参考: Swt/Jface tableViewer入门教程三(加入在表格上直接编辑数据)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1243686.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s-pod生命周期 4

容器环境初始化 pod 由pod 镜像来提供,在pod 生命周期里容器主要分为两种:初始化容器和主容器 初始化容器一定要成功运行并退出,当初始化容器运行退出完了之后主容器开始和运行 主容器开始运行的时候,有两个探针:存…

【C++初阶】STL详解(七)Stack与Queue的模拟实现

本专栏内容为:C学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C 🚚代码仓库:小小unicorn的代码仓库&…

git-3

1.如何让工作区的文件恢复为和暂存区一样? 工作区所作的变更还不及暂存区的变更好,想从暂存区拷贝到工作区,变更工作区(恢复成和暂存区一样的状态),想到用git checkout -- 文件名 2.怎样取消暂存区部分文件的更改? 如…

C语言函数练习(超基础超详细)

ps:题目来源于pta平台。 1. int sum(int m, int n) {int sum0;for(int im; i<n; i){sumi;}return sum; } 2. int max(int a, int b) {if(a>b)return a;else return b; } 3. double dist( double x1, double y1, double x2, double y2 ) {return sqrt((x1-x2)*(x1…

STM32笔记---RTC

目录 一、RTC简介 二、主要特性 三、功能描述 3.1 读RTC寄存器 3.2 配置RTC寄存器 四、BKP简介 五、RTC_Init() 1. 函数BKP_ReadBackupRegister 2.RCC_LSEConfig设置外部低速晶振&#xff08;LSE&#xff09; 3.RTC基本结构 5.RTC_Init()实现 6.time.h 一、R…

靠这份求职指南找工作,稳了!

大家好&#xff0c;我是鱼皮。为了帮助朋友们更好的准备秋招&#xff0c;我们精心汇总整理了 编程导航星球 内鱼友反馈的 200 多个高频求职问题和 150 多篇面经、以及最新秋招企业投递信息表&#xff0c;解答大家的求职困惑。 一、最新秋招投递信息表 目前已汇总整理了 600 多家…

spring 是如何开启事务的, 核心原理是什么

文章目录 spring 是如何开启事务的核心原理1 基于注解开启事务2 基于代码来开启事务 spring 是如何开启事务的 核心原理 Spring事务管理的实现有许多细节&#xff0c;如果对整个接口框架有个大体了解会非常有利于我们理解事务&#xff0c;下面通过讲解Spring的事务接口来了解…

人工智能今天能为你做什么?生成式人工智能如何改变技术文档领域

▲ 搜索“大龙谈智能内容”关注GongZongHao▲ 作者 | Fabrice Lacroix 大型语言模型&#xff08;LLM&#xff09;和生成式人工智能&#xff08;GenAI&#xff09;&#xff0c;尤其是ChatGPT&#xff0c;这些是引领科技革新的新兴技术。它们不仅在科技界引起了轩然大波&#x…

项目经理超能力图鉴

大家好&#xff0c;我是老原。 在项目管理中&#xff0c;项目经理远没有大家想象中的那么光鲜亮丽&#xff0c;反而成为了背锅的代名词。 项目顺利的时候&#xff0c;老板和颜悦色、团队融洽顺利&#xff1b; 项目出问题时&#xff0c;项目经理不得不承担起责任&#xff0c;…

在.bashrc文件修改环境变量的做法

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> ~/.bashrc文件是linux下保存环境变量的系统文件。原以为使用sed命令修改.bashrc文件&#xff0c;实际上不行&#xff0c;需要使用echo命令。具体示例如下…

[shader] 光照入门(未完结。。。

反射 漫反射&#xff1a;而当物体表面粗糙时&#xff0c;我们把物体表面看作无数不同方向的微小镜面&#xff0c;则这些镜面反射出的光方向均不相同&#xff0c;这就是漫反射。 高光反射&#xff1a;我们假定物体表面光滑&#xff0c;只有一个镜面&#xff0c;那么所有的光都…

【软件工程师从0到1】- 多态 (知识汇总)

前言 介绍&#xff1a;大家好啊&#xff0c;我是hitzaki辰。 社区&#xff1a;&#xff08;完全免费、欢迎加入&#xff09;日常打卡、学习交流、资源共享的知识星球。 自媒体&#xff1a;我会在b站/抖音更新视频讲解 或 一些纯技术外的分享&#xff0c;账号同名&#xff1a;hi…

使用XHProf查找PHP性能瓶颈

使用XHProf查找PHP性能瓶颈 XHProf是facebook 开发的一个测试php性能的扩展&#xff0c;本文记录了在PHP应用中使用XHProf对PHP进行性能优化&#xff0c;查找性能瓶颈的方法。 下载 网上很多是编译安装xhprof-0.9.4版本&#xff0c;应该是用php5&#xff0c;在php8.0下编译x…

【spring(三)】AOP总结

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 一、AOP相关概念 ① AOP核心思想思想&#xff1a; ② AOP专业术语&#xff1a; 二、AOP快速如入门 三、AOP工作流程 四、切入点表达式 ① 语法格式 ②支持通配符 ③书写技巧 五、通知类型 ①⭐环绕通知…

pip安装tkinter模块失败 No matching distribution found for tkinter

我想使用Python创建一个简单的桌面应用程序, 这个应用程序依赖于tkinter, 然而,当我尝试安装过程时,出现了错误。 $ pip install tkinter ERROR: Could not find a version that satisfies the requirement tkinter (from versions: none) ERROR: No matching distributio…

java--权限修饰符

1.什么是权限修饰符 就是是用来限制类中的成员(成员变量、成员方法、构造器、代码块...)能够被访问的范围。 2.权限修饰符有几种&#xff1f;各自的作用是什么&#xff1f; private<缺省<protected<public(范围由小到大)

【华为数通HCIP | 网络工程师】821-IGP高频题、易错题之OSPF(2)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

经典的回溯算法题leetcode组合问题整理及思路代码详解

目录 组合问题 leetcode77题.组合 leetcode216题.组合总和III leetcode40题.组合总和II leetcode39题.组合总和 倘若各位不太清楚回溯算法可以去看我上一篇文章。 回溯算法详解-CSDN博客 组合问题 一般组合和排列类的问题我们都会转化成一个树形问题&#xff0c;更便于…

C++程序中dump文件生成方法详解

最近项目中新作成了一个动态链接库&#xff0c;长时间运行后&#xff0c;偶尔会崩溃。根据log分析&#xff0c;被调用的动态库函数最外层catch到了这个异常&#xff0c;但是不能定位哪里出了问题。另外虽然上层exe是有dump文件输出处理的&#xff0c;但是在C中&#xff0c;如果…