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

前言

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

  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.mfbz.cn/a/182093.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue框架学习笔记——Vue实例中el和data的两种写法

文章目录 前文提要Vue实例的el第一种写法第二种写法小结 Vue实例中data第一种写法&#xff0c;对象式效果图片第二种写法&#xff0c;函数式效果图片小结 前文提要 本文仅做自己的学习记录&#xff0c;如有错误&#xff0c;请多谅解 Vue实例的el 第一种写法 <body><…

工业一体全国产方案,米尔T113核心板

入门级HMI屏作为嵌入式系统中重要组成部分&#xff0c;大部分都是串口屏&#xff1b;其功能简单、成本低等特点&#xff0c;使用历史悠久、应用广泛&#xff0c;而随着信息技术的快速发展&#xff0c;行业需求不断升级&#xff0c;工程师使用了大量串口屏后&#xff0c;发现串口…

微服务保护 Sentinel

1.初识Sentinel 文章目录 1.初识Sentinel1.1.雪崩问题及解决方案1.1.1.雪崩问题1.1.2.超时处理1.1.3.仓壁模式1.1.4.断路器1.1.5.限流1.1.6.总结 1.2.服务保护技术对比1.3.Sentinel介绍和安装1.3.1.初识Sentinel1.3.2.安装Sentinel 1.4.微服务整合Sentinel 2.流量控制2.1.簇点链…

python opencv 放射变换和图像缩放-实现图像平移旋转缩放

python opencv 放射变换和图像缩放-实现图像平移旋转缩放 我们实现这次实验主要用到cv2.resize和cv2.warpAffine cv2.warpAffine主要是传入一个图像矩阵&#xff0c;一个M矩阵&#xff0c;输出一个dst结果矩阵&#xff0c;计算公式如下&#xff1a; cv2.resize则主要使用fx&…

Arm64版本的centos编译muduo库遇到的问题的归纳

环境&#xff1a;Mac m2 pro下的VMware虚拟机中Arm64 centos ./build.sh 执行后提示如下 cmake -DCMAKE_BUILD_TYPErelease -DCMAKE_INSTALL_PREFIX…/release-install-cpp11 -DCMAKE_EXPORT_COMPILE_COMMANDSON /root/package/muduo-master – Boost version: 1.69.0 – Co…

【双指针】和为 s 的两个数字

和为 s 的两个数字 文章目录 和为 s 的两个数字题目描述算法思路暴力枚举双指针 代码编写Java代码C代码编写 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 题目描述 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品…

Go语言中结构体的使用和示例

结构体&#xff08;简称struct&#xff09;用于创建不同数据类型的成员集合&#xff0c;放入一个单一的变量中。虽然数组用于将相同数据类型的多个值存储在单一变量中&#xff0c;但结构体用于将不同数据类型的多个值存储在单一变量中。结构体对于将数据组合在一起以创建记录非…

云安全之盾:ZStack 云主机安全防护解决方案全方位保护云环境

随着云计算的蓬勃发展&#xff0c;网络威胁愈发复杂&#xff0c;涵盖了从勒索病毒到APT攻击的各种威胁类型。在这一风云变幻的网络安全环境下&#xff0c;云主机安全不再仅仅是一个选项&#xff0c;它是信息系统安全的核心要素。云轴科技ZStack 云主机安全防护解决方案是为了满…

国家超级计算济南中心低代码平台应用实践

摘要&#xff1a;文章主要介绍了济南超算使用低代码平台明道云解决了一系列业务问题&#xff0c;包括资产管理、人员与机构管理、流程制度管理等。通过明道云平台&#xff0c;济南超算成功地将不同部门的业务信息进行整合&#xff0c;提高了工作效率和管理水平。文章还强调了明…

操作系统 day13(RR)

RR&#xff08;时间片轮转&#xff09; 响应时间&#xff1a;系统中有10个进程正在并发执行&#xff0c;如果时间片为1秒&#xff0c;则一个进程被响应可能需要等待9秒。也就是说&#xff0c;如果用户在自己进程的时间片外通过键盘发出调试命令&#xff0c;可能需要等待9秒才能…

如何在AD上创建完整的项目

首先&#xff0c;我们先安装好AD&#xff0c;这里我使用的是AD22&#xff0c;安装过程如下&#xff1a; Altium Designer 22下载安装教程-CSDN博客 Altium Designer 22是全球领先的PCB设计软件之一&#xff0c;为电路板设计师提供了一种集成的解决方案&#xff0c;旨在简化和加…

Python大语言模型实战-记录一次用MetaGPT框架实现爬虫任务的完整过程

1、模型选择&#xff1a;GPT4 2、需求&#xff1a;在win10操作系统环境下&#xff0c;基于python3.10解释器&#xff0c;爬取豆瓣电影Top250的相关信息&#xff0c;包括电影详情链接&#xff0c;图片链接&#xff0c;影片中文名&#xff0c;影片外国名&#xff0c;评分&#x…

回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测

回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测 目录 回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现SCN随机配置网络多变量回归预测 1.data为数据集&#xff0c;7个输入特征&#xff0…

港口大型设备状态监测及预测性维护策略

在现代港口运营中&#xff0c;大型设备的正常运行对于保障港口作业的高效性至关重要。为了实现设备的可靠性和持续性&#xff0c;港口管理者需要采取一系列状态监测和预测性维护策略。 推进自动化和智能化是提高港口大型设备状态监测和维护管理效率的重要途径。通过应用先进的…

Node使用Nvm安装双版本切换(node两个版本同时用怎么办?不同的项目Node版本要求不一样怎么办?)

先把node.js卸载 开始—>添加删除程序—>node npm -v node -v //检查是否还存在&#xff0c;卸载成功就行了NVM下载 github下载 百度网盘下载 打开安装包以管理员身份安装&#xff0c;要是记得这个路径并且必须全是英文 使用nvm安装两个使用的node版本 cmd以管理员…

VR云游:让旅游产业插上数字化翅膀,打造地方名片

自多地入冬降温以来&#xff0c;泡温泉成了许多人周末度假的选择&#xff0c;在气温持续走低的趋势下&#xff0c;温泉游也迎来了旺季&#xff1b;但是依旧有些地区温度依旧温暖&#xff0c;例如南京的梧桐美景也吸引了不少游客前去打卡&#xff0c;大家穿着汉服与金黄的树叶合…

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

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

HCIP --- HCIA(部分汇总)--- 点对点网络

抽象语言 --- 电信号 抽象语言 --- 编码 编码 --- 二进制 二进制 --- 电信号 处理电信号 OSI/RM ---- 开放式系统互联参考模型 --- 1979 --- ISO --- 国际标准化组织 核心思想 --- 分层 应用层 --- 提供各种应用程序&#xff0c;抽象语言转换成编码&#xff0c;人机交互…

Web 自动化神器 TestCafe(三)—用例编写篇

一、用例编写基本规范 1、 fixture 测试夹具 使用 TestCafe 编写测试用例&#xff0c;必须要先使用 fixture 声明一个测试夹具&#xff0c;然后在这个测试夹具下编写测试用例&#xff0c;在一个编写测试用例的 js 或 ts 文件中&#xff0c;可以声明多个测试夹具 fixture(测试…
最新文章