jerrywu75的笔记 https://bbs.21ic.com/?62511 [收藏] [复制] [RSS]

日志

嵌入式linux新手入门手记-解决QT应用程序不响应触摸屏的问题

已有 2125 次阅读2015-8-6 09:23 |个人分类:嵌入式开发|系统分类:嵌入式系统| qt应用程序, 嵌入式, linux

    前面我用arm-linux-gnueabihf-readelf -d qtdemo已经检查过,程序已经包含使用libts.so共享库,但是运行qtdemo时点击触摸屏没有响应。

    qt的网站上看都通过设置QT_PLUGIN_PATH来加载共享库,但是设置后没有解决问题。

    后来上网查到,能够设置qt的运行环境变量export QT_DEBUG_PLUGINS=1,来在运行qt程序时,在超级终端打印输出信息。

    1、知道qt程序是通过qt5.4.1开发包中的libqtslibplugin.so(generic plugin库的一种)libts.so通信的,首先确认armnfs系统中是否存在需要的这些库,并路径设置是否正确。

    2、发现库都对,并路径设置也是对的。

    3、添加QT_DEBUG_PLUGINS后,启动qtdmeo时,查看minicom超级终端上的打印信息,发现只laodlinuxfb库,没有加载libqtslibplugin库,但是库的版本,路经设定都是对的,所以决定检查qt5.4.1运行库加载共享库的过程。

    4、基于guiqt程序启动时,需要初始化gui类,在gui的初始化过程中,会在init_platform函数中加载platform库,在init_plugins函数中加载generic plugins库,并最终是通过source/qtbase/src/corelib/plugin/qfactorylaoder.cpp来加载共享库:

        void QFactoryLoader::update()

        {

        #ifdef QT_SHARED

            Q_D(QFactoryLoader);

            QStringList paths =QCoreApplication::libraryPaths();

            for (int i = 0; i < paths.count(); ++i) {

                const QString &pluginDir = paths.at(i);

                // Already loaded, skip it...

                if (d->loadedPaths.contains(pluginDir)) continue;

                d->loadedPaths << pluginDir;

                 QString path = pluginDir + d->suffix;

                qDebug()<<"load at directory:"<<path; //增加这行代码,将加载插件时的搜索路径打印出来

                if(qt_debug_component())

                    qDebug() <<"QFactoryLoader::QFactoryLoader() checking directory path" <<path << "...";

                if(!QDir(path).exists(QLatin1String(".")))

                    continue;

                 QStringList plugins = QDir(path).entryList(QDir::Files);

                QLibraryPrivate *library = 0;

    进入到./source/qtbase/src/corelib目录下,执行make编译corelib,结束后,将./source/qtbase/lib目录下新的libQt5Core相关6个文件拷贝到armnfs文件系统中的opt/qt541arm/lib目录下,覆盖原来的core库文件。

    重新运行qtdemo,发现超级终端打印出信息,在加载generic plugins共享库时,是在/qt541arm/plugins/platforms/generic目录下寻找库文件的,这显然是错误的。在Qt5.4.1默认的make install安装中,generic plugins库的目录是:/qt541arm/plugins/generic。(在这里,考虑将generic目录以及文件直接拷贝到/platforms目录下,不过我还没有这样尝试)

    由于在QT的官网上查到的设置QT_PLUGIN_PATH环境变量的方法没有解决问题,所以决定自己改qt5.4.1的源程序。

    不过这里不能修改corelibqfactoryloader.cpp,由于generic plugins是由gui加载的,所以我们需要找到gui的源程序中加载generic

plugins库的代码。gui是在qguiapplication.cpp中调用qgenericpluginfactory.cppQGenericPluginFactory::create来加载generic plugins共享库,在./source/qtbase/src/gui目录下打开qgenericpluginfactory.cpp

        Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader,loader,(QGenericPluginFactoryInterface_iid,QLatin1String("/generic"), Qt::CaseInsensitive))

    上面的宏将corelib中的QFactoryLoader映射到loader,然后QGenericPluginFactory::createQObject *QGenericPluginFactory::create(const QString& key, const

QString &specification)

        {

            const QString driver = key.toLower();

         #if !defined(Q_OS_WIN32) || defined(QT_SHARED)

        #ifndef QT_NO_LIBRARY

            if (QObject *object = qLoadPlugin1<QObject, QGenericPlugin>(loader(), driver, specification))

                return object;

        #endif

        #endif

            return 0;

        }

    QGenericPluginFactory::create中,调用corelibloaderQFactoryLoader,查找key指定的共享库,并加载。

    显然路径是上面的宏传递到core去的:QLatin1String("/generic")。而在corelibqfactoryloader中,是将这个路径直接加到corelib默认路径上的。

    由于在gui初始化时,先调用platform的库加载函数,然后再调用generic plugins库的加载函数,导致core默认的路径是由QT_QPA_PLATFORM_PLGUIN_PATH来设置,所以这里gui加载generic plugins的路径就变成了QT_QPA_PLATFORM_PLGUIN_PATH/generic,这显然是错误的。

    修改上面的宏:

        Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader,loader,(QGenericPluginFactoryInterface_iid,QLatin1String("/../generic"), Qt::CaseInsensitive))

        QLatin1String("/generic")修改为QLatin1String("/../generic")

    然后进入到./source/qtbase/src/gui目录中,执行make重新编译gui库。结束后,将./source/qtbase/lib目录下的libQt5Gui相关的6个文件拷贝到armnfs文件系统中的qt541arm/lib目录中。

    然后重新启动qtdemo程序,这时发现minicom超级终端显示出找到TslibTslibRaw插件,并加载Tslib插件。程序最终加载2个共享库文件:libqlinuxfblibqtslibplugin。屏幕上显示出qtdemo的对话框,点击触摸屏,发现qtdemo相应的执行了动作。

    到此,就完成了Qt5.4.1tslib移植到am335xlinux kernel 3.2.0的工作。

    不过现在qt还有一个bug,就是在启动qt应用程序前,或者运行中,usb触摸屏设备故障后又自动恢复,qt应用程序时不能再次响应触摸屏事件。必须要退出qt应用程序,再次重新启动qt应用程序,才能够再次响应触摸屏事件。这对于工业控制的应用,就是一个很大的问题。下一篇笔记将讲述这个问题的解决过程。


(原创文章,转载请注明出处)

(未经本人同意,不得用于商业用途)


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)