嵌入式 QT开发汉字显示问题tr函数

Qt tr 函数详解
本文详细解析了 Qt 中 tr 函数的工作原理及其与 translate 函数的关系。探讨了 tr 在国际化中的应用,特别是在处理中文字符串时的注意事项。

在论坛中漂,经常遇到有人遇到tr相关的问题。用tr的有两类人:

  • (1)因为发现中文老出问题,然后搜索,发现很多人用tr,于是他也开始用tr
  • (2)另一类人,确实是出于国际化的需要,将需要在界面上显示的文件都用tr包起来,这有分两种:
    • (2a) 用tr包住英文(最最推荐的用法,源码英文,然后提供英文到其他语言的翻译包)
    • (2b) 用tr包住中文(源码用中文,然后提供中文到其他语言的翻译包)

注意哦,如果你正在用tr包裹中文字符,却不属于(2b),那么,这是个信号:

  • 你在误用tr
  • 你需要的是QString,而不是tr

如果你确实属于(2b),请做好心理准备,你可能还会遇到很多困难,请考虑Qt国际化(源码含中文时)的点滴分析

tr 是做什么的?下面二者的区别是什么?

QString text1 = QObject::tr("hello"); QString text2 = QString("hello");

tr是用来实现国际化,如果你为这个程序提供了中文翻译包(其中hello被翻译成中文"你好"),那么text1的内容将是中文"你好";如果你为程序提供且使用日文翻译包,那么text1的内容将是日文。

tr是经过多级函数调用才实现了翻译操作,是有代价的,所以不该用的时候最好不要用。

关注的对象

本文关注的是tr或translate中包含中文字符串的情况:

  • QObject::tr()

  • QCoreApplication::translate()

  • QTextCodec::setCodecForTr

这个问题本多少可说的。因为涉及到的编码问题和QString与中文问题中是完全一样的,只不过一个是用的setCodecForCStrings一个用的是setCodecForTr。

简单回顾QString的中文问题

  • QString 采用的unicode,在中文支持上不存在任何问题
  • "我是中文" 这是传统的 const char * 的窄字符串

  • 当将窄字符串赋值到QString时,我们需要告诉它我们的窄串采用的何种编码(gbk?、utf-8?)
  • 究竟何种编码主要取决于我们的源代码文件的编码(windows上一般是gbk,其他平台一般utf-8)

例子:

QString s1 "我是中文"; QString s2("我是中文"); QString s3; s3 "我是中文"
  • s1、s2用的是QString的构造函数QString const char str )

  • s3用的是QString的赋值操作符 QString operator= const char str)

如果不指定编码,s1,s2,s3将全部都是(国内大多数人所称的)乱码。因为QString将这些const char *按照latin1来解释的,而不是用户期待的gbk或utf8。

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"))

这两条语句中的一条可以解决问题,至于如何选择,此处不再重复。

QObject::tr

说实话,在tr中使用中文不是个好主意。不过既然总有人用(无论是(1)还是(2b)),而且总有人遇到问题,所以还是简单整理一下吧。

相比QCoreApplication::translate,大家用tr应该用的很多了,尽管不少人不清楚tr究竟是做什么的^_^

 

 

tr("我是中文");

这调用的是下面这个函数(至少我们可这么认为是)。

QString QObject::tr ( const char * sourceText, const char * disambiguation = 0, int n = -1 )

与QString("我是中文")完全一样,你必须告诉tr这个窄字符串是何种编码?你不告诉它,它就用latin1。于是所谓的乱码问题就出来了。

如何告诉tr你写的这几个汉字在磁盘中保存的是何种编码呢?这正是

QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312")); QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));

所做的。这两个选择的原则,由于和前文完全一样,此处也不再重复。

如果你的编码采用的utf8,可以直接使用trUtf8而不必设置setCodecForTr。

如果你只关心乱码问题,到此为止就可以了(下面不再关注编码)。如果想对tr进一步了解,不妨。。继续。。

 

QCoreApplication::translate

我们知道tr是用于实现程序的国际化(或者说多语言翻译),看Qt相关资料的话,我们知道实现该功能的还有下面这个函数:

QString QCoreApplication::translate ( const char * context, const char * sourceText, const char * disambiguation, Encoding encoding, int n )

其实,这个才是真正进行翻译操作的函数,前面我们提到的tr最终是通过调用该函数来实现翻译功能的(稍后我们会看tr是如何调用translate的)。

对tr和这个函数,manual中都有比较详尽的解释。我们这儿简单看一下它的这几个参数:

  • context 上下文,一般就是需要翻译的字符串所在的类的名字
  • sourceText 需要翻译的字符串。(我们关注的编码其实就是它的编码)
  • disambiguation消除歧义用的。(比如我们的类内出现两处"close",一处含义是关闭,另一处含义是亲密的。显然需要让翻译人员知道这点区别)
  • encoding 指定编码。它有两个值
    • CodecForTr 使用setCodecForTr()设置的编码来解释sourceText

    • UnicodeUTF8 使用utf8编码来解释 sourceText
    • 其实这两个分别对应tr和trUtf8
  • n 处理单复数(对中文来说,不存在这个问题)

tr与translate

这两个函数的说明,一个在QObject的manual,另一个在QCoreApplication的manual中。

介绍一下tr与translate的关系。前面提到了,tr调用的是translate。如果仅仅这样一说,没有证据,还真难以让大家相信。好吧,继续

tr 在何处定义

你可能说:这不废话吗,manual中写得明白的,它是QObject的静态成员函数。而且还有源码为证:

//来自 src/corelib/kernel/qobject.h #ifdef qdoc static QString tr(const char *sourceText,const char *comment 0, int = -1); static QString trUtf8(const char *sourceText, constchar *comment 0, int = -1); #endif

嘿嘿,差点就被骗了,发现没:它们被预处理语句包住了。

这说明了什么呢?说明了这段代码仅仅是用来生成Qt那漂亮的文档的(qdoc3从代码中抽取信息,生成一系列的html格式的manual)。

啊,也就是说,这是假的。那么真正的定义呢??在一个大家都很熟悉的地方,猜猜看?

这就是

Q_OBJECT

该宏的定义在src/corelib/kernel/qobjectdefs.h中

#define Q_OBJECT \  public: \  Q_OBJECT_CHECK \  static const QMetaObject staticMetaObject; \  Q_OBJECT_GETSTATICMETAOBJECT \  virtual const QMetaObject *metaObject() const; \  virtual void *qt_metacast(const char *); \  QT_TR_FUNCTIONS \  virtual int qt_metacall(QMetaObject::Call, int, void **); \  private:

其中的宏QT_TR_FUNCTIONS

define QT_TR_FUNCTIONS \  static inline QString tr(const char *s, const char *c = 0) \  { return staticMetaObject.tr(s, c); } \  static inline QString trUtf8(const char *s, const char *c = 0) \  { return staticMetaObject.trUtf8(s, c); } \  static inline QString tr(const char *s, const char *c, int n) \  { return staticMetaObject.tr(s, c, n); } \  static inline QString trUtf8(const char *s, const char *c, int n) \  { return staticMetaObject.trUtf8(s, c, n); }

现在看到:tr调用的是 staticMetaObject对象的tr函数,staticMetaObject 的定义在moc生成的xxx.moc 或 moc_xxx.cpp 文件内(你随时可以验证的)。

staticMetaObject 是一个 QMetaObject 类的实例,我们继续看一下该类的源码:

  QString QMetaObject::tr(const char *s, const char *c) const  {  returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr);    QString QMetaObject::trUtf8(const char *s, const char *c) const { returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8);

}

<think>嗯,用户想了解如何使用Qt进行嵌入式上位机开发,需要教程或解决方案。首先,我得回忆一下Qt嵌入式开发中的应用场景和相关知识。根据引用[1],Qt上位机开发涉及到环境搭建、界面设计、功能扩展以及注意事项,比如硬件资源限制和操作系统兼容性。还有引用[2]提到Qt是跨平台的框架,适合图形界面开发,这对嵌入式系统应该很重要。 用户可能已经知道Qt的基础,但作为新手,可能需要从环境搭建开始。嵌入式开发可能需要特定的工具链,比如交叉编译环境。此外,Qt Creator的安装和配置是关键步骤,需要确保目标设备的兼容性。比如,是否需要安装特定版本的Qt库或者模块? 然后是界面设计部分。Qt的信号和槽机制是核心,用户可能需要示例代码来理解如何连接界面元素和后台逻辑。比如串口通信,引用[1]里提到了自动获取串口号和发送接收数据,这部分可能需要用到Qt的SerialPort模块。需要确认用户是否了解QSerialPort类的使用,或者是否需要提供相关代码示例。 功能扩展方面,用户可能需要知道如何处理硬件资源限制,比如内存优化或功耗管理。引用[1]提到性能优化和安全性,这些都是开发中需要注意的点。此外,嵌入式设备可能有不同的显示需求,比如触摸屏适配,这涉及到界面布局和响应式设计。 用户的问题可能还涉及到实际开发中的难点,比如信号槽的正确使用、串口初始化的复杂性。需要解释这些挑战并提供解决建议,比如调试技巧或常见错误处理。引用[3]和[4]提到开发过程中的困难和可能需要的前端知识,但Qt相比Electron可能更适合嵌入式,因为Qt本身就是为跨平台设计的,不需要依赖Web技术。 最后,应该推荐学习资源,比如官方文档、书籍和社区论坛,帮助用户继续深入学习。同时,应用实例的参考项目能提供实践机会,巩固知识。可能用户需要知道未来趋势,比如与AI结合或跨平台需求,引用[1]里的展望部分可以作为补充信息。 总结下来,回答的结构应该是分步骤的教程,涵盖环境搭建、界面设计、功能实现、注意事项和资源推荐,同时解答常见问题和难点,确保用户能系统地进行学习。</think>### Qt嵌入式上位机开发解决方案 #### 一、开发环境搭建 1. **安装Qt Creator** - 下载Qt官方维护的嵌入式版本(如Qt for Embedded Linux)并安装,需注意选择与目标设备匹配的工具链[^1][^2] - 示例安装命令: ```bash sudo apt-get install qt5-default qtcreator ``` 2. **交叉编译配置** - 创建针对ARM架构的编译工具链(如使用Yocto或Buildroot) - 在Qt Creator中配置设备连接(SSH或串口协议)[^1] #### 二、基础框架设计 ```cpp // 主窗口类定义示例 class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); private: QSerialPort *serial; // 串口对象 QLabel *statusLabel; // 状态显示 void initSerialPort();// 串口初始化 }; ``` #### 三、核心功能实现 1. **串口通信模块** ```cpp // 自动扫描可用串口 QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts(); foreach (const QSerialPortInfo &info, ports) { ui->comboBox->addItem(info.portName()); } // 数据接收槽函数 connect(serial, &QSerialPort::readyRead, [=](){ QByteArray data = serial->readAll(); statusLabel->setText("接收数据:" + data.toHex()); }); ``` 2. **界面布局优化** - 使用`QGridLayout`实现自适应布局 - 添加`QSS`样式表增强视觉效果: ```css QPushButton { background-color: #4CAF50; border-radius: 5px; padding: 8px 16px; } ``` #### 四、关键注意事项 1. **硬件资源管理** - 通过`QElapsedTimer`监控代码执行时间 - 使用`QPixmap::cacheLimit()`控制图像缓存 2. **跨平台兼容性** - 条件编译处理平台差异: ```cpp #ifdef Q_OS_LINUX // Linux特定代码 #elif defined(Q_OS_WIN) // Windows特定代码 #endif ``` #### 五、进阶开发技巧 1. **自定义控件开发** ```cpp class GaugeWidget : public QWidget { Q_OBJECT public: explicit GaugeWidget(QWidget *parent = nullptr); void setValue(int value); protected: void paintEvent(QPaintEvent *event) override; }; ``` 2. **多语言支持** - 使用`tr()`标记可翻译字符串 - 生成.ts翻译文件并部署 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值