Qt Jambi 4.4文档翻译:QDataStream类,Class QDataStream

- no title specified

Qt Jambi 4.4文档翻译:QDataStream类,Class QDataStream

QDataStream类提供咯将二进制数据序列化到一个QIODevice 中去的功能。一个数据流就是一个代表已编码信息的二进制流,它是与所运行的电脑的操作系统、中央处理器或者字节序完全无关的。例如,使用Windows 的PC 所生成的一个数据流可以被运行Solaris 的Sun SPARC 读取。

你也可以使用一个数据流来读写未编码的二进制数据。如果你想使用一个带有“分词”(”parsing”)功能的输入流,那么就去看看QTextStream

QDataStream类实现咯对C++的基本数据类型的序列化,例如charshortintchar *等等。对更复杂的数据的序列化是通过将数据分解成原子单位来实现的

一个数据流与QIODevice 是紧密结合的。一个QIODevice表示一个输入/输出介质,你可以从中读取数据,也可以向其中写入数据。QFile 类就是输入/输出设备的一个例子。

示例(向一个流中写入二进制数据):

QFile file = new QFile(“file.dat”);

QFile.OpenMode mode = new QFile.OpenMode();

mode.set(QFile.OpenModeFlag.WriteOnly);

file.open(mode);

QDataStream out = new QDataStream(file); //我们会将数据序列化到file中

out.writeString(“the answer is”); //序列化一个字符串

out.writeInt(42); //序列化一个整数

示例(从一个流中读取二进制数据):

QFile file = new QFile(“file.dat”);

QFile.OpenMode mode = new QFile.OpenMode();

mode.set(QFile.OpenModeFlag.ReadOnly);

file.open(mode);

QDataStream in = new QDataStream(file); //从file中读取序列化后的数据

//提取”the answer is”和42

String str = in.readString();

int a = in.readInt();

写入到流中的每个条目都是以一个预定义的二进制格式写入的,这个格式根据条目的类型而变化。所支持的Qt 类型包括QBrushQColorQDateTimeQFontQPixmapQString(本座告诉你,QtJambi中没有QString)QVariant和其它的很多类型。要想知道支持数据流的Qt 类型的完整列表,就去看QDataStream操作符的格式

对于整数,最好在写入之前转换成一个Qt 整数,并且在读取的时候以那个相同的Qt 整数的类型来读取。这样能确保你得到你想要的大小的整数,并且将你与编译器和平台的差异隔离开。

举个例子吧,一个char *字符串是勒样写入的:一个32位的整数,表示的是包括’\0′字节在内的字符串的长度,紧接着是包含’\0′字节在内的整个字符串的各个字符。当读取一个char *字符串时,首先读取4字节,将它作为那个32 位的长度值,再读取那么多的字符,以构造那个char *字符串,其中包括’\0′终结符。

初始的输入/输出设备通常是在构造函数里设置的,但是可以使用setDevice()来修改。如果你到达咯数据的末尾(或者没有设置输入/输出设备),那么atEnd()就会返回真。

版本设置

QDataStream的二进制格式从Qt 1.0 以来一直在变化,并且看样子会随着Qt 的变化而继续变化。当你在输入或者输出复杂的类型时,要确保是使用相同版本的流version())来读取和写入的。如果你同时需要前向和后向兼容性,那么你可以将版本号硬编码到程序中:

stream.setVersion(QDataStream.Version.Qt_4_0.value());

如果你在创建一个新的二进制数据格式,例如由你的程序所创建的文档所使用的一个文件格式,那么你可以使用QDataStream 来按照一个可移植的格式来写这些数据。典型地,你可以写入一个简短的文件头,其中包含一个魔数字符串和一个版本号,这样就给你自己留下咯在将来进行扩展的空间。例如:

QFile file = new QFile(“file.xxx”);

QFile.OpenMode mode = new QFile.OpenMode();

mode.set(QFile.OpenModeFlag.WriteOnly);

file.open(mode);

QDataStream out = new QDataStream(file);

//写入一个包含“魔数”和一个版本号的文件头

out.writeInt(0xA0B0C0D0);

out.writeInt(123);

out.setVersion(QDataStream.Version.Qt_4_0.value());

//写入数据

out.writeBytes(lots_of_interesting_data.toByteArray());

以后再像这样读取:

QFile file = new QFile(“file.xxx”);

QFile.OpenMode mode = new QFile.OpenMode();

mode.set(QFile.OpenModeFlag.ReadOnly);

file.open(mode);

QDataStream in = new QDataStream(file);

//读取并且检查文件头

int magic = in.readInt();

if (magic != 0xA0B0C0D0)

return XXX_BAD_FILE_FORMAT;

//读取版本号

int version = in.readInt();

if (version < 100)

return XXX_BAD_FILE_TOO_OLD;

if (version > 123)

return XXX_BAD_FILE_TOO_NEW;

if (version <= 110)

in.setVersion(QDataStream.Version.Qt_3_1.value());

else

in.setVersion(QDataStream.Version.Qt_4_0.value());

//读取数据

QByteArray lots_of_interesting_data = new QByteArray();

QByteArray data_new_in_XXX_version_1_2 = new QByteArray();

QByteArray other_interesting_data = new QByteArray();

lots_of_interesting_data.readFrom(in);

if (version >= 120)

data_new_in_XXX_version_1_2.readFrom(in);

other_interesting_data.readFrom(in);

你可以选择在序列化数据时使用什么字节序。默认的设置是大端在前(最重要的字节(MSB)在前)。如果将它改变成小端在前的话会破坏可移植性(除非读取者也变成小端在前)。我们建议保留这个设置,除非你有特殊的需求。

读取和写入原始的二进制数据

你可能想要从数据流/向数据流直接读取/写入你自己的原始二进制数据。可以使用readRawData()来从流中将数据读取到一个预先分配咯空间的char *。可以使用writeRawData()来将类似的数据写入到流中。注意,任何的编码/解码工作都必须由你来做。

类似的一对函数是readBytes()writeBytes()。它们与对应的原始(raw)函数有以下不同:readBytes()首先会读取一个quint32,将它作为要读取的数据的长度,然后将那么多的数据读取到一个预先分配咯空间的char *中;writeBytes()首先写入一个quint32,它表示的是数据的长度,接下来就写入数据。注意,对数据(除咯那个表示长度的quint32 以外)的任何编码/解码工作要由你来做。

参见

QTextStreamQVariant

无线网络很是泛滥

- no title specified


无线网络很是泛滥

 

Qt Jambi 4.4文档翻译:安装Qt Jambi,Installing Qt Jambi

- no title specified


Qt Jambi 4.4文档翻译:安装Qt Jambi,Installing Qt Jambi

Qt Jambi可在Linux、Mac OS X 和Windows 上以预编译或者源代码软件包的方式获得。要安装Qt Jambi,需要有Java 1.5 或者更高版。

取决于你是下载咯一个预编译软件包还是一个源代码包,这个安装过程是不同的。这个安装向导分小节来说明两种不同的方法。

希望你喜欢!

内容目录

Qt Jambi 4.4文档翻译:安装Qt Jambi,Installing Qt Jambi

安装一个预编译包

手动运行Qt Jambi 程序

其它的载入原始库的方法

用源代碼編译Qt Jambi

为Qt Jambi而配置系统

為Qt Jambi而构建 Qt

设置环境

构建Qt Jambi

排除问题

常见问题

与载入相关的问题

与平台相关的注意事项

运行Qt 设计师

运行Qt Jambi 生成器

安装一个预编译包

解压缩咯软件包之后,你就可以运行启动器(Launcher)咯,它是一个用来启动Qt Jambi 自带的示例和演示程序的程序。

要在 Windows 上运行示例和演示程序启动器,就运行这个:

qtjambi.exe

在Linux 和Mac OS X 上运行这个

qtjambi.sh

运行这些文件将会验证虚拟机的版本并且为Qt Jambi 程序的运行而设置正确的环境。

当你准备发布你自己的程序时,就去查看部署 文档。

手动运行Qt Jambi 程序

要手动启动那些程序,你需要在你的类路径(classpath)里包含以下.jar文件:

  • •.qtjambi-4.4.0_01.jar,其中包含咯那些Jambi 类 

  • •.与平台相关的包,其中包含咯Qt Jambi 使用的本地(native)。这个包是以操作系统及用来构建这些库的编译器的名字来命名的;例如,针对Windows 和MSVC 2005,就是qtjambi-win32-msvc2005-4.4.0_01.jar 

  • •.要运行那些示例或者启动器本身,类路径还必须包含qtjambi-examples-4.4.0_01.jar 

3个文件都位于Qt Jambi 的安装目录里。下面针对每个操作系统给出一个例子:

// Linux

java -cp qtjambi-4.4.0_01.jar:qtjambi-linux32-gcc-4.4.0_01.jar:qtjambi-examples-4.4.0_01.jar com.trolltech.launcher.Launcher

 

// Mac OS X

java -XstartOnFirstThread -cp qtjambi-4.4.0_01.jar:qtjambi-macosx-gcc-4.4.0_01.jar:qtjambi-examples-4.4.0_01.jar com.trolltech.launcher.Launcher

 

// Windows

java -cp qtjambi-4.4.0_01.jar;qtjambi-win32-msvc2005-4.4.0_01.jar;qtjambi-examples-4.4.0_01.jar com.trolltech.launcher.Launcher

注意在 Mac 上运行一个Qt Jambi 程序时,必须将-XstartOnFirstThread参数传递给Java 命令。

其它的载入原始库的方法

就像前面说的那样,Jambi从平台软件包(在它已经包含到类路径的情况下)里载入原始库

另外一种载入原始库的方法就是依赖Java 的标准载入方法。可通过下面2种方法之1来实现:指定JVM 系统属性-Djava.library.path=[到库的路径]或者在以下环境变量中包含它们的路径

平台

说明

Windows

设置PATH 环境变量,使之包含Qt Jambi 目录下的bin 目录。

Linux

设置LD_LIBRARY_PATH 环境变量,使之包含Qt Jambi 目录下的lib 目录。

Mac OS X

设置DYLD_LIBRARY_PATH 环境变量,使之包含Qt Jambi 目录下的lib 目录。

注意,指向庫的路径需要是它些变量中的第一个路径。否則的話,Jambi可能会找到其它不兼容的版本的庫。例如,在 Linux 上,/usr/lib中的libQtCore.4.so 這个庫是默諗位于LD_LIBRARY_PATH 中的

Qt 的某些功能是通過原始插件載入的。這包括对JPEG 图片的支持。這些插件是放在Qt Jambi 的安装目彔里的plugins 目彔里的

Qt Jambi从QT_PLUGIN_PATH 環境变量中的目彔里查找插件(在没有使用与平台相关的軟件包的情况下)。所以你应當将QT_PLUGIN_PATH 指向plugins 目彔

然后你就可以运行Qt Jambi 程序咯。下面是手动运行启动器的示例:

java -cp qtjambi-4.4.0_01.jar:qtjambi-examples-4.4.0_01.jar com.trolltech.launcher.Launcher

用源代碼編Qt Jambi

這一小节講的是怎麽用源代碼來編译安装Qt Jambi。首先我們说一说如何配置你的系统,再來講述使用命令行來編译Qt Jambi 的過程。最后,我們看看一些常见的安装問題。

注意Qt Jambi 源代碼包也依賴Qt 源代碼包。为咯避免可能存在的二遘制不兼容的問題,我們强烈建议你在編译Qt Jambi 之前重新編译Qt。在 Mac OS X 上Qt必須配置成不使用框架(frameworks)(在运行configure 脚本時指定–no-framework選項)

为Qt Jambi而配置系统

除咯Qt 源代碼之外,你還需要JDK 1.5 或更高版以及构建工具ant

為Qt Jambi而构建 Qt

第一步就是为Qt Jambi 而构建Qt。一般地,按常規方法來构建Qt 就可以工作,但是也有一些例外。对于在任何给定的系统中构建Qt 的细节,可以去看Qt 的安装向导。

平台情况

注意事项

全部

使用-D QT_JAMBI_BUILD选项可以在Qt 中为Qt Jambi 而开启或关闭某些特性。Qt Jambi也不需要Qt 3 的支持库 所以建议使用-no-qt3support参数來编译

Mac OS X

Qt Jambi只支持使用-no-framework参数配置过的Qt,并且由于兼容性的原因建议以 10.4 SDK 为目标来配置Qt-sdk /Developer/SDKs/MacOSX10.4u.sdk

Linux

Sun的Java虚擬机有个问题,使得它不能使用MMX 和SSE 指令。当你要将程序与1.5 版本的Java 运行时环境一起部署时,使用这些参数-no-mmx -no-sse -no-sse2 -no-3dnow来配置Qt 以避免问题。另外,由于Qt Jambi要求Qt 的头文件和库都放置在相对于QTDIR 的位置,Qt应当以参数-prefix $PWD来配置,此时并没有安装。

Windows (MSVC 2005或更新版)

为咯让插件能正常地载入,需要-plugin-manifests参数。

设置环境

下面的表格描述咯安装Qt Jambi 时必要的环境变量

QTDIR

这个变量必须包含已安装的Qt 的目录路径。

JAVA_HOME

这个变量必须包含已安装的 Java 的目录路径。

构建Qt Jambi

Qt Jambi提供咯一个ant 任务,它将处理在构建Qt Jambi 库时的所有任务。要想从头开始构建Qt Jambi,就在Jambi 的安装目录里运行ant,不带任何参数。

> ant

在 Qt Jambi 的目录里。请注意,Qt Jambi需要ant ant-trax 模块,而这个模块在某些linux 发行版里是可选的。运行ant 会自动进行以下步骤:

  • •.编译Qt Jambi 生成器 

  • •.根据由$QTDIR指定的Qt 来生成Qt Jambi 库 

  • •.编译Juic 工具 

  • •.编译并且打包那些原始库 

  • •.编译并且打包那些类库 

  • •.针对那些示例运行Juic 

  • •.编译并且打包那些示例 

要想看到在ant 构建过程中的那些子目标的描述,你可以这样做:

> ant -projecthelp

要想看到那些在构建过程中的配置信息的描述,你可以这样做

> ant help

排除问题

如果你在编译和运行Qt Jambi 的时候有甚麽问题,可以看看我们准备的一个常见问题列表。这个表格应当足够解决大部分问题;如果还是不行的话,试试找个砖家问问。可以先看看Jambi 常见问题列表。在Jambi 邮件列表上,可以向活跃的Jambi 用户和Jambi 开发团队询问关于安装的问题;如果Qt Jambi 在载入原始库的时候失败咯,那么请设置好com.trolltech.qt.verbose-loading这个系统属性再运行Qt Jambi,以便给出调用栈的跟踪报告。

常见问题

在这一小节,我们试着收集在构建Qt Jambi 时的常见问题。它们都列在一个表格中,一列是问题的描述,另一列是解决方法。

问题

解决方法

在 Linux 上gcj(GNU 的Java 编译器)位于/usr/bin;指向正确的java 版本的路径必须在PATH 中位于这个之前。这个问题通常引起java.lang.ClassFormatError 错误

确保在PATH 中的是正确的java 可执行程序。

环境变量设置不正确。

对照着 Qt Jambi 而配置系统小节,检查一下你的系统是否已经为Jambi 而做咯正确的设置。

Qt Jambi使用Qt 头文件来生成从c++到java 的映射。除非是以默认设置来构建Qt 的,否则你将可能在绑定原始库以外的库的时候遇到链接错误。

以默认设置来构建Qt

juic不会更新那些没有修改过的.jui文件,这在Java 源代码被删除时可能导致问题

带着-a选项来运行juic。

Qt Jambi预期Qt 是在关掉调试信息的情况下编译的。如果在构建Qt的时候打开咯调试选项,那么就找不到库

在设置咯com.trolltech.qt.debug 这个系统属性的情况下运行Qt Jambi

Qt Jambi试图使用错误的编译器

在Windows 系统中,当MSVC 和MinGW 编译器都安装咯的时候,可能发生这个错误。你可以设置QMAKESPEC 变量。请参考qmake文档以了解细节。

与载入相关的问题

如果Jambi 没能找到那些原始库,那么你会遇到java.lang.UnsatisfiedLinkError 或者其它与载入相关的错误。我们在下面列出查找路径。它们是按照Jambi 查找库的顺序列出来的

  • •.com.trolltech.qt.library-path 这个系统属性 

  • •.类路径(包括jar 文件)。 

  • •.Jambi 软件包结构的根目录(即Qt Jambi 的安装目录下的lib(Mac OS X和Linux)或者bin(Windows)子目录。 

  • •.java.library.path 这个系统属性,在Linux上 被设置为LD_LIBRARY_PATH,Windows 上是PATH,Mac OS X 上是DYLD_LIBRARY_PATH。 

与平台相关的注意事项

我们现在快速地看一看特定平台的问题

平台

注意事项

Mac OS X

在运行一个Qt Jambi 程序时,必须将-XstartOnFirstThread参数传递给Java 可执行程序。另外,如果你使用的是源代码包,那么你必须用–no-framework选项来编译Qt

Linux/64位

安装一个32位的虚拟机,例如,在Ubuntu上,安装ia32-sun-java5-bin软件包并且将/usr/lib/jvm/ia32-java-1.5.0-sun-1.5.0.06/jre/bin添加到PATH环境变量中

运行Qt 设计师

Qt 设计师是一个用于设计和构建用户界面的可视化工具。如果你使用的是预编译的软件包,那么你可以使用designer.bat 或者designer.sh 脚本来从命令行启动它Eclipse整合会自动处理设计师的相关事项

你可以在Qt设计师文档中找到更多信息。

运行Qt Jambi 生成器

生成器是一个Qt程序,它可以用来将基于C++的Qt API映射到等价的Java API。Qt Jambi软件包中提供咯一个关于如何使用Qt Jambi生成器的示例,放在到/Qt Jambi/的路径/generator_example目录中

要从源代码包中构建那个生成器示例,只需要简单地这样做:

ant -f build_generator_example.xml

警告Qt Jambi 生成器是用来处理基于Qt 的源代码的,不适合于对普通的C++库进行映射

Qt Jambi4.4文档翻译:使用Qt进行国际化,Internationalization with Qt

- no title specified

li span. { clear: both; line-height:0; width:0; height:0; margin:0; padding:0; } span.footnodeNumber { padding-right:1em; } span.annotation_style_by_filter { font-size:95%; font-family:Arial; background-color:#fff000; margin:0; border:0; padding:0; } * { margin:0;} .Heading_20_2 { font-size:18pt; margin-bottom:0.212cm; margin-top:0.423cm; font-family:文泉驿正黑; writing-mode:page; font-weight:bold; } .Heading_20_3 { font-size:14pt; margin-bottom:0.212cm; margin-top:0.423cm; font-family:文泉驿正黑; writing-mode:page; font-weight:bold; } .P1 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P10 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P11 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P12 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P13 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P14 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P15 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P16 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P17 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P18 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P19 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P2 { font-size:24pt; font-weight:bold; margin-bottom:0.212cm; margin-top:0.423cm; font-family:文泉驿正黑; writing-mode:page; text-align:center ! important; } .P20 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P21 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P22 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P23 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P24 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P25 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P26 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P27 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P28 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P29 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P3 { font-size:10pt; margin-bottom:0.499cm; margin-top:0cm; font-family:文泉驿等宽正黑; writing-mode:page; } .P30 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P31 { font-size:12pt; margin-bottom:0cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P4 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P5 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P6 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P7 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P8 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .P9 { font-size:12pt; margin-bottom:0.212cm; margin-top:0cm; font-family:文泉驿正黑; writing-mode:page; } .Preformatted_20_Text { font-size:10pt; font-family:文泉驿等宽正黑; writing-mode:page; margin-top:0cm; margin-bottom:0cm; } .Text_20_body { font-size:12pt; font-family:文泉驿正黑; writing-mode:page; margin-top:0cm; margin-bottom:0.212cm; } .Bullet_20_Symbols { font-family:OpenSymbol; } .T1 { font-weight:bold; } .T2 { font-weight:bold; } .T3 { font-weight:bold; } .Teletype { font-family:文泉驿等宽正黑; } .Numbering_20_Symbols .T10 .T100 .T101 .T102 .T103 .T11 .T12 .T13 .T14 .T15 .T16 .T17 .T18 .T19 .T20 .T21 .T22 .T23 .T24 .T25 .T26 .T27 .T28 .T29 .T30 .T31 .T32 .T33 .T34 .T35 .T36 .T37 .T38 .T39 .T4 .T40 .T41 .T42 .T43 .T44 .T45 .T46 .T47 .T48 .T49 .T5 .T50 .T51 .T52 .T53 .T54 .T55 .T56 .T57 .T58 .T59 .T6 .T60 .T61 .T62 .T63 .T64 .T65 .T66 .T67 .T68 .T69 .T7 .T70 .T71 .T72 .T73 .T74 .T75 .T76 .T77 .T78 .T79 .T8 .T80 .T81 .T82 .T83 .T84 .T85 .T86 .T87 .T88 .T89 .T9 .T90 .T91 .T92 .T93 .T94 .T95 .T96 .T97 .T98 .T99 { } –>

Qt Jambi4.4文档翻译:使用Qt进行国际化,Internationalization with Qt

原文http://doc.trolltech.com/qtjambi-4.4/html/com/trolltech/qt/qtjambi-i18n.html

关于Qt jambi 对国际化和多语言的支持的信息。对一个程序进行国际化就是让这个程序可被与作者所在的国家不同的人使用的过程

在某些情况下,国际化是很简单的,例如,要把一个美国的程序拿去给澳大利亚的或者英国的用户使用,可能只需要做一些拼写上的修改。但是要把一个美国程序拿去给一个日本鬼子用,或者把一个韩国程序拿去给一个德国佬用,就要求那个软件不止是使用不同的语言,还要使用不同的输入技术、字符编码和显示习惯。

Qt Jambi努力让开发者可以进行无痛的国际化。Qt Jambi 里面全部的输入部件和文字绘制方法都为所有受支持的语言提供内建的支持。内建的字体引擎可以正确并且漂亮地渲染出那些同时包含从多种不同的书写系统中弄出来的字符的文字

Qt支持现在使用的大部分语言,具体地是

  • •.所有的东亚语言(汉语、日语和韩语)

  • •.所有的西方语言(拉丁字母)

  • •.阿拉伯语

  • •.西里尔语(俄罗斯、乌克兰等等)

  • •.希腊语

  • •.以色列语

  • •.泰语和老挝语

  • •.Unicode 4.0 中不需要特殊处理的全部字符

在Windows、有FontConfig(客户端字体支持)的Unix/X11和用于嵌入式Linux 的Qt上,还支持以下语言

  • •.孟加拉语

  • •.梵文

  • •.迪维希语 (马尔代夫语)

  • •.古吉拉特语

  • •.古尔穆希语

  • •.埃纳德语

  • •.高棉語

  • •.馬拉雅拉姆語

  • •.缅甸语

  • •.叙利亚语

  • •.坦米爾語

  • •.泰卢固语

  • •.西藏語

这些书写系统中有很多是有特殊习惯的

  • •.特殊的换行行为。某些亚洲语言在书写的时候字与字之间没有空格。换行可能发生在任何一个字符之后(有例外),例如汉语、日语和韩语;也可能发生在逻辑词之后,例如泰语。

  • •.双向书写。阿拉伯语和以色列語是从右向左书写的,除咯数字和嵌入到其中的英语文字之外,那些东西是从左向右书写的。准确的行为是在Unicode 9号技术附件Unicode Technical Annex #9里定义的

  • •.非空格或者区别符(欧洲语言中的重音或者元音标记)。某些语言,例如越南语,广泛地使用这些标记,某些字符可有多于一个标记,以澄清它的发音。

  • •.连字在特定的上下文中,某些字母被一个点号代替,以形成一个连字。常见的例子就是美国和欧洲的书中使用排版的fl 和fi 连字

Qt Jambi努力照顾到上面所列出的全部特性。只要你使用Qt Jambi 的输入部件(例如QLineEditQTextEdit和派生的类)和Qt Jambi 的显示部件(例如QLabel),那么你通常不用担心这些特性。

对这些书写系统的支持对于程序猿来说是透明的,是完全封装在Qt Jambi的文字引擎里的。这意味着,你不需要了解一个特定语言中的书写系统的任何东西,除咯以下小问题以外

  • •.QPainter::drawText(int x, int y, const QString &str)在绘制的时候一直会将字符串的左边界放置到x、y 参数指定的位置。这就会一直生成左对齐的字符串。阿拉伯语和以色列语的程序中字符串通常是右对齐的,所以对于这些语言就使用那个以 QRect 为参数的drawText(),因为这样就能够根据语言的特性来对齐咯

  • •.当你在也你自己的文字输入控件时,使用QFontMetrics::charWidth()来确定一个字符串中的字符的宽度。在某些语言(例如阿拉伯语或者来自印度次大陆的语言)中,一个字符的宽度和开头是依据周围的字符而改变的。编写输入控件通常需求对它所要被用于其中的语言的文字系统有一定的了解。通常最简单的办法是子类化QLineEdit 或者QTextEdit

下面的一些小节中有一些关于Qt Jambi 的国际化(i18n)支持的状态的信息。另外可参见Qt语言家手册

一步步地来

使用Qt Jambi 来编写跨平台的国际化软件是一个渐近的过程。你的软件可在以下阶段变成国际化的

针对纯文字使用tr()

每当你的程序使用那些会显示到用户面前的”引号中的文字”时,确保它被QCoreApplication::translate()函数处理。实际上,为了实现这一点,只需要使用QtJambiObject::tr()。例如:

public LoginWidget()

{

QLabel abel = new QLabel(tr(“Password:”));

}

这将覆盖到你所写出来让用户看的字符串中的99%

如果引用的文字不在一个QtJambiObject 子类的成员函数里,那么就直接使用QCoreApplication::translate()函数:

void some_static_function()

{

QLabel abel = new QLabel(

QApplication.instance().translate(“LoginWidget”, “Password:”));

}

针对快捷键的值使用QKeySequence()

像Ctrl+Q 或者Alt+F 这样的快捷键也需要翻译。如果你在你的程序中将“退出”(“quit”的快捷键硬编码为Qt::CTRL + Qt::Key_Q,那么翻译器将无法改写它们。正确的用法是

exitAct = new QAction(tr(“E&xit”), this);

exitAct.setShortcut(tr(“Ctrl+Q”, “Quit”));

生成翻译内容

一旦你在一个程序中使用咯tr(),你就可以开始生成你的程序中那些用户可见的文字的翻译咯

Qt语言家手册提供咯关于Qt Jambi 的翻译工具Qt语言家Linguistlupdate lrelease 的详细信息。

对一个Qt Jambi 程序的翻译有3个步骤:

  1. 1.运行lupdate来从这个Qt Jambi 程序的Java 源代码中提取出文字,将生成一个用于翻译程序的消息文件(一个.ts文件)。这个工具识别出上面所描述的tr()结构,并且生成.ts文件(通常是每种语言一个)。

  2. 2.使用Qt语言家来为这个.ts文件中的源文字提供翻译。由于.ts文件是XML 格式的,所以你可以手动修改它们。

  3. 3.运行lrelease以从这个.ts文件中获取一个只适合于最终使用的轻量级的消息文件(一个.qm文件)。把.ts文件当成“源文件”,把.qm文件当成“目标文件”。翻译者编辑那些.ts文件,但是你的程序的用户只需要那些.qm文件。这两种文件都是与平台和地域无关的

典型地,每当你发布你的程序时,你就会重复这些步骤。lupdate 工具会尽量重用以前的版本中的翻译内容

在你的程序中,你必须使用QTranslator::load()来将适合于你的用户的语言的翻译文件载入到程序中,再使用QCoreApplication::installTranslator()来安装它们。

linguistlupdatelrelease都会安装到Qt Jambi 所安装到的基准目录中的bin 子目录里。在Qt语言家里面点击帮助|手册(Help|Manual)以访问用户手册;它包含咯一个教程,可带你上路。Qt自己也包含咯400多个字符串,它们也需要翻译为你将要使用的目标语言。你可以在$QTDIR/translations目录下找到针对法语、德语和简体中文的翻译文件,以及一个用来翻译为其它语言的模板。(这个目录中也包含咯一些附加的未受支持的翻译文件,它们也可能有用)

典型地,你的程序的main()函数会是这样的:

public static void main(String args[])

{

QApplication.initialize(args);

 

QTranslator qtTranslator = new QTranslator();

qtTranslator.load(“classpath:/translations_directory/qt_” + QLocale.system().name() + “.qm”);

QApplication.instance().installTranslator(tTranslator);

 

 

QTranslator myappTranslator = new QTranslator();

myappTranslator.load(“classpath:/translations_directory/myapp_” + QLocale.system().name() + “.qm”);

QApplication.instance().installTranslator(myappTranslator);

 

QApplication.exec();

}

本地化

本地化就是适应本地的习惯的过程,例如,采用本地的习惯格式来表示日期时间。这种本地化过程可以使用适当的tr()字符串来完成。

void setTime(QTime ime)

{

if (tr(“AMPM”) == “AMPM”) {

// 12-hour clock

} else {

// 24-hour clock

}

}

在这个例子里,对于美国人,我们会将”AMPM”的翻译按原样保留,因此就会使用12小时的时钟分支;但是在欧洲勒,我们会把这个东西翻译成别的东西,这样的话,在代码里面就会进入24小时的时钟分支。

对于本地化的数字,使用QLocale

不建议对图片进行本地化。选择适合于所有语言的清晰的图标,而不要依赖本地的双关语或者隐喻。唯一的例外是那些用来显示向左或者向右的箭头的图片,针对阿拉伯语和以色列语,可能需要将这些图片翻转。

动态翻译

某些程序,例如Qt 语言家,必须在它们还在运行的时候支持用户的语言设置的变化。要让部件知道那些安装咯的QTranslator的变化,就重载那个部件的changeEvent()函数,检查当前事件是不是一个LanguageChange 事件,并且像通常那样使用tr()函数来更新部件显示的文字。例如:

void changeEvent(QEvent vent)

{

if (e.type() == QEvent.Type.LanguageChange) {

titleLabel.setText(tr(“Document Title”));

okPushButton.setText(tr(“K”));

} else

QWidget.changeEvent(event);

}

所有其它的事件都应当通过调用这个函数的默认实现来继续传递下去

已安装的翻译器的列表可以依据一个LocaleChange 事件来发生变化,或者程序可以提供一个用户界面以让用户改变程序的当前语言。

QWidget 子类的默认事件处理器会响应QEvent::LanguageChange 事件,并且在必要的时候调用这个函数;其它的程序组件也可以通过向部件发送LanguageChange 事件来强制让它们更新自己。

Qt Jambi4.4文档翻译:QDir.homePath

Qt Jambi4.4文档翻译:QDir.homePath

homePath

public static java.lang.String homePath()

返回用户的家目录的绝对路径。

在 Windows 上,这个函数会返回当前用户的配置文件的目录。典型地,它 是这个:

        C:/Documents and Settings/Username

使用toNativeSeparators()函数来将分隔符转 换成适合于当前操作系统的分隔符

如果当前用户的配置文件所在的目录不存在或者无法被获取,那么就会(按照给定的 顺序)检查以下的替代位置,直到找到一个可用的路径:

  1. 1.USERPROFILE 环境变量指定的路径。 

  2. 2.通过将HOMEDRIVE HOMEPATH 环境变量连接而形成的路径。 

  3. 3.HOME 环境变量指定的路径。 

  4. 4.rootPath()函数(它使用SystemDrive 环境变 量)返回的路径 

  5. 5.C:/目 录 

在非Windows 操作系统上,如果存在HOME 环境变量,将会使用它,否则将会使用rootPath()函数返回的路径。

参见

home()currentPath()rootPath()tempPath()

Qt Jambi4.4.3文档翻译:简单用户界面示例,Simple UI Example

Qt Jambi4.4.3文档翻译:简单用户界面示例,Simple UI Example

代码

简单用户界面示例展示的是怎么把那些由Qt设计师创建的用户界面.jui)文件用来实现程序的用户界面。

这个示例的主窗口显示出一个文本浏览器和一个Open Dialog 按钮,这个按钮可以用来访问一个有输入区域的对话框。当这些输入区域都填充满咯,或者是对话框被取消咯的时候,输入结果会被放置到文本浏览器中。

SimpleUIExample 类的实现

SimpleUIExample类 是从QMainWindow 派生的,并且提供一个由Ui_SimpleUIExampleMainWindow 类的实例实现的用户界面

public class SimpleUIExample extends QMainWindow {

 

 

    public static void main(String[] args) {

        QApplication.initialize(args);

        SimpleUIExample mainw = new SimpleUIExample();

        mainw.show();

        QApplication.exec();

    }

 

 

    Ui_SimpleUIExampleMainWindow mainWindowUi = new Ui_SimpleUIExampleMainWindow();

用户界面类的实例被实现为SimpleUIExample 类的一个成员。

用户界面类是在构建这个示例的时候从一个用户界面文件中生成出来的,它提供一个setupUi()方法,我们在 SimpleUIExample 的构造 函数中使用这个方法来建立用户界面:

    public SimpleUIExample() {

        // Place what you made in Designer onto the main window.

        mainWindowUi.setupUi(this);

        setWindowIcon(new QIcon(“classpath:com/trolltech/images/qt-logo.png”));

 

        // Connect the OpenDialog button to the showDialog method.

        mainWindowUi.pushButton_OpenDialog.clicked.connect(this, “showDialog()”);

    }

我们还设置窗口的图标,并且将用户界面中定义的一个按钮连接到这个类中的showDialog()

    private void showDialog() {

        // Make the dialog.

        Ui_SimpleUIExample dialogUi = new Ui_SimpleUIExample();

        QDialog dialog = new QDialog(this);

        dialogUi.setupUi(dialog);

对话框自己也使用一个从.jui文 件生成的用户界面类,这个文件是我们以前使用类似的方法制作出来的。在这里,我们在新构建的QDialog 实例上调用Ui_SimpleUIExample 实例的setupUi()方法。

一旦建立好咯,对话框就以正常的方式执行:

        String result = “”;

        if (dialog.exec() == QDialog.DialogCode.Accepted.value()) {

            result += “Name: ” + dialogUi.lineEdit_Name.text() + “n”;

            result += “E-Mail: ” + dialogUi.lineEdit_Email.text() + “n”;

            // Get rest of dialog information here

 

        } else {

            result = “Cancelled by user.”;

        }

 

        mainWindowUi.textBrowser.setText(result);

 

    }

 

}

如果用户接受咯对话框,那么我们读取它所包含的输入部件 中的内容,再将读取的结果写入到主窗口的文本浏览器部件中。如果用户取消咯对话框,那么就会将”Cancelled by user.”写入到文本浏览器中。

main() 函数

main()方法被定义为 SimpleUIExample 类的一部分。它构造必需的QApplication 实例、构造并且显示出 SimpleUIExample 类的一个实例、再执行程序的事件循环:

    public static void main(String[] args) {

        QApplication.initialize(args);

        SimpleUIExample mainw = new SimpleUIExample();

        mainw.show();

        QApplication.exec();

    }

当事件循环结束运行时,示例程序退出。一般地,当用户关 闭主窗口时会发生这个。

Qt Jambi的.jui文件与标准Qt的.ui文件的区别

Qt Jambi的.jui文件与标准Qt的.ui文件的区别

Qt Jambi中使用的用户界面文件的扩展名是jui,跟ui文件一样,是一个XML文件。

如果你把一个标准的.ui文 件拿来给juic命令编译的话,会告诉你这个错误:

uic: File is not a ‘jambi’ form

./juic: Failed on input file: ‘/home/dvn/test.ui’

也就是juic不接受标准的Qt界面文件,很遗憾的是本座使用Qt Jambi自带的designer做出来的界面文件仍然是标准的ui文件,没有任何选项指示是否要将它生成一个“jambi” 界面文件。不知道Qt Jambi是哪里出咯问题。

当本座用kompare 将一个.jui文件与一个.ui文件比较时,发现,其实它们只有一点区别。在.jui 文件中,XML里的“ui”元素多咯个属性“language”,并且取值为“jambi”。本座试着将标准的.ui文件手动改咯一下,加上这个“language”属性,果然能编译咯。

可能这个属性还对应着很多其它的东西,但是最起码是能使用这个属性将一个标准的.ui文件“转 换”成一个.jui文件咯。

所以也不是管Qt Jambi自带的designer为什么输出的还是标准的.ui文件咯,只管用任一个Qt Designer设计你的界面,再给“ui”元素加上“language”属性就能拿到Qt Jambi中用咯。

Qt Jambi4.4.3文档翻译:Qt Jambi教程7 – 环环相扣,Qt Jambi Tutorial 7 – One Thing Leads to Another

Qt Jambi4.4.3文档翻译:Qt Jambi教程7 – 环环相扣Qt Jambi Tutorial 7 – One Thing Leads to Another

[上一篇Qt Jambi教程6 - 构建丰富的方块!(Building Blocks Galore!][Qt Jambi教程]

代码

 

这个示例展示的是如何创建拥有信号和信号槽的自定义部件,以及如何用更复杂的方式将它们连接起来。

一行行地看代码

这个文件主要是从第6 章中的BlocksGalore 修改过来的;在这里只说那些重要的改动

现在,除了构造函数之外,LCDRange 类还包含3个成员。在一个程序中,它们组成咯这个部件与其它组件之间的接口。直到现 在,LCDRange才真正拥有咯一个应用编程接口。我们 会在代码中碰到它们的时候研究它们。

这个类的大部分与第6 章中的那个LCDRange 是相同的,在这里只看作咯改变的地方

        quit.setFont(new QFont(“Times”, 18, QFont.Weight.Bold.value()));

我们加上咯一个私有的变量,它记录着显示出来的数字。

        public final Signal1<Integer> valueChanged = new Signal1<Integer>();

在这里我们声明我们的第一个自定义的信号valueChanged。每当LCD 的值改变时,我们就会发射它。一个信号是某 个信号类的一个实例,信号类包括Signal1Signal2 … Signal9。后缀的数字是指这个信号的参数的个数;参数的类型必须是通用的类。我们想使用1个参数(LCD 的值),所以我们使用Signal1 类和Integer。你已经知道如何与信号连接起来咯。这个信号可以连接到任何以一个Integer 作为参数的方法。

我们接下来看构造函数

        public LCDRange()

 

        {

            slider.valueChanged.connect(lcd, “display(int)”);

 

            slider.valueChanged.connect(valueChanged);

        }

我们将滑标的valueChanged 信 号连接到我们的display()信号槽以及我们自己的valueChanged 信号。你所连接的信号会由被连接到的信号触发

让我们仔细地看看,当用户操作滑标时会发生什么。滑标发 现自己的值改变咯,于是发射QSlider.valueChanged 信号。那个信号同时连接到咯QLCDNumber.display()信 号槽和LCDRange valueChanged 信号。

所以,当这个信号被发射的时候,LCDRange也发射它自己的valueChanged 信号。另外,QLCDNumber.display() 被调用,于是显示出新数字。

注意,你不能确保任何特定的执行顺序LCDRange.valueChanged可能会在QLCDNumber.display() 被调用之前或者之后发射

        public int value()

        {

            return value;

        }

value()的实现是很直观 的。它简单地返回滑标的值。

        public void setValue(int value)

        {

            slider.setValue(value);

        }

setValue()的实现也 是很直观的。注意,由于滑标和 LCD 数字是连接上咯的,所以设置滑标的值会自动地更新 LCD 的数字。另外,如果滑标的值超出咯它的允许范围,它会自动调整

ConnectedSlider 类 是从前一章的BlocksGalore 复制过来的,只是构造函数不同。我们来看看所作的改动:

        LCDRange previousRange = null;

 

 

        for (int row = 0; row < 3; ++row) {

            for (int column = 0; column < 3; ++column) {

                LCDRange lcdRange = new LCDRange();

                grid.addWidget(lcdRange, row, column);

 

            if (previousRange != null)

                lcdRange.valueChanged.

                connect(previousRange, “setValue(int)”);

 

                previousRange = lcdRange;

 

            }

 

        }

当我们创建这9个LCDRange 对象时,我们使用信号和信号槽机制将它们连接起来。每个对象的valueChanged 信号都与前一个对象的setValue()信号槽连接起来。 因为LCDRange 会在它的值发生改变的时候发射valueChanged 信号,所 以我们在这里就创建咯一个信号与信号槽的链

运行这个程序

刚启动时,这个程序与前一个的外观是完全相同的。试试操 作一下右下角的滑标。

练习

使用右下角的滑标将全部LCD的值设置成50。然后通过 点击上一行对应的那个滑标来将上面6个LCD的值设置成30。现在,使用刚才操作过 的那个滑标左边的滑标来将前5个LCD的值恢复成50。

点击右下角的滑标的滑块的左侧。发生咯什么?为什么这是 正确的行为?

Qt Jambi4.4.3文档翻译:Qt Jambi教程3-家族价值,Qt Jambi Tutorial 3 – Family Values

Qt Jambi4.4.3文档翻译:Qt Jambi教程3-家族价值,Qt Jambi Tutorial 3 – Family Values

英文原文来自http://doc.trolltech.com/qtjambi-4.4/html/com/trolltech/qt/qtjambi-tutorial3.html

此文章由飞豚扫描器博客荣誉出品:http://stupidbeauty.com/AirPhin

[上一篇Qt Jambi教程2 - 让它退出][Qt Jambi教程][下一篇Qt Jambi教程4 - 来点部件]

代码

 

这个例子展示的是如何创建亲代和子代部件。

我们搞简单点,只使用一个亲代部件、一个子代部件

public class FamilyValues

{

    public static void main(String args[])

    {

        QApplication.initialize(args);

 

 

        QWidget window = new QWidget();

 

        window.resize(200, 120);

 

 

 

        QPushButton quit = new QPushButton(“Quit”, window);

 

        quit.setFont(new QFont(“Times”, 18, QFont.Weight.Bold.value()));

 

        quit.setGeometry(10, 40, 180, 40);

 

 

        quit.clicked.connect(QApplication.instance(), “quit()”);

 

        window.setWindowTitle(“FamilyValues”);

 

        window.show();

 

        QApplication.exec();

    }

}

一行行地看

        QWidget window = new QWidget();

这里我们简单地创建一个普通的部件对象。QWidget 类是所有用户界面对象的基类。部件是用户界面的原子: 它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制出一个表示它自己的图形。一个部件的外观被它的亲代部件裁剪,被它前面的部件遮挡。

像这个部件这样没有嵌入到某个亲代部件中去的部件被叫做窗口。通常,窗口拥有它们自己的窗口边 框和任务栏条目,那是由窗口系统提供的。没有亲代部件的部件永远是一个独立的窗口。它在屏幕上的初始位 置是由窗口系统控制的

        window.resize(200, 120);

我们将窗口的宽度设置为200 像素,高度设置为120 像素。

        QPushButton quit = new QPushButton(“Quit”, window);

一个孩子出生咯。这个QPushButton在 创建的时候有一个亲代部件(窗口window)。一个子代部件永远都会显示在它的亲代部件的区域中。在显示出来之后,它会被亲代部件的边界所裁剪。默认地, 它会位于亲代部件的左上解,也就是(0, 0)的位置。

        quit.setGeometry(10, 40, 180, 40);

QWidget.setGeometry() 方法有4个参数:前2个参数是这个按钮的左上角的 x 和y 坐标。坐标是相对于亲代部件的。后2个参数是按钮的宽度和高度。结果就是 一个从(10, 40)延伸到(190, 80)的按钮。

        window.show();

当一个亲代部件被显示出来的时候,它会调用所有子代部件的显示函数(除咯那些明确使用QWidget.hide()隐藏起来的之 外)。

运行程序

这个按钮不再充满整个窗口咯。它位于窗口中(10, 40)的位置,大小是(180, 40),这是由那个QWidget.setGeometry() 调用造成的。

练习

试试改变窗口的大小。按钮怎么变化?当你使用一个更大的字体来运行程序的时候,按钮的高度发生 咯什么变化?当你把窗口弄得非常小的时候,发生咯什么