事情是从一张截图开始的。
我把界面放大到能数像素的程度,想看看一处文字为什么显示不全。
结果好家伙。
编码那一栏少了个右括号,按钮上的字集体往下沉,深色模式下有个勾选项直接隐身。最离谱的是一个「合」字,下面那一横没了。
不是看不清,是根本没画出来。

我当时的第一反应是,行,修一下。
修完截图。
又发现一个。
再修,再截图。
又一个。
这玩意儿有完没完?
#一、我只是想修几个字
最开始,我真没打算折腾什么大工程。
TextTool 本来就是个处理文本的小工具,能合并文件、替换标点、整理视觉小说文本就行了。界面嘛,能用就好。
谁知道「能用」和「看起来没毛病」之间,隔着一整个截图放大镜。
我把 10 月 22 日那份 Release 重新翻出来,对着两轮截图和一张放大图,列了一份问题清单。
清单越列越长。
文字被切掉,修。
深色模式下白字消失,修。
按钮文字贴着底边,修。
窗口缩窄后,右边的内容不见了,修。
「合」字少一横?修。
修到后来,我甚至开始怀疑自己到底认不认识修这个字。
我把问题分了分类,发现它们还挺会挑地方。
有些是控件太小,文字塞不下。有些是布局层层套娃,每一层都觉得自己给子控件留了余量,最后余量全被吃光了。
还有些更气人。
我明明给按钮设了背景色,它不听。
我说你给我画成深色,它说不,我就喜欢白的。
尤其是某些系统自带的按钮、页签和下拉框。你在代码里改得热火朝天,它该什么颜色还是什么颜色,主打一个「你写你的,我画我的」。
这就像你装修房子,墙漆买好了,刷子也拿上了,结果发现有几面墙属于物业管辖,你不能碰。
而且还不告诉你哪几面墙不能碰。
更麻烦的是,问题根本不只出在某一个按钮上。
电脑把文字放大了,界面布局却没跟着一起长大。原本刚好放得下的内容,一放大就开始互相挤兑,最后右边一截直接消失。
这时候你再去给某个控件加两像素宽度,效果就像发现裤子穿不上,于是拿剪刀把裤脚剪短。
能解决眼前的问题。
但你最好别问下一条裤子怎么办。
修到这里,我终于意识到,这不是几个控件不听话,而是我正在跟整套界面的脾气较劲。
我想修的是几个字,最后修成了给框架打工。
于是我做了一个非常符合当时心情的决定,不修了。
整个前端重写。
#二、换个框架,重新做人
新前端我选了 Avalonia。
名字先不管,听起来像某种高级洗发水也没关系。反正我这次的要求很简单,Windows 能用,Linux 也能用,深色模式别再跟我唱反调,文字更别动不动缺胳膊少腿。
为什么不继续用原来的方案?
因为我已经修到有点怕了。
原来的界面是 Windows 专用的。命令行版虽然能在 Linux 上工作,但如果想改个替换规则,就得打开配置文件手动编辑。
对普通用户来说,这相当于买了个电饭煲,想换口味还得先学会改固件。
我不想把一个小工具做成这样。
Avalonia 至少有几个地方比较合我心意,Windows 和 Linux 都能跑,控件的外观可以交给统一的主题处理,布局也使用设备无关的单位,不必再让文字和控件各长各的。
当然,它不是魔法。
我只是希望换一套规矩更统一的工具,少跟系统自带控件斗智斗勇。
至于其他框架,我也看过。最后没有选,不是因为它们都不行,而是放在我这个小工具上,要么平台不合适,要么迁移成本不划算。
我这次只是想做个文本工具,不是打算顺便成立一家软件公司。
新界面先搭起来再说。

看到新界面出来的时候,我还挺高兴。
熟悉的功能,新的外壳,布局终于不用继续跟旧框架纠缠。
然后我开始测试。
很好,新的坑也来了。
#三、前端重写,顺便解锁三个新坑
重写之前,我以为最麻烦的事情是把界面重新做一遍。
重写之后我才发现,界面只是门面,门后面还站着一堆等着检查你作业的东西。
#坑一,文件没读出来,程序选择了沉默
平时测试,我用的基本都是 UTF-8 文件。
这次我找了一个 GBK 编码的老文件,想看看新界面能不能正常处理。
编码栏很争气,正确显示了「GBK」。
我点执行。
没反应。
再点。
还是没反应。
程序没崩,没弹错误提示,按钮甚至正常地恢复了原样。整个过程安静得像我根本没点过。
如果软件有表情,它当时一定是一脸无辜。
最后查出来,问题居然是一行注册代码。
GBK 这类编码需要先注册相应的代码页支持。旧程序入口里有这行,新程序入口里忘了带过来。
于是,界面负责接单,底下负责报错,中间负责把错误吞掉。
用户看到的结果就是,你点了按钮,程序什么也没干。
这比直接报错还让人难受。
报错至少会告诉你哪里不对。什么都不发生,只会让你怀疑人生,是文件坏了?是按钮坏了?还是我刚才其实没点上?
补回那行代码,问题解决。
我默默把测试文件夹里的 GBK 老文件往前挪了挪。
以后它就是我的固定员工了。
#坑二,颜色明明写了,程序就是不给你看
第二个问题出现在结果提示上。
正常处理应该显示绿色,警告应该显示橙色。这些颜色我都已经放进主题里了,代码也确实去查了。
结果运行起来,字是黑的。
不是界面崩了,也不是整个主题失效了。
就是那些本该显眼的提示,全部混进了普通正文里。
你乍一看甚至觉得挺正常。毕竟黑字白底,清清爽爽,完全不像出了问题。
但你要找的那条警告,偏偏就藏在这一片黑字里。
后来发现,我查主题颜色的时候,用错了查询方式。颜色存放在按主题区分的资源里,我查询时却没指定当前主题。
结果当然是没找到。
而我的代码还贴心地准备了一个备用方案,找不到就用默认颜色。
于是它很有礼貌地告诉我,
颜色没找到?没关系,我帮你用黑色。
谢谢,真的不用。
这个坑让我最无语的地方是,它没有明显的故障表现。按钮能点,文字能看,窗口也能正常打开。
只有当你知道那里本该是橙色的时候,才会发现不对劲。
软件有时候就是这样,坏得不够彻底,反而最难查。
#坑三,翻译把数据也翻译了
第三个坑就比较丢人了。
TextTool 里有个「预设方案」,就是一组提前配好的规则,用户勾选之后就能直接使用。

检查报告发现问题时,还会推荐用户去启用某个方案。
后来我给报告加多语言支持,顺手把报告里的文字都抽出来翻译。
包括方案名。
翻完以后,报告看起来国际化了不少。
然后用户根据报告上的英文名字,跑去方案列表里找。
找不到。
因为列表里的方案名还是中文。
我当时的心情大概是,很好,我成功让软件学会了另一种语言,同时让它失去了和自己交流的能力。
这里其实是我把两种东西混在了一起。
「建议启用这个方案」是界面文案,可以翻译。
「这个方案叫什么名字」却是数据。它必须和程序里真正存在的方案保持一致,不能因为切换语言就随便改名。
就像通讯录里的联系人叫张三,你可以把「拨打电话」翻译成英文,但不能把张三也翻成 John,然后期待通讯录自动帮你找到另一个人。
更尴尬的是,继续检查后,我还发现有几条规则推荐的方案,压根就不在方案列表里。
这下好了。
有的方案是改名改丢的,有的方案从出生起就不存在。
一个是翻译问题,一个是数据问题。它们碰巧都表现为「用户找不到东西」,却得分别处理。
我把它们记下来,挨个补。
这次重写的功能数量是零。
新增的待办事项倒是挺丰富。
#四、我不敢再只靠眼睛验收了
前面这些坑,让我开始认真考虑一件事,
新界面做好了,到底怎么证明它没把旧功能弄坏?
光靠自己点一遍,肯定不行。
你点过按钮,不代表每种编码都正常。你看过界面,不代表每种语言都能显示完整。你今天点了上移按钮,不代表配置文件里的规则真的换了位置。

更何况,人眼很容易被糊弄。
一段文字大部分都显示出来了,你很可能觉得没问题。一个按钮颜色差不多,你也懒得追究。直到某个用户恰好使用另一种语言、另一种主题、另一种屏幕缩放比例,问题才突然出现。
所以这次我给自己加了一套额外的检查。
简单说,就是让程序自己给自己做作业。
第一种,截图。
不是真的打开一堆窗口,然后拿手机对着屏幕拍照,而是在不显示窗口的情况下,把界面渲染成图片。
每种语言、每种主题都跑一遍,看看有没有文字被切掉,页签有没有换行。
第二种,量尺寸。
不再只凭感觉判断「这个按钮好像有点挤」,而是检查文字需要多宽、控件实际给了多宽。
文字需要 120,控件只给 100,那就别再争辩它到底算不算被裁了。
数学不会因为你觉得界面挺好看,就多送你 20 像素。
第三种,真的按按钮。
脚本会去添加规则、删除规则、调整顺序、执行替换,然后检查磁盘上的配置文件和输出文件。
不是看按钮有没有按下去,而是看按下去之后,事情有没有真的发生。
前面那个 GBK 的问题,就是靠这种检查抓出来的。
听起来是不是挺靠谱?
然后我发现,连检查程序本身都会骗人。
有一条测试的逻辑是,只要结果行出现文字,就认为本次操作完成。
问题是,第二次运行时,结果行里还留着第一次的文字。
于是测试程序看了一眼,发现有字。
「完成!」
至于第二次处理到底有没有结束,它根本不关心。
还有一条检查只按默认数值计算文字宽度。默认值下放得下,就判定通过。用户稍微调整一下数字框里的值,文字立刻就塞不进去了。
我原本是想让程序帮我省心。
结果还得先确认这个帮手不是在糊弄我。
不过这套检查还是有用的。至少它让我知道,截图能发现问题,尺寸能验证问题,脚本能确认功能,但这些检查也得自己经过验证。
不能因为是机器算出来的,就默认它一定正确。
这句话,我这次算是花时间亲自体验了一遍。
#五、Linux 版也不是点一下就能变出来的
重写界面的时候,我还有一个目标,让 TextTool 真正拥有 Linux 桌面版。
但这里也得先交代清楚。
「能发布」和「在 Linux 上用得很舒服」,是两回事。
这次 Linux 版可以发布,也能解压运行,但我手头的实测条件有限,没有完成在真实 Linux 桌面环境里从安装到操作的完整验收。
所以有些事情,我选择老老实实留个尾巴。
比如自动更新。
Windows 版可以通过脚本等程序退出后再替换文件,Linux 版暂时没有做同样的自动更新流程。发现新版本,就提示用户自己下载。
比如中文字体。
我没把整套中文字库塞进安装包。完整字体文件体积不小,随包附带并不划算,所以界面使用系统字体,Linux 用户需要按安装说明准备中文字体。
还有 Wayland。
目前没有专门追求原生 Wayland 支持,默认采用 X11 路径,在 Wayland 会话下依赖兼容层运行。
这部分后续还得找合适的 Linux 桌面环境继续实测。
我知道,把这些事情写出来,不如一句「全面支持 Linux」听起来漂亮。
但我不想为了让项目介绍好看,就把「理论上能跑」写成「已经验证没问题」。
毕竟我刚刚才被那些看起来正常、实际上什么都没做的东西折磨过。
我可不想自己的项目介绍也加入这个行列。
#六、所以,什么时候值得直接重写?
写到这里,好像很容易得出一个结论,旧界面有问题?那就换框架!
千万别。
重写并不是万能的。尤其是一个原本能用的项目,重写前端意味着你得重新确认原来的功能、配置、交互和各种边角行为。
你以为自己只是在换门面,结果很可能连门锁都拆下来重新装了一遍。
这次我决定重写,主要是因为三个很现实的原因。
一是问题已经不只是某个按钮或者某一行代码,而是布局、缩放、主题和系统控件各有各的脾气。修一个地方,另一个地方还可能冒出同类问题。
二是我想让它跨平台。继续在旧界面上修修补补,并不能顺手解决 Linux 桌面版的问题。
三是我愿意为重写后的验收花时间。功能不增加,但旧功能必须继续工作。不能因为界面变漂亮了,就假装里面的一切也自动升级了。
当然,重写之后也没发生什么神奇的事情。
GBK 还是会出问题,颜色还是会查错,翻译还是会把数据搞丢。
框架换了,开发者本人并没有跟着升级。
但至少,这次我不用再为了一个按钮的背景色,和系统自带控件进行长达半天的心理博弈。
这已经很值得了。
最后回头看,整个过程最有意思的地方是,我最初想解决的,只是截图里几个不顺眼的细节。
结果修着修着,发现旧界面的问题比想象中复杂。决定重写之后,又发现新界面有自己的坑。等到开始验收,连验收程序都得接受验收。
软件开发就像打地鼠。你刚把这边的地鼠按下去,那边又探出一只。
区别是,这次我没有继续追着地鼠跑。
我换了张桌子。至于新桌子上还有没有地鼠?
有,但至少目前,它们比较少。
评论