在使用Qt5.8完成程序动态语言切换时遇到的问题

时间:2022-03-19 07:18:38

因为之前了解过一些Qt国际化的东西,所以在写程序的时候需要显示给用户的字符都使用了 tr(" ")的形式,然后使用 Qt Linguist得到相应的 qm(Qt message)文件,再通过网上介绍的方式,在 main函数中使用 installTranslator,即可让程序在启动时自动判断语言环境,加载相应语言。

至此,静态语言切换已经完成,下面要做的是动态切换(即不需要重启软件)。

1.首先,令语言能够切换的 GUI组件用的是 QComboBox,信号是 currentIndexChanged,在于这个信号对应的槽中加载不同的语言文件,安装 translator,并且调用主界面的retranslateUI函数。这样,每当下拉框的选中项发生改变时,语言就会立即切换,而不是像大多数软件一样需要再次点击“确定”后才会切换。但是这么做出现了问题,因为如果是使用 Qt Designer生成的界面,在自动生成的 retranslateUI程序(ui_**.h文件)中,会先调用 QComboBox类的 clear,再调用 insertItems函数,而这两个函数都会触发 currentIndexChanged信号。这样的话,就会产生一个死循环。

2.后来改成了点击“确定”后才会切换语言,这样也不需要再使用 QComboBox类的 currentIndexChanged信号,也就避开了上面的死循环。

3.只调用  retranslateUI函数时,则只有在 Qt Designer中输入的字符能够成功翻译。后来上网看别人的 Blog后知道,自己在代码中赋值的字符需要统一放到一个函数(retranslate)中,在安装好 translator后再调用这个函数。这样来看,Qt实现国际化的原理大致是,在显示字符时,会先从当前 translator中寻找该字符的翻译文本,有的话显示“翻译文本”,没有则显示“原本字符”。所以,由于一开始写程序时用的就是英文,英文的语言文本可以不做翻译,直接由 ts文件发布为 qm文件。

4.别人的 Blog中还写到:因为当调用 installTranslator后,会向所有的类发送一个 LanguageChanged事件。如果要实时切换另一个窗口的语言,就需要在另一个窗口类中重载 changeEvent,并判断事件是否是 LanguageChanged类型,是的话调用它的 retranslateUI函数,如果有字符是在代码中给出的,还需要自定义一个 retranslate函数,然后再调用这个函数。

5.一开始在自定义的 retranslate函数中,直接使用  setText(QApplication::translate("Mainwindow", "str", 0, QApplication::UnicodeUTF8));  形式,报错。当前 Qt版本(5.8)下,则需要使用 setText(QApplication::translate("Mainwindow", "str",Q_NULLPTR)); 形式。

6.这样的话,每一个组件有两处字符串赋值的地方,不利于修改。我就想着可不可以只保留一处呢?看到 ui_**.h文件中的初始化函数中就会调用 retranslateUI函数,我就想着构造函数中就不对字符串赋值了,而都放到自定义的 retranslate函数中,在 Mainwindow的构造函数中调用 retranslate函数即可。可是这样 Qt Linguist就找不到这些需要翻译的字符了,然后在别人的代码中看到使用的是 setText(tr("---")); 形式。这样,就也能找到这些需要翻译的字符了。

7.但是出了一个很奇怪的问题,一开始是英文,英->中->英切换就没问题;一开始是中文的话,就切换不成英文。不知怎的,我就想到把程序启动时自动加载相应语言的代码改到 MainWindow的构造函数中,结果就好了。。。