给json数组中的元素排序

从其它平台迁移而来 起因 基本信息 平台:windows IDE:Lazarus 2.2.6 json包:FPC自带的fpjson 背景 最近在搞一个小工具,数据文件采用的是json格式,其中一个节点存放的是一组文件的基本信息的清单,这个节点自然就是个json数组,元素就是每个文件基本信息的json对象。界面展示用的是经典的DBGrid + DataSource + DataSet方案,所以会把json数组转为DataSet。 操作过程中会比对磁盘上的文件,该添的添,该删的的删,该改的改,该标记的标记。一番操作下来,顺序自然是乱的,虽然可以操作DataSet或者换用带排序功能的DBGridEh达到排序的目的,但直接看json数据的话,依然是乱序的。因此,期望直接对json数组进行排序。 解决过程 习惯先看源码,如果没有原生解决方案了,或者原生解决方案太别扭了,才会选择第三方解决方案或自己造轮子。 一看源码 1 2 3 4 TJSONArray = class(TJSONData) public ... Procedure Sort(Compare: TListSortCompare); TJSONArray已经提供了排序方法,不过这个参数是什么东西? 1 TListSortCompare = function (Item1, Item2: Pointer): Integer; 嗯,是个函数声明,也就是说具体的算法实现要自己写,可以先找找看有默认的实现没。结果是:没有!那就自己写吧。 看声明,这个函数是要比较两个指针指向的东西,并返回一个整数。嗯,看上去很简单,不过: 到底是怎么实现排序的? 参数是指针,指向的又是什么东西? 返回一个什么样的整数才能实现排序呢? 没懂!!! 还是接着看源码吧: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 procedure TJSONArray....

2023-11-28 21:38:45 · 3 分钟 · 慢步道人

给类型、记录、类添加助手

从其它平台迁移而来 通常情况下,类型和记录是没有方法的,只有类有方法,但是可以通过给类型和记录添加助手来达到类似于类的方法的功能,当然,也可以给类添加助手。 语法 1 2 3 HelperName = class|record|type helper[(OptionalBaseHelper)] for TypeName [properties, procedures, functions, constructors, consts, vars] end [hint modifiers]; 类助手 FPC 2.6+版本可用,ObjFPC模式下无需特别设置。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //定义 TObjectHelper = class helper for TObject function SomeFunc: string; end; //实现 function TObjectHelper.SomeFunc: string; begin Result := '类名:' + Self.ClassName; end; //使用 var o: TObject; begin Writeln(o.SomeFunc); end. 一般情况下,给类添加方法可直接在类中添加,但这样添加的方法会直接在所有后代类中显示,如果只是想在特定的范围内添加方法,就可以使用类助手。...

2023-08-25 20:38:35 · 1 分钟 · 慢步道人

使用Lazarus压缩/解压zip

从其它平台迁移而来 Lazarus默认已经提供了zip文件的压缩和解压功能,在Zipper单元中,不过,使用过程中还是有一些细节需要注意。 压缩 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 uses Zipper; { 使用类方法进行压缩 } //压缩单个文件 TZipper.Zip('压缩后的文件.zip', '待压缩的文件.txt'); //压缩多个文件 TZipper.Zip('压缩后的文件.zip', ['待压缩的文件1.txt', '待压缩的文件2.pdf']); { 使用实例对象进行压缩 } var zip: TZipper; zip := TZipper.Create; try //压缩单个文件 zip.ZipFile('压缩后的文件.zip', '待压缩的文件.txt'); //压缩多个文件 zip.ZipFiles('压缩后的文件.zip', ['待压缩的文件1.txt', '待压缩的文件2.pdf']); finally zip.Free; end; 以上为比较方便的使用方法,但是还存在一些问题: 以上仅限于文件名为英文的情况,若文件名为中文则会出现乱码(主要是在windows平台上,用专门的压缩/解压工具打开查看列表和解压时)。查看解决方案。 若待压缩的文件包括路径,则压缩后的文件内也会包含传参时传入的路径。查看解决方案。 另外,也可以配合FileName(压缩后的文件名)和Entries(待压缩的文件)属性使用ZipAllFiles方法;或者配合Entries(待压缩的文件)属性使用SaveToFile方法。不过,多次调用前一定要调用Clear方法,否则就会受前一次压缩操作的影响。 解压 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 uses Zipper; { 使用类方法进行解压 } //解压出全部文件 TUnZipper....

2023-07-29 21:31:15 · 1 分钟 · 慢步道人

在Lazarus中使用代码模板

从其它平台迁移而来 在Delphi中,可以使用CnPack中代码助手的功能,实现快速编写基础代码,专注于写具体业务、逻辑代码。在Lazarus中,也可以使用代码模板功能,实现相同的需求。 使用方法 将光标移到需要录入代码的位置 按Ctrl+J快捷键,弹出代码模板列表 选择要使用的模板,Enter回车 若模板需要填写参数,可在代码模板插入后,按Tab键在各参数间切换并修改,最后按Esc键或将光标移到其它位置 在模板生成的代码的基础上继续编写代码 注意: 可以先输入部分/完整代码模板的Token,然后再按快捷键;也可以按过快捷键后,继续输入Token剩余部分进一步过滤;当然,也可以组合使用。 先输入Token再按快捷键时,若可唯一确定模板,则会直接应用而不弹出模板列表。 自定义模板 Lazarus默认了一批模板,可以在菜单Tools->Code Templates ...中进行查看。 若感觉默认模板不合适,可自行修改;若默认模板无法满足使用,也可自行添加。 简要说明 Module:当前使用的代码模板,默认是主配置目录下的lazarus.dci,可点右侧按钮选用其它模板。 Templates:所选代码模板的具体清单,格式为:Token - "说明"。右侧三个按钮用于对模板清单进行维护。 其余部分:所选模板项的详细信息。 最下方的编辑区:代码模板的具体内容,$开头的表示使用的宏代码,|表示模板插入后光标的位置。 Keep indentation:保持代码模板内容的缩进,勾选后代码模板首行在光标处插入,除首行外的缩进量保持原样插入(类似行模式插入);否则模板首行外的内容与首行保持相对缩进(类似列模式插入)。 Enable Macros:启用宏代码,点Insert Macro可插入预定义的宏。 Auto complate on:自动完成,类似于事件触发,即满足条件后无需按Ctrl+J快捷键直接应用模板。 line break:按回车键时触发 space:按空格键时触发 tab:按Tab键时触发 word end:输入结束字符时触发,可暂时理解为输入;时触发 do not complate selection:暂时还不清楚具体效果 do not add character:可与前四种结合使用,勾选后不会把用来触发的字符插入到代码中,否则会插入用来触发的字符

2023-05-27 21:12:44 · 1 分钟 · 慢步道人

ctypes里的bug?

从其它平台迁移而来 起因 以前使用Delphi调用海康SDK时,专门改写过HCNetSDK.h,当时大部分桌面应用还都是32位的,毕竟64位还没彻底普及开(即便现在,还是有一部分桌面考虑兼容性依然是32位)。后来也搞过64位版的,编译没问题,运行就不成功。虽然没成功,但心里还是清楚这基本上是数据类型的问题,由于对64位了解不多,也就一直搁置着。 转Lazarus之后,又搞过一次64位版,还是没成功。后来知道有ctypes这个单元,也知道这是专门针对c语言数据类型的,但一直没去看过。近来又想起这个事,就想一探究竟。 探 直接看源码,其实就是给pascal的数据类型取了个c的别名。要想了解透彻,自已撸码跑一下还是很有必要的: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 program test; uses SysUtils, ctypes; begin writeln(Format('%-16s%s', ['type', 'size'])); writeln('--------------------'); writeln(Format('%-16s%d', ['cint8', SizeOf(cint8)])); writeln(Format('%-16s%d', ['cuint8', SizeOf(cuint8)])); writeln(Format('%-16s%d', ['cchar', SizeOf(cchar)])); writeln(Format('%-16s%d', ['cschar', SizeOf(cschar)])); writeln(Format('%-16s%d', ['cuchar', SizeOf(cuchar)])); writeln(Format('%-16s%d', ['cint16', SizeOf(cint16)])); writeln(Format('%-16s%d', ['cuint16', SizeOf(cuint16)])); writeln(Format('%-16s%d', ['cshort', SizeOf(cshort)])); writeln(Format('%-16s%d', ['csshort', SizeOf(csshort)])); writeln(Format('%-16s%d', ['cushort', SizeOf(cushort)])); writeln(Format('%-16s%d', ['cint32', SizeOf(cint32)])); writeln(Format('%-16s%d', ['cuint32', SizeOf(cuint32)])); writeln(Format('%-16s%d', ['cint64', SizeOf(cint64)])); writeln(Format('%-16s%d', ['cuint64', SizeOf(cuint64)])); writeln(Format('%-16s%d', ['clonglong', SizeOf(clonglong)])); writeln(Format('%-16s%d', ['cslonglong', SizeOf(cslonglong)])); writeln(Format('%-16s%d', ['culonglong', SizeOf(culonglong)])); writeln(Format('%-16s%d', ['cbool', SizeOf(cbool)])); writeln(Format('%-16s%d', ['cint', SizeOf(cint)])); writeln(Format('%-16s%d', ['csint', SizeOf(csint)])); writeln(Format('%-16s%d', ['cuint', SizeOf(cuint)])); writeln(Format('%-16s%d', ['clong', SizeOf(clong)])); writeln(Format('%-16s%d', ['cslong', SizeOf(cslong)])); writeln(Format('%-16s%d', ['culong', SizeOf(culong)])); writeln(Format('%-16s%d', ['csigned', SizeOf(csigned)])); writeln(Format('%-16s%d', ['cunsigned', SizeOf(cunsigned)])); writeln(Format('%-16s%d', ['csize_t', SizeOf(csize_t)])); writeln(Format('%-16s%d', ['cfloat', SizeOf(cfloat)])); writeln(Format('%-16s%d', ['cdouble', SizeOf(cdouble)])); writeln(Format('%-16s%d', ['clongdouble', SizeOf(clongdouble)])); Readln(); end....

2023-04-24 21:20:06 · 4 分钟 · 慢步道人

Lazarus发布v2.2.6版本

从其它平台迁移而来 2023-03-09,Lazarus 团队宣布发布 Lazarus 2.2.6 版本,这是一个错误修复版本,使用 FPC 3.2.2 构建。 大概在Lazarus 2.2.6发布的第二天吧,就把自己电脑上的Lazarus升级到最新了,一直以来都是这个习惯,基本上从来没怎么关心过具体都更新了哪些内容。 不过,这次心血来潮,把发行日志给大致看了下,看了之后还是有点小收获的,在此记录一二。 版本号 Lazarus是IDE,最终完成编译的是FPC,两者的版本号管理策略和Linux内核的策略类似。以下为笔者总结,实际的版本号管理策略未考证。 版本号格式如下: 1 [主版本号].[次版本号].[修订版本号] 其中,次版本号和修订版本号,奇数为开发版,偶数为稳定版。 发行日志 Lazarus 2.2.x发行日志原文。可以看到,这是2.2.0的发行日志,并非2.2.6的发行日志,说明这是按次版本号统一整理的。 由于内容较多,而且部分内容笔者也没接触/使用过,所以,只拣熟悉的或感觉比较重要的拿出来分享一下。 LazUtils包 移除PasWStr单元 原因:只有当编译器版本低于3.0才包含代码。 补救:不要再使用PasWStr LCL包 TValueListEditor 旧行为:允许在键列中使用当前的NameValueSeparator(默认情况下:=)。 新行为:不能在键列中使用名称值分隔符。如果在键列中键入名称值分隔符,焦点将移动到值列。如果将其粘贴到列中,它将被删除(没有任何反馈或警告)。 Screen添加了三组新方法 BeginTempCursor / EndTempCursor、BeginWaitCursor / EndWaitCursor和BeginScreenCursor / EndScreenCursor用于临时光标更改,而不是直接设置Screen.Cursor属性。 TGroupBox,TRadioGroup,TCheckGroup Win32旧行为:可以设置属性颜色,它直接显示。 Win32新行为:如果要更改颜色,则必须设置ParentBackground := False; TFrame Win32旧行为:无法更改TFrame的颜色。 Win32新行为:如果要更改颜色,则必须设置ParentBackground := False; T(Float)SpinEdit 新增了EditorEnabled属性,以禁用编辑中的直接用户输入。如果设置为False,则用户只能使用微调器或箭头键更改值。 Debugger LazDebugger-FP (FpDebug) v1.0成为Windows和Linux默认的调试器。 GDB(mo)使用修改版的GDB 9.2 笔者补充:FpDebug无法调试dll,需要使用GDB 组件 OpenGL全面支持Qt5的widgetset。 TSpinEditEx 新属性ThousandSeparator允许显示插入了千位分隔符的值。 TFloatSpinEditEx 支持以科学计数法形式的文本进行录入。 新属性DisplayMode,用于控制是否使用科学记数法。 新属性property控制以科学记数法显示值时使用的精度。 还有其它许多更改,详细请看原文。

2023-04-06 20:43:52 · 1 分钟 · 慢步道人

Lazarus开发环境配置

从其它平台迁移而来 前言 做为一个桌面应用开发者,工作中一直使用的是Delphi(是语言,也是IDE,基于pascal语言),无论是经典的D7,还是现下最新的XE,都有着还算丰富的使用经验吧,虽然这两者都各有优缺点。做为团队开发成员之一,具体使用什么,几乎是没什么选择权的,毕竟公司有自己的技术栈,当然还有相应的技术债。 但是,做为一个个人开发者,还是比较喜欢严谨的pascal语言的(其实Go的一些语法就是借鉴pascal的,比如:类型在变量右侧),而且还有着那么多年的开发经验,理论上来说,写个小工具啊什么的,还是应该选择熟悉的Delphi才是,但是Delphi并不符合个人的选择条件: 不要太重量级 有当前比较流行的特性 有相对活跃的社区 D7以现在的眼光来看,绝对算是足够轻量级的,整个环境(不含三方组件)安装完还不到1G,但是是毕竟是二十年前的东西了,不说新特性,一些陈年bug就够喝一壶了。 相对来说,XE却是一直在更新着,新特性是有了,但是仅安装包就7~9G,只安装桌面开发必须的自带组件,安装完也有15G+,而且正版授权巨贵,社区版限制又巨多。 至于有相对活跃的社区这条,国外应该还行,但对英文渣渣来说还是有点难了;而国内,Delphi都是快绝迹的语言了,当我什么都没说吧。 所以,选来选去,也就只剩开源的Lazarus和CodeTyphon(基于Lazarus)了。原本是看中了CodeTyphon的,但是死活在Bug10上安装不成功,也就只能选Lazarus了,不过Lazarus倒也是越用越顺心了。 虽说Lazarus标榜的一次编写,到处编译,不过,实际用到的几乎都是windows平台,至于其它平台,有机会再说吧。 开发环境 以下以Lazarus 2.2.4为例。 安装IDE Lazarus有32位版本和64位版本,而且都互相有对方架构的插件包,个人尝试后还是觉得分别安装两个版本比较合适(不要质疑,真的可以同时安装多个版本,不同架构、不同版本号都可以)。 由于Bug10不愧是Bug10,所以个人还是喜欢整成免安装版本,万一哪天Bug10作妖,就不怕重新折腾了。 在非系统盘下手动创建目录,比如D:\lazarus和D:\lazarus\config,前者是IDE的安装目录,后者是IDE的配置目录 下载并运行安装包 在选择目标位置这一步时,选择之前手动创建的安装目录,同时勾选创建一个新的第二的安装(不要质疑,哪怕是第一次安装),下一步 到选择配置文件夹这一步,选择之前手动创建的配置目录,然后一路下一步 安装完之后,把安装目录备份一下,再把IDE卸载了,然后把安装目录恢复了(当然,这一步也可以不做) 运行lazarus.exe,首次运行时(包括未来重装系统后)会弹出Welcom to Lazarus IDE的窗口,其中Fppkg项会有叹号(似乎是2.2版本之后才有的),点Restore Fppkg configuration,再点Write new configuration files,最后点Start IDE 可以为lazarus.exe创建快捷方式 至此,IDE就算是安装完了,需要的话可以把安装目录整个压缩备份,不过个人还是建议把IDE配置好了再备份 IDE配置 构建配置 由于Lazarus每次安装三方组件都要重新build,如果三方组件装得多了,IDE的exe会很大(不是你自己写的exe),而个人又是比较喜欢小巧的,所以这一步是少不了的。 菜单Tools->Configure "Build Lazarus" Profile to build项选择Optimized IDE 点Build会立即重新构建IDE;点Save Settings仅保存配置,下次构建时生效 一体式窗口 安装完之后,IDE默认是D7那种分离式窗口,在小分辨率屏幕的时代很有用,不过现在嘛,个人感觉还是一体式窗口比较舒服。Lazarus已经提供了这样的包,只不过默认并没有启用。 菜单Package->Install/Uninstall Packages ... 右侧选择AnchorDockingDsgn 1.0,点Install selection或双击 点Save and rebuild IDE重新构建,IDE重启之后就是一体式的窗口了 拖动子窗口的标题,会自动吸附,调整为自己喜欢的布局,重启IDE即可 此时,若是不小心把布局调乱了,就不好恢复了,所以可以考虑把自动保存布局功能给关了: 菜单Tools->Desktops ...,去掉Auto save active desktop的勾,关闭 其它配置 菜单Tools->Options ...是IDE集中的配置,可依自己习惯或喜好进行配置。不过,倒是可以分享些个人的配置及相应的考虑,以供参考:...

2023-02-25 23:52:38 · 1 分钟 · 慢步道人

FPHTTPClient请求https

从其它平台迁移而来 在客户端不需要证书的情况下,简单两步操作即可让TFPHTTPClient实现https的请求: 在源码中引用opensslsockets单元 在生成目录下加入动态库libcrypto-1_1.dll和libssl-1_1.dll

2023-02-17 20:59:53 · 1 分钟 · 慢步道人

Lazarus连数据库的那点坑

从其它平台迁移而来 环境 Lazarus v2.2.4(32位/64位) MySQL 8.0.31 64位 PostgreSQL 15.1 64位 坑 MySQL Lazarus v2.2.4已内置MySQL8.0的TMySQL80Connection组件,但是连接时却提示Can not load MySQL library "libmysql.dll". Please check your installation.使用64位编译,放进64位MySQL8.0.31的libmysql.dll仍然报该错,一直到把版本降到5.7系列才正常,换32位编译,同样的结果:使用5.7系列的libmysql.dll可正常使用。 PostgreSQL 连接PostgreSQL时,同样遇到与MySQL类似的报错:Can not load PostgreSQL client library "libpq.dll". Check your installation.按照与MySQL相同的思路,版本从15.1一直降到目前支持的最低版本9.2.24,仍然报错! 查一下官方论坛,各种方式试了一通,发现64位的程序除libpq.dll外,v11+还需要libcrypto-3-x64.dll、libiconv-2.dll、libintl-9.dll、libssl-3-x64.dll和libwinpthread-1.dll;v9.4~v10.23还需要libcrypto-1_1-x64.dll、libiconv-2.dll、libintl-8.dll、libssl-1_1-x64.dll。 而32位程序,最高可用版本为v10.23,除libpq.dll外,还需要libcrypto-1_1.dll、libiconv-2.dll、libintl-8.dll、libssl-1_1.dll,必要时可能还需要VC运行时。

2022-12-24 22:03:38 · 1 分钟 · 慢步道人

Lazarus的dll卸载问题

从其它平台迁移而来 事件 计划做一个插件式的桌面应用框架,一方面练练手,另一方面算是自身的技术积累吧。 在练手过程中,发现一个巨难受的问题,dll卸载不掉,程序直接假死! 虽然可以不直接调用卸载,依赖主程序退出时卸载的特性,但做为插件式应用,必须能在运行中加载/卸载才算完整。即便不是插件式应用,dll的正常卸载也应该是很常用的功能,现在不正常,那么一定是代码写得有问题。 写了测试Demo,一行一行加代码,结果都能正常卸载,这就杯具了……测试了无数次,直到想把每一步都输出到日志时,dll无法卸载了。一点点分析源码后,发现很可能是日志中为了方便使用,加的initialization节和finalization节导致的,注释掉之后就真的正常了。 分析 initialization节应该是在Application.Initialize;时执行的,finalization节应该是在Application.Terminate;之后的某个时间点执行的(具体执行时机没深入研究过)。而我的dll是要做成插件的,不可避免会有可视化窗体,所以Application.Initialize;不可避免(Lazarus是这样,Delphi不是),而在initialization节中创建了日志记录器实例,在finalization节中进行释放,这样,在卸载dll时就出现了锁死的情况:卸载时有内存(实例)未释放,需要等内存释放了才能完全卸载,而未卸载又导致执行不到finalization节,就不能释放实例……于是,dll无法卸载,程序就进入假死状态。 以上只是初步分析,鉴于对底层机制了解不深,可能分析不完全正确,甚至是错误的。 结论 在编写的dll中不要在initialization节和finalization节中进行内存管理的工作。 对于无对象、纯函数式的dll,initialization节和finalization节会不会产生影响尚未测试,目前也暂无这方面需求,待以后遇到了再详细测试吧。

2022-12-10 22:26:44 · 1 分钟 · 慢步道人