JRT实现表格元素

news2024/11/28 2:41:27

数据结构决定算法基础,良好的设计可以极大的减轻上层的复杂度。以前由于受限M没画笔,都得通过Webservice代理出去,所以实现一些效果比较难。用M控制打印绘制表格就很费劲。但是打印报告结果、药敏等很多都是列表排版。用TextLength控制换行或者一个个字符串判断宽度换行实在是实现丑陋。

这些都是需要解决的痛点,先看效果:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

调换画表格代码
在这里插入图片描述

初步画表格实现,画一个表格很复杂,先定义好表格的数据结构,然后基于数据结构实现算法,因为涉及到画行、列、边框、还有单元格换行情况,本次算法上也进行足够的分离,把一个问题分而治之就不那么复杂了,每个方法负责对应职责,差不多一次就写通了。把画表格分割成了画行,画行分割成了画单元格和画构造边框数据,画单元格又分成切割串和画串,最或全部画完了再画边框。

import JRT.Core.DataGrid.GridColDto;
import JRT.Core.DataGrid.GridDto;
import JRT.Core.DataGrid.GridLineDto;
import JRT.Core.DataGrid.GridPageDto;
import JRT.Core.Dto.OutValue;
import JRT.Core.Dto.PrintElement;
import JRT.Core.Metrics.DrawMetricsHandler;
import JRT.Core.Util.PrintDrawProtocol;
import JRTBLLBase.BaseHttpHandlerNoSession;
import JRTBLLBase.Helper;

import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * 画表格测试,将要实现一个自动切割和实现换页的表格个业务使用
 */
public class DrawGrid extends BaseHttpHandlerNoSession {
    /**
     * 按传入的RowID输出符合打印元素绘制协议的数据来实现打印控制
     *
     * @param RowID   业务主键
     * @param P1
     * @param P2
     * @param P3
     * @param P4
     * @param P5
     * @param P6
     * @param P7
     * @param P8
     * @param P9
     * @param P10
     * @param P11
     * @param P12
     * @param P13
     * @param Session
     * @param Output
     * @return
     */
    public String GetData(String RowID, String P1, String P2, String P3, String P4, String P5, String P6, String P7, String P8, String P9, String P10, String P11, String P12, String P13, OutValue Session, OutValue Output) throws Exception {
        List<PrintElement> retList = null;
        //这部分由设计器维护的Json得到表格维护信息
        GridDto def = new GridDto();
        GridPageDto page = new GridPageDto();
        def.PageList.add(page);
        GridColDto col = null;
        //表格列
        for (int i = 0; i < 5; i++) {
            col = new GridColDto();
            col.DataField = "Col" + i;
            col.Width = 150;
            def.DataCol.add(col);
        }
        //这部分由业务打印组装数据
        List<Object> dataList = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            GridDataDto one = new GridDataDto();
            one.Col0 = "第" + i + "行0列,这是比较长的内容额,会自动换行";
            one.Col1 = "第" + i + "行1列,这是稍微长的内容";
            one.Col2 = "第" + i + "行2列,this is jrtbase draw grid test for printtemplate";
            one.Col3 = "第" + i + "行3列";
            one.Col4 = "1.这是第一行$r$n2.这是第二行$r$n3.这是第三行";
            dataList.add(one);
        }
        OutValue lastYObj = new OutValue();
        //绘制表格
        retList = DrawGrid(def, null, dataList, lastYObj);
        return Helper.Object2Json(retList);
    }

    /**
     * 绘制表格
     *
     * @param def      表格定义
     * @param headData 标题数据
     * @param datas    行数据
     * @param lastY    绘制完成最后Y
     * @return 表格的打印绘图元素
     */
    public List<PrintElement> DrawGrid(GridDto def, Object headData, List<Object> datas, OutValue lastY) throws Exception {
        List<PrintElement> retList = new ArrayList<>();
        //处理标题字体
        if (def.HeadCol.size() > 0) {
            for (GridColDto col : def.HeadCol) {
                if (col.PrintFont == null) {
                    col.PrintFont = def.PrintFont;
                }
                if (col.PrintFontSize == null) {
                    col.PrintFontSize = def.PrintFontSize;
                }
                if (col.PrintFontStyle == null) {
                    col.PrintFontStyle = def.PrintFontStyle;
                }
            }
        }
        //处理数据列字体
        if (def.DataCol.size() > 0) {
            for (GridColDto col : def.DataCol) {
                if (col.PrintFont == null) {
                    col.PrintFont = def.PrintFont;
                }
                if (col.PrintFontSize == null) {
                    col.PrintFontSize = def.PrintFontSize;
                }
                if (col.PrintFontStyle == null) {
                    col.PrintFontStyle = def.PrintFontStyle;
                }
            }
        }
        //测量句柄
        DrawMetricsHandler metricsHandler = new DrawMetricsHandler();
        //所有的边框
        HashMap<String, GridLineDto> boderMap = new HashMap();
        //绘制标题
        if (headData != null) {

        }
        //绘制数据行
        if (datas != null && datas.size() > 0) {
            int maxY = def.PageList.get(0).Top;
            //遍历绘制行
            for (int i = 0; i < datas.size(); i++) {
                Object rowData = datas.get(i);
                //绘制一行数据
                maxY = DrawOneRow(maxY, i, def, def.DataCol, rowData, boderMap, metricsHandler, retList);
            }
        }
        //画边框
        for (String key : boderMap.keySet()) {
            GridLineDto line = boderMap.get(key);
            PrintElement lineEle = PrintDrawProtocol.DrawLine(line.StartX, line.StartY, line.EndX, line.EndY, def.BoderWidth, "", "");
            retList.add(lineEle);
        }
        return retList;
    }

    /**
     * 绘制一行数据
     *
     * @param top            顶部
     * @param rowIndex       行号
     * @param def            表格定义
     * @param colList        列定义
     * @param rowData        一行数据
     * @param boderMap       边框
     * @param metricsHandler 测量工具
     * @param retList        元素
     * @return 最大Y
     * @throws Exception
     */
    private int DrawOneRow(int top, int rowIndex, GridDto def, List<GridColDto> colList, Object rowData, HashMap boderMap, DrawMetricsHandler metricsHandler, List<PrintElement> retList) throws Exception {
        int cellLeft = def.PageList.get(0).Left;
        int colIndex = -1;
        //行画到的最大Y
        int rowMaxY = top + def.RowHeight + def.PaddingTop + def.PaddingBottom;
        //循环绘制每个单元格内容
        for (GridColDto col : colList) {
            colIndex++;
            //画一个单元格
            int colMaxY = DrawOneCell(top, cellLeft, def, col, rowData, metricsHandler, retList);
            if (rowMaxY < colMaxY) {
                rowMaxY = colMaxY;
            }
            cellLeft += col.Width;
        }
        colIndex = -1;
        cellLeft = def.PageList.get(0).Left;
        //循环组成每个单元格边框
        for (GridColDto col : colList) {
            colIndex++;
            //上边框
            String key = (rowIndex - 1) + "H#" + colIndex;
            GridLineDto line = new GridLineDto();
            line.StartX = cellLeft;
            line.StartY = top;
            line.EndX = cellLeft + col.Width;
            line.EndY = top;
            boderMap.put(key, line);

            //下边框
            key = (rowIndex) + "H#" + colIndex;
            line = new GridLineDto();
            line.StartX = cellLeft;
            line.StartY = rowMaxY;
            line.EndX = cellLeft + col.Width;
            line.EndY = rowMaxY;
            boderMap.put(key, line);


            //左边框
            key = (rowIndex) + "V#" + (colIndex - 1);
            line = new GridLineDto();
            line.StartX = cellLeft;
            line.StartY = top;
            line.EndX = cellLeft;
            line.EndY = rowMaxY;
            boderMap.put(key, line);

            //右边框
            key = (rowIndex) + "VS#" + (colIndex);
            line = new GridLineDto();
            line.StartX = cellLeft + col.Width;
            line.StartY = top;
            line.EndX = cellLeft + col.Width;
            line.EndY = rowMaxY;
            boderMap.put(key, line);

            cellLeft += col.Width;
        }
        return rowMaxY;
    }

    /**
     * 绘制一个单元格数据
     *
     * @param top            顶部
     * @param left           左边
     * @param def            表格定义
     * @param col            一列定义
     * @param rowData        一行数据
     * @param metricsHandler 测量工具
     * @param retList        元素
     * @return 最大Y
     * @throws Exception
     */
    private int DrawOneCell(int top, int left, GridDto def, GridColDto col, Object rowData, DrawMetricsHandler metricsHandler, List<PrintElement> retList) throws Exception {
        Object val = JRT.Core.Util.ReflectUtil.GetObjValue(rowData, col.DataField);
        //画一行时候底部的线坐标
        int maxY = top + def.RowHeight + def.PaddingTop + def.PaddingBottom;
        //能画文本的区域宽度
        int drwAreaWidth = col.Width - def.PaddingLeft + def.PaddingRight;
        if (val != null) {
            FontMetrics metrics = metricsHandler.GetFontMetrics(col.PrintFont, col.PrintFontSize, col.PrintFontStyle);
            String valStr = val.toString();
            String nr = (char) 13 + "";
            //替换换行符号
            valStr = valStr.replace("$r$n", nr);
            //存多行绘制文本
            List<String> drawValList = new ArrayList<>();
            //宽度小于绘制宽度且不包含换行符就直接画
            if (metrics.stringWidth(valStr) < drwAreaWidth && !valStr.contains(nr)) {
                drawValList.add(valStr);
            }
            //处理换行与宽度计算
            else {
                String[] arr = null;
                //包含换行符
                if (valStr.contains(nr)) {
                    arr = valStr.split(nr);
                } else {
                    arr = new String[1];
                    arr[0] = valStr;
                }
                //测量切割字符串
                MetricCutStr(drwAreaWidth, arr, metrics, drawValList);
            }
            //绘制一个单元格每行数据
            if (drawValList.size() > 0) {
                int startY = top + def.PaddingTop;
                for (String s : drawValList) {
                    PrintElement lab = PrintDrawProtocol.DrawLabel(left + def.PaddingLeft, startY, s, col.PrintFont, Integer.valueOf(col.PrintFontSize), col.PrintFontStyle, PrintDrawProtocol.GetPrintAlignment(col.PrintAlignment), col.PrintColor, "", "");
                    retList.add(lab);
                    startY += def.RowHeight;
                }
                maxY = startY + def.PaddingBottom;
            }
        }
        return maxY;
    }

    /**
     * yyoyon允许宽度和字符测量来切割字符串
     *
     * @param drwAreaWidth 绘制宽度
     * @param cutArr       要切割的每行数据
     * @param metrics      测量工具
     * @param drawValList  绘图结果行
     */
    private void MetricCutStr(int drwAreaWidth, String[] cutArr, FontMetrics metrics, List<String> drawValList) {
        //遍历切割多行数据
        for (String one : cutArr) {

            if (one.isEmpty()) {
                drawValList.add("");
            } else {
                String cutStr = "";
                for (int i = 0; i < one.length(); i++) {
                    String c = one.substring(i, i + 1);
                    //换行
                    if (metrics.stringWidth(cutStr + c) > drwAreaWidth - 5) {
                        drawValList.add(cutStr);
                        cutStr = c;
                    } else {
                        cutStr += c;
                    }
                }
                if (!cutStr.isEmpty()) {
                    drawValList.add(cutStr);
                }
            }
        }
    }

    /**
     * 数据实体
     */
    public static class GridDataDto {
        public String Col0;
        public String Col1;
        public String Col2;
        public String Col3;
        public String Col4;
    }
}


JRT模板设计实现表格元素基本没阻碍了,稳定的表格将为业务带来简化,得益于框架越来越完善了,写逻辑也可以在业务层先测好再转移到jar包层,实现东西越来越快了,主要只能抽一些带娃间隙,不然速度嗖嗖的,哈哈

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

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

相关文章

wy的leetcode刷题记录_Day72

wy的leetcode刷题记录_Day72 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a; 前言 目录 wy的leetcode刷题记录_Day72声明前言2397. 被列覆盖的最多行数题目介绍思路代码收获 1137. 第 N 个泰波那契数题目介绍思路代码收获 2397. 被列覆…

MATLAB全局最优搜索函数:GlobalSearch函数

摘要&#xff1a;本文介绍了 GlobalSearch 函数的使用句式&#xff08;一&#xff09;、三个运行案例&#xff08;二&#xff09;、以及 GlobalSearch 函数的参数设置&#xff08;三、四&#xff09;。详细介绍如下&#xff1a; 一、函数句法 Syntax gs GlobalSearch gs Glo…

java 6种深拷贝集合方式及其性能差异对比

文章目录 ArrayList 构造方法拷贝运行1000次耗时 1ms for循环拷贝运行1000次耗时 14ms Stream流 collect实现拷贝运行1000次耗时 54ms Stream流spring的BeanUtils实现拷贝运行1000次耗时 2468 ms Hutool工具实现拷贝Hutool 5.7.13版本运行1000次耗时 64674 msHutool 5.8.24版本…

LiveGBS国标GB/T28181流媒体平台功能-国标级联中作为下级平台对接海康大华宇视华为政务公安内网等GB28181国标平台查看级联状态及会话

LiveGBS国标级联中作为下级平台对接海康大华宇视华为政务公安内网等GB28181国标平台查看级联状态及会话 1、GB/T28181级联是什么2、搭建GB28181国标流媒体平台3、获取上级平台接入信息3.1、如何提供信息给上级3.2、上级国标平台如何添加下级域3.2、接入LiveGBS示例 4、配置国标…

推荐Linux和Ubuntu系统中特别有用的几个指令

常用推荐指令 1.在Ubuntu中好多文件或文件夹是不能使用右键删除的&#xff0c;因此知道删除文件或文件夹的rm命令显得尤为重要。 &#xff08;1&#xff09;删除文件夹的内容包括文件夹: # 以最高权限删除 sudo rm -rf 文件夹的名字 #&#xff08;-r 是循环的意思&…

高精度、大电流、低压差电压调整器芯片 D2632,可以用于电池供电设备等产品上

D2632是一款高精度、大电流、低压差电压调整器。主要作为电源装置提供高效的电压调整。 最大输出电流可达3A&#xff0c;并且外接器件少&#xff0c;拥有输出电压(ADJ) 可调特点。 主要特点&#xff1a; 1. 低压差(满载350mV); 2. 地电流小; …

Python trash-cli模块实现Linux服务器回收站

概述&#xff1a; trash-cli是一个用于管理类 Unix 系统垃圾箱的命令行工具。它提供了一个安全的替代方案来代替传统的 rm 命令&#xff0c;后者会永久删除文件和目录。使用 trash-cli&#xff0c;文件和目录被移动到垃圾箱中&#xff0c;这样就可以在意外删除的情况下恢复它们…

【Nginx】在线安装与离线安装

目录 1、下载nginx news 1.2、 安装包 2、 在线安装 第一步&#xff0c;安装pcre 第二步&#xff0c;安装openssl 、zlib 、 gcc 依赖 第三步&#xff0c;安装nginx 第四步&#xff0c;关闭防火墙&#xff0c;访问nginx ​编辑 3、 离线安装 第一步 安装pcre 第二步…

android 通过反射获取U盘路径地址

2015-01-20 21:37:05.420 26674-26674/ E/MainActivity: ---getUsbPath() length2 2015-01-20 21:37:05.420 26674-26674/E/MainActivity: ---getUsbPath()[/storage/emulated/0, /storage/D65A-07AE]

电脑提示“KBDRU1.DLL文件缺失”,导致游戏和软件无法启动运行,快速修复方法

看到很多小伙伴&#xff0c;在问电脑启动某些软件或游戏的时候&#xff0c;提示“KBDRU1.DLL文件缺失&#xff0c;软件无法启动&#xff0c;请尝试重新安装&#xff0c;解决问题”&#xff0c;不知道应该怎么办&#xff1f; 首先&#xff0c;我们要先了解“KBDRU1.DLL文件”是什…

激光焊接机:塑料产品制造中的革命性优势

随着科技的飞速发展&#xff0c;激光焊接机在塑料产品制造领域的应用越来越广泛。相较于传统的焊接技术&#xff0c;激光焊接机在塑料产品制造中展现出诸多优势&#xff0c;成为现代工业生产中不可或缺的一部分。 一、精确、高效的焊接性能 激光焊接机采用高能激光束作为焊接热…

【 RF 射频 电缆】 MIL-C-17F 标准 规格

第〇、&#xff1f;&#xff1f; RGXXXXX 第一、应用场景 标准号应用场景–&#xff08;–&#xff09;RG-8 RG-9 RG-11粗缆以太网–RG-58细缆以太网–RG-59 RG-75电视系统–RG-62ARCnet网络和IBM 3270网络–RG142电信设备之间的互连 航空电子机架 雷达 GPS 医疗–RG178通信…

基于深度学习的PCB板缺陷检测系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 添加注意力机制&#xff08;SE、CBAM等&#xff09;         2. 修改可变形卷积&#xff08;DySnake-主干c…

开发知识点-Weblogic

Weblogic 介绍CVE_2018_2628poc-yaml-weblogic-ssrfpoc-yaml-weblogic-cve-2017-10271poc-yaml-weblogic-cve-2019-2725poc-yaml-weblogic-cve-2019-2729-1poc-yaml-weblogic-cve-2019-2729-2poc-yaml-weblogic-cve-2020-14750poc-yaml-weblogic-local-cve-2022-21371-file-inc…

低压线性恒流驱动芯片的产品特性与应用领域

低压线性恒流驱动芯片是一种具有多种产品特性的电子器件。 首先&#xff0c;它具有广泛的输入电压范围&#xff0c;可以适用于5V至80V的输入电压&#xff0c;使得其在不同的电源环境下都能正常工作。 低压线性恒流驱动芯片的产品特性与应用领域 其次&#xff0c;该芯片的输出…

函数——系统函数(c++)

二维数组结束&#xff0c;就到函数了。函数&#xff0c;就相当于scratch中的自制积木&#xff0c;需要自己定义其作用&#xff0c;让代码更简洁、一目了然。但是&#xff0c;与scratch不同的是&#xff0c;c中&#xff0c;系统就给出了一些函数&#xff0c;如&#xff1a;sizoe…

内存管理的概念-第四十一天

目录 前言 内存空间的分配与回收 内存空间的扩展 地址转换 存储保护 上下限寄存器 重定位寄存器和界地址寄存器 本节思维导图 前言 操作系统作为系统资源的管理者&#xff0c;当然也需要对内存进行管理&#xff0c;要管理什么呢&#xff1f; 操作系统复杂内存空间的分…

【网络】网络层IP地址和IP数据报的格式

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

1-Linux-基础

文章目录 Linux基础知识操作系统基础知识Linux基础知识Linux系统的组成Linux系统图示Linux发行版 Linux基础命令Linux系统的目录结构目录结构对比&#xff1a;windows路径描述方式 Linux命令入门Linux命令通用格式入门命令示例&#xff1a;ls 目录切换【命令】路径&#xff1a;…

使用valgrind 分析缓存命中

使用valgrind 分析缓存命中 char transpose_submit_desc[] "Transpose submission"; void transpose_submit(int M, int N, int A[N][M], int B[M][N]) { int i,j,tmp;int bsize 8;unsigned long long addrA;unsigned long long addrB;unsigned long long setin…