本文来自依云's Blog,转载请注明。
GUI 程序我现在依然倾向于 GTK,因为虽然 Qt 拥有良好的跨平台性,但可能是太注重跨平台性了,在 Linux 平台上反而有一些水土不服的问题。
字体太多,支持太少
你可能觉得,系统上字体太少,所以经常会遇到不常见的字符无法显示的情况。然而对于 Qt 来说,字体越多,反而越容易遇到个别字符不能显示的情况。
这是我的 /etc/fonts/conf.d/66-qt.conf
中的一段。因为顺序的原因,我只能放到 /etc 下。除了针对 sans-serif 配置外,我也有同样的配置应用于 serif 和 monospace。
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 | < fontconfig > <!-- Adjust font order for Qt applications --> < alias > < family >sans-serif</ family > < prefer > <!-- 格拉哥里字母:Ⰽⱁⱀⱄⱅⰰⱀⱅⰹⱀ Ⰹⱍⰹⰳⱁⰲ --> < family >Noto Sans Glagolitic</ family > <!-- 爪哇文:꧁ ꧂ --> < family >Noto Sans Javanese</ family > <!-- 西夏文:𗷲𗒅 --> < family >Noto Serif Tangut</ family > <!-- 埃及象形文字:𓁹 --> < family >Noto Sans Egyptian Hieroglyphs</ family > <!-- 苏美尔楔形文字:𒆠𒂗𒂠 --> < family >Noto Sans Cuneiform</ family > <!-- 中日韩统一表意文字扩展 C:𫚥 --> < family >HanaMinB</ family > <!-- 拉让文:ꥃ --> < family >Noto Sans Rejang</ family > <!-- 越南傣文:ꪀꪑ --> < family >Noto Sans Tai Viet</ family > <!-- 切罗基文:ꮳꮧꮢ ᨣ --> < family >Noto Sans Cherokee</ family > <!-- 老傣仂文:ᨣ --> < family >Noto Sans Tai Tham</ family > <!-- 安纳托利亚象形文字:𔘓 --> < family >Noto Sans Anatolian Hieroglyphs</ family > <!-- 马姆穆文补充:𖤍 --> < family >Noto Sans Bamum</ family > <!-- 图标字体(PUA): --> < family >OperatorMonoSSmLig Nerd Font</ family > <!-- 巴塔克文:ᯤ --> < family >Noto Sans Batak</ family > <!-- 古北欧文:ᛋᛖᚱᚣᚨᛚᚳᚨᚾᛞᛚᛖ --> < family >Noto Sans Runic</ family > </ prefer > </ alias > </ fontconfig > |
这个配置的意思是,把这些字体的优先级提高一些。当使用 fontconfig 的程序要显示字符的时候,它会指定一个模式,匹配到一个字体列表。渲染文字的时候,就可以遍历这个列表,直到找到可以显示这个字符的字体,所以一般来说,只要系统上装了对应字符的字体,它就能显示出来。
但是 Qt 额外地需要这个配置,因为 Qt 只会检查列表中的前255项。而世界上的不同文字那么多,所以想要能够显示它们,就得有一堆字体。比如 noto-fonts 这个包里就有614个字体文件,远超 Qt 支持的数量。总有些奇奇怪怪的文字被网友用来当颜文字,或者挂在名字上彰显个性。不这么调整一下,Qt 遇到了就只能「吃豆腐」了。
空心豆腐
当一个字符显示不出来的时候,那么怎么显示好呢?一般会显示成某种方框。Pango 和火狐会将该字符的 Unicode 码点以十六进制的形式显示在方框里边,这样虽然不知道这个字符长什么样子,但至少知道它是哪个字符,也知道多块豆腐是不是同一字符,在不能复制字符本身的时候很有用。比如当它出现在求助者的截图里的时候,比如当它出现在不能复制的地方的时候。
然而 Qt 不这样做。管你什么字符,Qt 统一显示为空心方框。从视觉上完全无法知晓它到底是什么字符,要是复制不到的话,就别想弄明白你缺什么字体了。
PS: Matrix 客户端 fluffychat 的 Web 版,使用的是 Fluffy 图形界面库,即使在 Web 版,文字渲染依然完全是自己做的。不管浏览器的设置不管系统的设置,豆腐块是带叉号的方框,还不能选中,十分讨厌。
非 BMP 字符
所有使用 UTF-16 的平台(Java、JavaScript、Windows、Qt),外加 MySQL 容易遇到的一个问题:非 BMP 字符(也就是那些 U+FFFF 之后的字符)会被当作是两个字符处理。随着 emoji 的流行,大家应该都修了不少。然而,Qt 在展示非 BMP 字符的时候,你可以选中半个字符。如果不小心漏掉半个的话,复制出来的半个字符就会变成问号(还好不是 GBK 时代那样弄乱后续所有字符)。
font features
一些字体可以通过 fontconfig 设置 fontfeatures 属性来启用(或者禁用)一些特性,比如连字,带斜杠的 0,小型大写字母,居中的中文标点,等等。Pango 很早就支持了,火狐最近也支持了,但 Qt 那边依旧没啥动静。(感谢 Coelacanthus 的评论。)
3 年前
还有一个水土不服的问题是,Qt 并不完全听从 fontconfig 的设置,他会忽略 fontconfig 提供的字体 feature 设置,然后用一个 hardcode 的列表取而代之
https://github.com/qt/qtbase/blob/a1fb3971f222afa01583e41f4d8f0e037d2c7892/src/gui/text/qtextengine.cpp#L1687-L1705
这导致我必须专门为其编译一个字体而不是使用 OpenType feature 切换字形等功能
而这个功能,Pango 早在九年前就已经实现,前段时间我参考原有代码给火狐写了一个,然后转过头来想给 Qt 也写一个的时候,看到这个 hardcode 的列表真的是哭笑不得
https://bugreports.qt.io/browse/QTBUG-78645
3 年前
哦对,我是记得好像漏掉了一个群友最近告诉我的问题。我自己不用这个所以搞忘了。
3 年前
GTK 感觉走一条相反的道路。
GTK4 移除了好多抹除跨平台差异的 API,如果一件事情无法用平台通用的方法实现,他们就放弃它,这对开发者来说很难受。
3 年前
呃,能具体说说吗?
「如果一件事情无法用平台通用的方法实现,他们就放弃它」——这听着很 Qt / Java 啊。
3 年前
比如说这个: https://stackoverflow.com/questions/62614703/how-to-make-window-centered-in-gtk4
3 年前
这就很 Java 了 QAQ
flameshot 不支持选窗口截图也是这种理由唉。
3 年前
最近又发现了另一个问题,Qt 在加载可变字体时默认的 Regular 字重似乎是按字体最细渲染的
3 年前
啊咧,我好像没遇到过。有复现的例子吗?
8 个月前
Qt 似乎在字体匹配的时候把匹配到的第一个字体重新匹配一遍()导致如果把一个等宽的中文字体放到sans的第一个之后英文字体也变成等宽的()
4 个月前
telegram linux版有空白方块问题,为什么kde没有这个问题?
4 个月前
都会有的吧。Telegram 应该是更经常出现那些少见的字符。
3 个月前
当年研究字体设置,废了老大劲写了个CJK的font-family css,结果到fontconfig一看,人都傻了,这也太难写了。