QT 移植杂项

来源:互联网 发布:人体断层解剖学软件 编辑:程序博客网 时间:2024/04/25 03:56

今天翻看以前写的blog, 发现一篇关于QtE屏幕动态旋转的文章(俺写的,汗), 结合今天碰巧看到的代码一对照, 发现原来QtE是可以支持屏幕动态旋转的, 只是上次没有发现而已! 原来自己写了一篇很傻的blog还不自知… 这里只好补上一篇简单的blog以做修正。

在 QtE程序动态旋转的不完全实现 一文中笔者讲到QtE自带了支持旋转的gfxdriver插件“transformed”, 通过编译src/plugins/gfxdrivers/transformed目录可以得到这个插件。 进一步在启动程序时设置环境变量可以指定QtE载入这个插件:

export QWS_DISPLAY=transformed:::rot90:0 #rot90表示顺时针旋转90度

在QtE内部会使用QTransformedScreen这个类替代普通的QScreen进而实现屏幕旋转。
而QWSDisplay类提供了一个静态方法setTransformation, 函数原型:
void QWSDisplay::setTransformation ( int transformation, int screenNo = -1 )   [static]

这个函数就是笔者先前没有发现的宝藏! 第一个参数给0、1、2、3代表旋转0、90、180、270度。 这个函数在Qt文档中隐藏得实在太深了, 如果你不是非常有目的性地去仔细查找, 是不太可能留意到这个函数的。(而笔者是先看到代码才找到这个函数的文档, 其实很负责任的讲, 俺觉得即使Qt文档中确实出现了这个函数的原型, 也不能说这个函数是个公开的API, 因为文档实在是太隐蔽了。。。。让人非常汗)

有几点需要注意的地方:

- 该函数只能在server程序中调用, 在client中调用有时会没有作用(笔者的测试是有时管用有时不管用, 建议只在server里调用)
- 该函数的作用域是整个QtE环境, 包括server的widgets和client的widgets
- 启动server时必须加载transformed驱动, 不然调用setTransformation函数是没用的。

综上, 如果你想实现的是某个widget的旋转, 可能该方法就不适用了。 笔者的建议是改用QGraphicsView或QML来实现。

]]> http://www.cuteqt.com/blog/?feed=rss2&p=1971 5 http://www.cuteqt.com/blog/?p=1121 http://www.cuteqt.com/blog/?p=1121#comments Wed, 18 Nov 2009 16:10:53 +0000 shiroki http://www.cuteqt.com/blog/?p=1121 <![CDATA[

(本文内容实属原创,如果有雷同纯属抄袭~)

今天我们又要来讨论一个经久不衰的经典问题, 那就是在QtEmbedded中如何实现程序随屏幕动态旋转。 该功能最常见的应用是在类似手机的嵌入式环境中, 特别是带有sensor的手机,当用户旋转手机的时候程序也跟着旋转并适应屏幕。(见N95,呵呵)

QtE的Transformed gfxdriver

在QtEmbedded公开的API中, 提供了Transformed绘制插件, 这个插件可以帮助你实现应用程序的旋转。 用法是在环境变量中指定该driver及其参数, 这样程序在初始化时就会根据环境变量的设定创建相应的QTransformedScreen。

export QWS_DISPLAY=transformed:::rot90:0 #rot90表示顺时针旋转90度

从上面的例子大家可能看出了其中的局限性, 由于QtE程序被设计为启动初始化时创建gfxdriver的插件, 如果要旋转程序必须重新启动 — 这样根本就没办法实现动态的旋转。 当然,无数的运动品牌用各种方式告诉我们, “Impossible is Nothing”, “Nothing is Impossible”, 让我们深入研究一下QtE的屏幕旋转是如何实现的,从中找到突破口。

QtE中”Transformed”的处理流程

对QWS_DISPLAY环境变量的处理在src/gui/kernel/qapplication_qws.cpp中, 环境变量经由QApplication类的实例传递到QWSDisplay::Data::init函数, 在该函数中调用qt_get_screen去创建适当的QScreen。 真正的创建过程在src/gui/embedded/qscreen_qws.cpp, 在qt_get_screen函数的实现中调用了QScreenDriverFactory::create方法(在embedded/qscreendriverfactory_qws.cpp里), 程序运行到create函数最后一个分支:

if (QScreenDriverFactoryInterface *factory = qobject_cast(loader()->instance(key))) return factory->create(driver, displayId);

这段代码实际上会从gfxdriver plugin目录里寻找key与参数匹配的插件,返回插件提供的QScreen实例, 而在使用transformed情况下就返回了 QTransformedScreen指针。 之后程序的初始化过程就不再赘述。 QTransformedScreen指针被赋予一个全局变量 qt_screen, 在整个程序里都使用该变量, 在后面的一切绘制中都访问该变量。

俺的构想

鉴于qt_screen是整个屏幕的基本关键, 俺的构想是通过动态的替换qt_screen来实现动态的旋转屏幕。 经过俺的试验,该想法部分成功, 屏幕可以动态切换, 但存在的问题非常多。  如果要解决的话可能得通读QtE的源码并完全理解它的功能才行。如:

1、必须一开始就初始化为使用QTransformedScreen, 方法是给个旋转角度为零的参数, 不然后面替换掉screen之后会出现丢失与用户的交互连接的问题。 个人感觉是初始化的代码没有写好,不过懒得去研究了。

2、只在server程序中试验成功,client程序一旋转就出seg fault。 唉,很让人郁闷。

3、旋转之后还需要及时调整应用程序的widget大小以适应新的屏幕布局。 这个还没研究。

俺的实现

虽然问题多多,不好解决,俺还是把我的代码贡献给大家。  虽然俺的水平不济,只能实现到这个程度。如果哪位看官有兴趣,不妨继续深入研究研究,别忘了把成果share给大家。

先来个截图:

rotate

下面的代码片断是在点击Rotate按钮之后做的操作:

void MainWin::rotate() { static int rot = 0; qWarning("do transformation!"); QScreen* temp = qt_screen; qt_screen = NULL; //create a rot screen rot+= 90; if( rot >= 360) rot -= 360; QString spec = "transformed:::rot"; spec+= QString::number(rot) + ":0"; qt_screen = qt_get_screen(0, spec.toAscii()); if( qt_screen) delete temp; else qt_screen = temp; //update the desktop qt_screen->exposeRegion(qt_screen->region(), false); }

完整例子在此, 可以在qvfb里运行测试。 dynrotate1.tgz

请大家用极其宽容的心态来阅读俺的代码, 千万不要拍砖打击我yuki的心灵哦~~

]]> http://www.cuteqt.com/blog/?feed=rss2&p=1121 4 http://www.cuteqt.com/blog/?p=956 http://www.cuteqt.com/blog/?p=956#comments Thu, 27 Aug 2009 04:14:48 +0000 shiroki http://www.cuteqt.com/blog/?p=956 <![CDATA[

本博客前面有篇帖子介绍怎么解决一个常见的Qt/Embedded程序的运行时错误的文章:

Qt经典出错信息之QFontDatabase: Cannot find font directory

这个错误最常见的成因是configure QtE的时候没有加 -prefix参数, 而编译和运行时路径不同导致QtE程序找不到自己的工作目录.

最正规的解决方法是重新configure 并加上正确的-prefix参数; 稍微土点儿的方法是用blog里介绍的软链接去欺骗Qt. 今天给大家介绍个笔者无意中发现的一个新方法, 估计知道的人屈指可数….呵呵, 一般人我不告诉他!

Qt为了提供更好的调试方法给用户, 不断地提供更多外部控制程序的方法, 让程序员可以在不修改程序不重新编译的基础上临时修改程序的行为.  我们如果用过Qt做嵌入式程序, 有可能曾经用到过像 -font之类的参数.  在Qt4.3.2版本引入了一个新的环境变量, 正是针对上述找不到字体目录的问题, 该环境变量就是:

QT_QWS_FONTDIR

在linux下用下面的命令行去设置:

export QT_QWS_FONTDIR=/path/to/your/font/dir

自此我们就不用头疼找不到字体目录的问题啦, 是不是很方便?

]]> http://www.cuteqt.com/blog/?feed=rss2&p=956 0 http://www.cuteqt.com/blog/?p=914 http://www.cuteqt.com/blog/?p=914#comments Wed, 12 Aug 2009 07:24:57 +0000 qpang http://www.cuteqt.com/blog/?p=914 <![CDATA[

前言:长久以来,虽然使用QtEmbedded在作开发,但对QtEmbedded的性能方面不甚关心,并且因为抱着对qtsoftware的信心,也没仔细去了解如何优化QtEmbedded。直到前段时间,参加了某个全国嵌入式大赛,使用了QtEmbedded4.5.0在s3c2410平台上,竟然出现了卡机的现象。对于嵌入式开发来说,资源是极为重要的,而现在看来,Qt变得越来越庞大,越来越耗费稀缺的设备资源,这时,优化就变得格外重要了。在QtEmbedded的文档中有关于性能优化的介绍,我做了简单地翻译,希望能给在嵌入式领域使用QtEmbedded的开发者有所帮助。

正文:

Qt 性能优化

当在资源稀缺的设备上开发嵌入式应用程序时,Qt for Windows CE Qt for Embedded Linux通过调整一系列参数的开启或关闭来内存及CPU的需求。这些选择参数方法的范围主要在编程风格,链接方式及内存分配。

着重注意的是,最直接节省资源的办法是在编译时去掉不需要的特性。详细可以见文档中的fine tuning features部分。

*编程风格

*静态链接vs动态链接

*替换内存分配方式

*绕过后备存放区

编程风格

与其选择随时地创造对话框和控件当它们需要时,并且在不再需要时删除它们,不如一次性地创建,同时在需要的时候使用QWidget::hide()QWidget::show() 功能函数。为了避免应用程序启动的缓慢,应该推迟对话框和控件的创建直到需要的时候。所有这样将改善CPU的性能,所需要付出的只是更多的一点内存,但这会加快运行的效率。

 

动态 Vs 静态链接

许多CPU和内存是通过ELF (Executable and Linking Format)链接进程,重大的节省可以通过静态编译程序的方式实现;而不像是在实际执行中,采集与Qt库有关的部分并且动态链接,所有的应用程序将被创建成一个独立的执行文件,这个文件采用静态方式链接到Qt库上。

这些将改善程序启动时间和减少内存占有率,但前提它会损害灵活实用的特性(一旦增加新的应用部分,必须重新编译一个独立的执行文件)和程序健壮性(假如一个应用部分有bug,将危害到其他的应用部分)。

建立一个静态编译

为了将Qt编译成为一个静态库,在编译时采用-static参数:

./configure –static

为了将应用程序套装建立为一个一体化的应用,应当设计各个应用作为单独的控件(或者控件集)并尽可能地使用最少的代码量在main()函数。然后,设计一个独立的应用程序可以提高其他应用程序见交互的方法。Qt Extended platform就是采用典型的实例:它既可以使用一系列动态链接执行创建,也可以作为单独的一个静态的独立应用程序。

需注意的时,程序仍将动态地链接标准C库以及其它库,因为在目标平台上可能会有其他的应用程序使用它们。

当安装最终客户端应用程序时,这个方式不一定是个选择,但是当在为一个受CPU和内存限制的设备开发一个单独的应用程序套装时,这个选择是十分有益的。

 

替换内存分配方式

在一些平台上,那些运用C++编译的库,在使用“new”和“delete”操作方面有十分差的性能。未来改善内存分配的性能,可以通过以下的功能函数替代实现:

void *operator new[](size_t size)

 {

     return malloc(size);

 }

 

 void *operator new(size_t size)

 {

     return malloc(size);

 }

 

 void operator delete[](void *ptr)

 {

     free(ptr);

 }

 

 void operator delete[](void *ptr, size_t)

 {

     free(ptr);

 }

 

 void operator delete(void *ptr)

 {

     free(ptr);

 }

 

 void operator delete(void *ptr, size_t)

 {

     free(ptr);

 }

以上这些实例显示了必要的代码采用C的内存分配。

 

绕过后备存放区

当运行时,Qt使用了后备存放区。比如,一个绘图缓存,可以减少闪烁和支持如重叠的图形操作。

一般,默认的流程是这样的,对于每个客户端,将自己的控件传入内存,同时,服务端负责将这些内容从内存中取出并在屏幕上绘制。但是有些硬件是众所周知的,同时已经有嵌入式软件的案例,这些对于绕开后备存放区是很有帮助的,可以运行客户端直接地熟练地操作硬件。这里有两种方式来实现直接绘制:第一种方式是对每个控件使用Qt::WA_PaintOnScreen窗口属性,另一种是使用了QDirectPainter类来保存帧缓存的区域。想获取更多信息,可以参考architecture 文档部分的direct painting细节。

]]> http://www.cuteqt.com/blog/?feed=rss2&p=914 5 http://www.cuteqt.com/blog/?p=911 http://www.cuteqt.com/blog/?p=911#comments Fri, 07 Aug 2009 13:34:22 +0000 臭虫 http://www.cuteqt.com/blog/?p=911 <![CDATA[

错误输出为
libQtWebKit.so: undefined reference to `trunc’
libQtWebKit.so: undefined reference to `lroundf’
libQtWebKit.so: undefined reference to `roundf’
libQtWebKit.so: undefined reference to `lround’

这些函数是定义在Linux下的数学库里的,也就是libm.so或者libm.a。但是有些toolchina在做基本库的时候,并没有把这些函数包括进去,你在Linux Shell命令行下,可以用
$ nm libm.so | grep trunc
或者
$ strings libm.so |grep trunc
查看是否定义了对应的函数。

最直观的解决方法就是重新编译一个带有trunc/roundf这些函数的数学库。也可以造福其它引用libm库的应用或应用框架。

如果你只是编译Qt的话,还有一个解决方法,就是自己去实现这些函数。因为Windows版的数学库就是不带这些函数的,所以Qt的代码里已经自带了这些函数的实现代码。我以QtEmbedded-4.5.2为例,看代码
src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h

105 #if COMPILER(MSVC) || COMPILER(RVCT) 106 107 inline long lround(double num) { return static_cast<long>(num > 0 ? num + 0.5 : ceil(num - 0.5)); } 108 inline long lroundf(float num) { return static_cast<long>(num > 0 ? num + 0.5f : ceilf(num - 0.5f)); } 109 inline double round(double num) { return num > 0 ? floor(num + 0.5) : ceil(num - 0.5); } 110 inline float roundf(float num) { return num > 0 ? floorf(num + 0.5f) : ceilf(num - 0.5f); } 111 inline double trunc(double num) { return num > 0 ? floor(num) : ceil(num); } 112 113 #endif

上面看到的这段代码只在MSVC的情况下可以编译,我们自然可以自己的宏去控制它是否编译了,这个宏可以在qmake.conf里的QMAKE_CXXFLAGS或者QMAKE_CFLAGS环境变量中添加

]]> http://www.cuteqt.com/blog/?feed=rss2&p=911 8 http://www.cuteqt.com/blog/?p=898 http://www.cuteqt.com/blog/?p=898#comments Tue, 04 Aug 2009 08:01:13 +0000 qpang http://www.cuteqt.com/blog/?p=898 <![CDATA[前言:

就移植Qte而言,本菜菜已经是熟练工种了,因此这次移植到达芬奇6441平台,开始并不觉得是非常难的事。但是后来发现国内移植方面资料不多,相关的也只有OMAP方面的,并且工具链及linux的不同,还是生产了很多困难,所以还是写篇文章以帮助后来者。该移植过程采用的NFS来共享根文件系统,如果没有NFS按自己的更改

正文:

先就移植的环境做个简单介绍介绍:

开发板:达芬奇6441芯片组(ARM9 + C64x+)

主机系统:redhat enterprise linux 4

主机编译器:gcc version 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)

交叉编译器:arm_v5t_le-gcc(MontaVista提供)

移植过程: 移植前准备

移植Qt4图形开发库前,首先应获取Qt4对应嵌入式开发的最新源代码。Qt4最新源代码可以在它的官方网站上获得,下载地址为:http://www.qtsoftware.com/downloads。为了开发的便利,在PC上可以使用qvfb来模拟Qt4在嵌入式设备上的运行。同时,为了清楚概念,Qt4图形开发库对应PC桌面开发板命名为Qt4,对应嵌入式设备开发板命名为Qte4。

解压源码包

一般需要获取两个源码包,从官方网站下载完成后,应该有如下两个压缩包:
qt-embedded-linux-opensource-src-4.5.2.tar.gz
qt-x11-opensource-src-4.5.2.tar.gz
这两个分别对应的是linux下桌面开发的Qt4图形库和对应嵌入式linux设备开发的图形库。使用tar命令来解压这两个源码包,以便进行配置编译开发,过程如下
#tar zxvf qt-embedded-linux-opensource-src-4.5.2.tar.gz
#tar zxvf qt-x11-opensource-src-4.5.2.tar.gz

配置编译安装tslib

Tslib是一个开源的程序,能够为触摸屏驱动获得的采样提供诸如滤波、去抖、校准等功能,通常作为触摸屏驱动的适配层,为上层的应用提供了一个统一的接口。使用tslib可以为Qt4开发的程序提供准备的触摸屏数据,利于程序触摸的定位。
同样,首先应下载获取tslib的源代码,然后解压至指定文件夹,最后安全如下步骤配置编译安装:
#./autogen.sh
#./configure –prefix=/home/wangc/mytslib/ –host=arm-linux-linux ac_cv_func_malloc_0
_nonnull=yes
#make
#make install
安装成功后,tslib会安装在mytslib目录中,如果想指定安装目录,在prefix参数后修改安装目录即可。

配置编译Qte4

当准备工作做完以后,Qte4的配置编译就可以开始了,由于Qte4对于嵌入式设备来说,是个很庞大的图形库,因此,需要在参数里进行配置和裁剪。由于交叉工具链与一般的交叉工具链不同,需要修改针对arm平台的编译脚本才能正常进行。
在Qte4的解压目录下,进入mkspecs/qws/linux-arm-g++/目录,打开命名为qmake.conf的文件,在里面配置交叉工具链的选择,将所有的arm-linux-改为arm_v5t_le-就可以指定成达芬奇平台的交叉工具链。

配置Qte4

先根据需要选择参数,选择后,进入源代码解压目录进行配置,步骤如下:
#./configure -release -shared -fast -no-largefile -qt-sql-sqlite -no-qt3support -no-xmlpatterns -no-phonon -no-phonon-backend -no-scripttools -no-mmx -no-3dnow -no-sse -no-sse2 -nomake tools -nomake examples -nomake docs -nomake demo -xplatform qws/linux-arm-g++ -embedded arm -little-endian -qt-freetype -qt-gfx-linuxfb -no-gfx-transformed -no-gfx-multiscreen -no-gfx-vnc -no-gfx-qvfb -qt-kbd-usb -no-glib -qt-mouse-tslib -I/home/wangc/mytslib/include -L/home/wangc/mytslib/lib
参数选择中,对于触摸屏应该选择tslib,并且指定tslib的头文件和库文件的目录。

编译Qte4

配置完毕后,就可以编译Qte4,按照如下步骤:
#make
编译时间长短视编译机器的性能和配置参数决定,但编译完成后,就可以得到需要的Qte4库文件。

移植Qte4

编译完成后,为了便于日后的开发,应该在PC上安装Qte4,这样就获得了Qte4的qmake工具和相
关文档。安装命令如下:
#make install
开发板上要运行Qt4的程序,就应该有相对应的库文件,移植的过程就是把已经交叉编译好的库文件移至到开发板上。开发板可以使用NFS共享根文件系统启动,因此,可以先将库文件拷贝到共享的根文件系统下进行测试。当测试完成后,再将库文件拷贝到开发板上。

移植库文件

按照步骤,首先把Qte4的库文件拷贝到NFS启动的根文件系统,其步骤如下:
#cp –f lib/ rootfs/usr/local/Trolltech/QtEmbedded-4.5.0-arm
之所以放入该目录中,是因为这是Qte的默认安装目录,这样可以避免因为路径的不同而产生不必要的问题。

设置环境变量

将根文件拷贝到指定位置后,为了使系统能在运行时获取Qte4库文件位置,应该设置系统的环境变量,配置的环境变量如下:
export QTEDIR=/usr/local/Trolltech/QtEmbedded-4.5.0-arm
export PATH=/usr/local/Trolltech/QtEmbedded-4.5.0-arm/bin:$PATH
export QWS_DISPLAY=LinuxFb:/dev/fb/0
export QWS_DISPLAY=”LinuxFb:mmWidth720:mmHeight272:0〃
export QWS_SIZE=720×272
export LD_LIBRARY_PATH=/usr/local/Trolltech/QtEmbedded-4.5.0-arm/lib:$LD_LIBRARY_PATH
第一个参数指定了Qte所在的目录,第二个参数是将Qte所在目录导入环境变量,第三个及第四个参数指定了Qte的绘制设备,第五个参数是将Qte的库文件目录导入环境变量。

可能出现的错误:

移植过程中,由于硬件体系,系统环境的差异,可能会出现错误,因此,要对这些错误逐一分析检查,并解决。
问题一:Root-NFS: Unable to get nfsd port number from server, using default
问题原因:这种情况通常是nfs配置问题,或者是网线
解决方案:看看网线接好没,配置是否正确
问题二:tslib测试程序不可执行
问题原因:查看连接关系后,发现目标平台式为x86
解决办法:原因是交叉编译工具命名规范与普通的不一样,在编译前导入至编译终端即可。
问题三:./findfiles: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
问题原因:开发板上库文件与PC上交叉编译开发环境库文件不一致
解决方案:该文件在/opt/mv_pro_4.0/montavista/pro/devkit/arm/v5t_le/target/usr/lib/目录下,拷贝到开发板/usr/lib目录下即可。
问题四:QScreenLinuxFb::connect: No such file or directory
Error opening framebuffer device /dev/fb0
: driver cannot connect
Aborted
问题原因:程序默认的帧缓存设备为/dev/fb0,而实际上设备为/dev/fb/0,所以出错显示打不开该设备
解决方案:ln -s /dev/fb/0 /dev/fb0,建立链接,使fb0指向/dev/fb/0后,程序即可顺利运行
具体的问题还是需要根据自己的开发环境来分析解决。

]]> http://www.cuteqt.com/blog/?feed=rss2&p=898 5 http://www.cuteqt.com/blog/?p=889 http://www.cuteqt.com/blog/?p=889#comments Tue, 04 Aug 2009 06:50:57 +0000 shiroki http://www.cuteqt.com/blog/?p=889 <![CDATA[

(本文基于qte4.5, 其他版本酌情阅读,呵呵)

最近看到很多人讨论关于QtEmbedded软键盘的问题, 问的最多的主要集中在以下方面:
1、怎么才能写出不和程序窗口争夺焦点的输入法软键盘
2、怎么把软键盘的键值发送给焦点widget
3、其他关于中文输入法的问题

首先必须明确, 软键盘其实是输入法的一种表现形式, 所以我们在设计实现软键盘时先要去寻找系统中是否提供了输入法的API。 有些人还有疑问:“为什么非得用输入法的API呢? 我用普通的Qt API一样可以实现类似的东西亚!” 但事实并非如此,或许你可以在你的程序中写出一个看起来很像输入法的软键盘窗口, 但要知道普通的QtE API是不能跨进程的, 如果你的系统包含多个程序就必然歇菜! 相反, 好消息是QtE的输入法API可以保证你的输入法在各个QtE的程序里都可以使用。 ^_^y

限于QtEmbedded文档的不够系统, 可能很多人在大海里捞针样的寻找之后终告放弃,转而采用其他古怪的方法实现软键盘需要的功能。 本文旨在提供入门的输入法框架介绍, 并介绍软键盘的实现方法, 让大家少走一些弯路。

下面将介绍输入法中最重要的基础和框架, 以一个简单的软键盘为蓝本, 后边会捎带提提普通的键盘输入法(如像scim这样的中文输入法)在QtEmbedded中该如何实现。

QtE的输入法框架从较早的QtE2到现在的QtE4没有太多的变化, 一个输入法必须提供一个QWSInputMethod类的实例, 所以在输入法中要实现一个QWSInputMethod类的派生类, 在此派生类中显示和操作软键盘widget并完成与输入法框架的通讯。 QWSServer进程调用QWSServer::setCurrentInputMethod(QWSInputMethod*)激活该输入法后, 输入法框架会把应用程序的信息发送给QWSInputMethod类, 由QWSInputMethod的虚函数来处理。 所以最核心的部分变成怎样去实现一个QWSInputMethod的派生类,另外怎么让你的软键盘窗口能和程序输入窗口和QWSInputMethod和平共存。 下面这篇QtE的文档提及了如何解决本文开头提出的第一个问题:
http://doc.qt.nokia.com/4.5/qt-embedded-charinput.html

其核心是软键盘widget需要设置Qt::Tool属性, 以保证它不和焦点窗体争夺焦点

关于第二个问题可以在QWSInputMethod类的文档中找到大部分答案。 QWSInputMethod提供的sendPreeditString方法负责将预处理的文本发送给焦点窗体, 一般情况下编辑器会将此文本显示为带下划线或虚线的文本, 表示这是编辑过程中的半成品; 然后QWSInputMethod::sendCommitString函数负责发送最终用户确认的文本给编辑框。

解决了这两个问题我们就可以写出一个简单的软键盘输入法了, 呵呵, 可能还有人不相信软键盘如此容易实现, 所以笔者提供了一个小的软键盘例子演示如何解决上面两个问题。 这个例子很简单, 包含main.cpp和mainwin.*代表qte的server进程, 而imframe.*则是QWSInputMethod的派生类, inputwidget.*则是软键盘窗体。 程序里还用到了以前blog中介绍的QSignalMapper类, 如果对此类不熟悉的同学看看这篇帖子扫扫盲。 其他不明白的可以blog或bbs留言。

imframe.tar

QWSInputMethod派生类还应该去实现updateHandler虚函数,该虚函数是输入法框架和输入法之间的桥梁, 专门向输入法发送一些状态信息, 比如在焦点离开或进入编辑框时updateHandler函数就会被调用到, 在这里加入你的输入法的处理可以实现在适当时机显示或隐藏输入法widget等功能。 笔者的例子里也重写了这个函数, 但没写什么实用的功能,只是加了输入法的清空操作。 (懒了,不想写code)

本例子基于QtEmbedded 4.5 开发,可以在qvfb环境运行。 其他版本的输入法程序架构类似, 只是QWSInputMethod类的API差别可能会比较大,以各个版本的文档为准。

上面介绍的是最简单的软键盘输入法, 如果你要实现一个像scim那样的键盘输入法或者触摸屏手写输入法则要复杂得多, 最重要的是如何在焦点窗体之前接收用户的输入, 这里就要用到QWSInputMethod::filter虚函数。 这里不打算对输入法做过多的介绍了, 大家多看文档。 如果看遍文档仍然有弄不明白的地方, 这时你就需要找个好例子了。 推荐个Qtopia带的输入法, 在Qtopia或QtExtended源码包的src/3rdparty/plugins/inputmethod/pkim目录下可以找到pkim输入法, 该输入法功能非常完善, 既有键盘输入法又有手写输入法, 所以是个极佳的开发蓝本。 使用qte2和qte3的同学可以参考qtopia2带的输入法插件。

]]> http://www.cuteqt.com/blog/?feed=rss2&p=889 12 http://www.cuteqt.com/blog/?p=846 http://www.cuteqt.com/blog/?p=846#comments Wed, 29 Jul 2009 02:41:11 +0000 qpang http://www.cuteqt.com/blog/?p=846 <![CDATA[

只是一个简单的小问题的说明,是由本菜菜的毕业设计中遇到的问题得到启发的,也许对你有帮助和启示。
对于开源的中文字体,不得不感谢伟大的房骞骞大神,正式由于她开创了文泉驿项目,才使得我们在嵌入式linux开发中有了优美的文泉驿正黑字体,尽管有少许的缺点,但不能掩盖文泉驿正体的优点和其开源的特性。
在开发过程中,我首先采用了QtEmbedded4.4.3版本,在qvfb模拟中运行时设定
-font wenquanyi,就这样就可以采用文泉驿正黑字体,而在该版本中lib/fonts下已经自带有了文泉驿的qpf字体文件,因此我们并不用过分关心字体的生成。
其后,QtQtEmbedded4.5系列版本发布了,问题就产生了,我再次使用相同的办法在qvfb中运行,却显示乱码。这是为什么呢?原来在QtEmbedded4.5系列版本中,不再带有文泉驿字体,因此再次选用就不行了。
原来QtQtEmbedded4.5中不再带有文泉驿字体,于是我想到了一个办法,将4.4.3版本中的文泉驿的qpf文件拷贝过来使用。结果,当然是成功了,而且在开发板中也可以使用,正常地显示中文。
对于嵌入式linux下的qt开发,中文显示一直是个难点,希望我这个小问题的解决过程对大家的开发有所启示。

]]> http://www.cuteqt.com/blog/?feed=rss2&p=846 3 http://www.cuteqt.com/blog/?p=770 http://www.cuteqt.com/blog/?p=770#comments Mon, 20 Jul 2009 07:23:58 +0000 qpang http://www.cuteqt.com/blog/?p=770 <![CDATA[

这篇下隔了好几天才出来,这是因为本菜菜去了下北京,在北京可谓是收获非凡。

不仅bug大叔请俺和shiroki吃了饭,还见到了传说中的nokia的qtsoftware的技术顾问——Qt Everywhere的博主。不过据说,被我雷到了…

不扯题外话了,在下里本菜菜会者重讲解嵌入式特有的参数,对于开发来说,这些参数相当重要,细微的区别就要可能造成出现一堆不知原因的问题。

下面,就针对每个参数来讲解:

-xplatform target

相当浅显的参数,即交叉编译的目标平台,一般来说根据你所要移植的目标板来确定。

-no-feature-<feature>
-feature-<feature>

选取qte的feature编译,对于这个,我理解为特性,特性的描述你可以参考src/corelib/global/qfeatures.txt,在这里面对于每个特性都有比较充分的讲解。对于特性地选择,也是要根据开发需求进行,如果裁剪适当,能大大为qte库瘦身。

-embedded <arch>

嵌入式平台架构选择,可以选择arm,mips,x86及generic,视你的目标平台决定吧。

-armfpa
-no-armfpa

这个参数也只是针对ARM平台的,是否加入对于基于ARM的浮点数格式的支持,通常,这个参数在编译时会自动选择。

-little-endian
-big-endian

目标平台的大端和小端选择,这应该是常识了,如果这不知道,就不要来混嵌入式了

-host-little-endian
-host-big-endia

主机平台的大端和小端选择,属于鸡肋的参数,不选择也会在配置时自动选择。

-no-freetype
-qt-freetype
-system-freetype

选择freetype,FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,在嵌入式开发中,有套可使用的字体对于中文开发至关重要,本人一般使用文泉驿字体。

-qconfig local

使用本地的qconfig配置文件来替代全部参数配置,有需要的可以去研究下,可以裁剪控件级别的参数。

-depths <list>

显示的像素位深,也是根据需要来进行吧。

-qt-decoration-<style>
-plugin-decoration-<style>
-no-decoration-<style>

这个是选择qt的样式风格,对于需要美化界面的项目来说,可以好好选择下。

-no-opengl
-opengl <api>

是否加入opengl的支持,OpenGL是个专业的3D程序接口,是一个功能强大,调用方便的底层3D图形库。不过对于一般的开发来说,似乎有很少用到的地方。

-qt-gfx-<driver>
-plugin-gfx-<driver>
-no-gfx-<driver>

这个是相当重要的一个参数,选择QtGui的图形显示驱动,比如我们在pc上使用qvfb模拟时,就应该加入对qfvb的支持。我们可以在linuxfb,transformed,qvfb,vnc,multiscreen这几个中选择。在平常的开发板上,选择linuxfb即可。

-qt-kbd-<driver>
-plugin-kbd-<driver>
-no-kbd-<driver>

选择键盘的驱动支持,可以支持usb键盘,串口键盘等等,也是在tty,usb ,sl5000, yopy, vr41xx ,qvfb中选择。

qt-mouse-<driver>
-plugin-mouse-<driver>
-no-mouse-<driver>

鼠标的驱动支持,一般都会选择tslib,可以完美地支持触摸屏,在pc,bus,linuxtp,yopy,vr41xx,tslib,qvfb中选择吧。

-iwmmxt

加入iWMMXt指令的编译,也只是部分XScale架构才具有。

-no-glib
-glib

是否加入glib库的支持,glib库对应即gtk库,就也是说加入后可以使用gtk。

至此,所有qte的参数介绍完成了,对于qt,其参数是共通的,学习好一个版本的参数,其他版本的配置也能很快上手。

]]> http://www.cuteqt.com/blog/?feed=rss2&p=770 0 http://www.cuteqt.com/blog/?p=759 http://www.cuteqt.com/blog/?p=759#comments Sat, 18 Jul 2009 00:22:04 +0000 臭虫 http://www.cuteqt.com/blog/?p=759 <![CDATA[

Qt代码版本:qt-embedded-linux-opensource-src-4.5.2
在上篇中,我们提到了
src/gui/embedded/qmousedriverfactory_qws.cpp 中
QMouseDriverFactory::create(…)函数加载一个QMouseHandler的地方,那么我今天就接着地方往下讲,我们以tslib为例来讲解

133 #ifndef QT_NO_QWS_MOUSE_TSLIB 134 if (driver == QLatin1String("tslib") || driver.isEmpty()) 135 return new QWSTslibMouseHandler(key, device); 136 #endif

要使135行的QWSTslibMouseHandler能够正常被加载,需要注意两个条件
1. 就是133行的那个宏,如果你在编译Qt-Embedded的时候没有加“-qt-mouse-tslib”选项的话,那么该宏会被使能,那么134,135自然不会被编译咯。
当然,如果你编译Qt-Embedded的时候,使用“-plugin-mouse-tslib”,那么下面的代码

142 #if !defined(Q_OS_WIN32) || defined(QT_MAKEDLL) 143 #ifndef QT_NO_LIBRARY 144 if (QWSMouseHandlerFactoryInterface *factory = qobject_cast(loader()->instance(driver))) 145 return factory->create(driver, device); 146 #endif 147 #endif

会去插件目录下找到对应的代码,不是我们要要讨论的重点。
2. 134行的driver名字来自于QWS_MOUSE_PROTO环境变量中的冒号前那一部分.例如”tslib:/dev/ts”中tslib就是driver,/dev/ts就是device。 名字不能搞错:)

如果前面两部分都没有问题,可以进入实现代码看看了
src/gui/embedded/qmousetslib_qws.cpp

320 QWSTslibMouseHandler::QWSTslibMouseHandler(const QString &driver, 321 const QString &device) 322 : QWSCalibratedMouseHandler(driver, device) 323 { 324 d = new QWSTslibMouseHandlerPrivate(this, device); 325 }

看来默默无闻的做着后勤工作的还是QWSTslibMouseHandlerPrivate

136 QWSTslibMouseHandlerPrivate::QWSTslibMouseHandlerPrivate(QWSTslibMouseHandler *h, 137 const QString &device) 138 : handler(h), dev(0), mouseNotifier(0), jitter_limit(3) 139 { 140 QStringList args = device.split(QLatin1Char(':'), QString::SkipEmptyParts); //.............. 148 devName = args.join(QString()); 150 if (devName.isNull()) { 151 const char *str = getenv("TSLIB_TSDEVICE"); 152 if (str) 153 devName = QString::fromLocal8Bit(str); 154 } 156 if (devName.isNull()) 157 devName = QLatin1String("/dev/ts"); 159 if (!open()) 160 return; 165 mouseNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); 166 connect(mouseNotifier, SIGNAL(activated(int)),this, SLOT(readMouseData())); 168 }

一些不重要的代码被我删掉了,通过上面代码可以明白,如果在QWS_MOUSE_PROTO没写设备名,还可以通过环境TSLIB_TSDEVICE得到,如果TSLIB_TSDEVICE也没有设置,那么就会使用设备/dev/ts,你需要搞清你的驱动建立的设备名是什么。
165,166行是关键的两行,这表明Qt会通过QSocketNotifier监视你的鼠标设备上是否有新的数据传入,如果有则通过readMouseData()读取数据。

226 void QWSTslibMouseHandlerPrivate::readMouseData() 227 { //............ 285 if (calibrated) { 286 // tslib should do all the translation and filtering, so we send a 287 // "raw" mouse event 288 handler->QWSMouseHandler::mouseChanged(p, pressed); 289 } else { 290 handler->sendFiltered(p, pressed); 291 } 292 } 293 }

readMouseData()中大部分代码都是读取鼠标数据的,我们更关心把数据送到哪里去,那么我们看290行的sendFilterer(…)
src/gui/embedded/qmouse_qws.cpp

604 bool QWSCalibratedMouseHandler::sendFiltered(const QPoint &position, int button) 605 { //....... 642 643 mouseChanged(transform(pos), button); 644 sent = true; //....... 651 } 在我快没有耐心的时候终于看到了我想看到的代码 259 void QWSMouseHandler::mouseChanged(const QPoint &position, int state, int wheel) 260 { 261 mousePos = position + d_ptr->screen->offset(); 262 QWSServer::sendMouseEvent(mousePos, state, wheel); 263 }

在这里把鼠标事件正式交给QWSServer,感兴趣的话可以接着往下跟踪,应该会进入Qt的事件处理。

0 0