Qt Creator插件制作小插曲:有关QT_NO_CAST_FROM_ASCII的注意事项



  • 这两天制作了两个Qt Creator增强套装的两个插件,其实也是非常简单的,但是其实花了我超过四天的时间,为什么呢?因为我之前很长一段时间都是在Linux下开发的,一切安好,没有任何问题,但是到了Windows下,各种问题就暴露出来了。首先呢,就是——

    1、Qt Creator源码中,默认是打开QT_NO_CAST_FROM_ASCII这个宏的,看文档,这个宏就是禁用一切来自双引号或者单引号的字符串字面量传入QString的函数。但是我们裸写字符串不是非常平常的一件事情么?这里是Qt Creator断了我们一条道路,解决的方法还是有的,我这里提供两个方法,欢迎提出新的方法:

    include($$QTCREATOR_SOURCES/src/qtcreatorplugin.pri)
    

    这一句后面添加

    DEFINES -= QT_NO_CAST_FROM_ASCII
    

    如果还有必要的话,那么还需要添加

    DEFINES -= QT_NO_CAST_TO_ASCII
    

    这些都是解除设定宏的好方法

    1. 使用QStringLiteral宏来包裹字面量
      我还设计了两个宏,分别对应识别单个字符和字符串。他们分别是:
    #define CHAR( c ) QChar( ushort( c ) )
    #define TEXT QStringLiteral
    

    这些都是非常方便的宏,可以很方便地替换掉裸写的字面量。

    2、由于Windows下编译器有MinGW以及MSVC,我们要注意我们编写的插件是C++插件,是编译器相关的,比如说,MinGW编写的插件无法在MSVC编译器编译的Qt Creator上使用。遗憾的是,Qt Creator官方编译的都是MSVC的,而且有一个现象,不同的MSVC版本编写的Qt Creator依赖的Qt库,有一些函数的地址还不能通用。比如说和上面一个例子非常相似的例子,那就是我使用MSVC2015编译的Qt Creator插件,其中用到了QString::utf8()函数,但就是这个函数,无法在官方MSVC2013编译的Qt Creator中成功载入,提示“无法找到模块”。为什么呢?看看QString::utf8()函数源码吧:

    #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
        QByteArray toLatin1() const & Q_REQUIRED_RESULT
        { return toLatin1_helper(*this); }
        QByteArray toLatin1() && Q_REQUIRED_RESULT
        { return toLatin1_helper_inplace(*this); }
        QByteArray toUtf8() const & Q_REQUIRED_RESULT
        { return toUtf8_helper(*this); }
        QByteArray toUtf8() && Q_REQUIRED_RESULT
        { return toUtf8_helper(*this); }
        QByteArray toLocal8Bit() const & Q_REQUIRED_RESULT
        { return toLocal8Bit_helper(constData(), size()); }
        QByteArray toLocal8Bit() && Q_REQUIRED_RESULT
        { return toLocal8Bit_helper(constData(), size()); }
    #else
        QByteArray toLatin1() const Q_REQUIRED_RESULT;
        QByteArray toUtf8() const Q_REQUIRED_RESULT;
        QByteArray toLocal8Bit() const Q_REQUIRED_RESULT;
    #endif
    

    看出来什么吗?不同的预编译宏会导致不同版本的toUtf8()函数被编译,难怪Qt Creator发现QString::utf8()函数和自己Qt库中的这个函数地址不一致会报“无法找到模块”错误呢。

    那,有没有解决的方法呢?由于Json格式化,一定要这样的函数,因此我打算看看它的源码,是否能够找到替代的实现方法。没错,就是

    toUtf8_helper(*this);
    

    中,我找到了

    QUtf8::convertFromUnicode()
    

    方法
    终于找到了这个方法,又偶然发现QTextCodec::fromUnicode()函数中隐含调用了上述函数,于是我这么操作:

        QTextCodec* utf8Codec = QTextCodec::codecForName( "UTF-8" );
    
        QString plainText = ui->jsonEdit->toPlainText( );
        QByteArray converted = QJsonDocument::fromJson( utf8Codec->fromUnicode( plainText ) ).
                toJson( QJsonDocument::Indented );
        plainText = utf8Codec->toUnicode( converted );
    

    顺利实现效果!

    开发Qt Creator的过程中,每一步都是一个坑。但万变不离其宗,只要你有耐心,找到规律,找到核心问题,相信你一定和我一样,最终会找到问题的答案的。



  • @jiangcaiyang123Qt Creator插件制作小插曲:有关QT_NO_CAST_FROM_ASCII的注意事项 中说:

    plainText

    1. plainText 是一个编码 不是字符呢????
      怎么合适的方法转成 QByteArray,再 toUnicode( converted );
    2. 一定要DEFINES -= QT_NO_CAST_FROM_ASCII


  • @jiangcaiyang123Qt Creator插件制作小插曲:有关QT_NO_CAST_FROM_ASCII的注意事项 中说:
    //编码=0xcb9d,编号
    QTextCodec 能把GB2312任意编码转换成 Unicode编码吗?
    还是只能 由Unicode编码找到GB2312编码?
    也就是说只能 一个汉字 QString s="字";Qt存储为Unicode,QTextCodec::codecForName( "GB2312" ); fromUnicode,Unicode编码 装成了 GB2312编码,

    这样的话 由GB2312编码 转换成 Unicode编码 只能通过查表了吗????

    也就是说
    Unicode 提取区位码 可以找到 GB2312 编码;
    而由 GB2312 编码 不能反查 区 位码, 找到Unicode编码???

    也就是说 x+y=z 求z 只有一个解
    但是 z= x+y 求 x,y 可以有多种组合????



  • 那么 QTextCodec::toUnicode 做了些什么事情呢???

    QJsonDocument是5.0以上的 4.7 还用不了?
    Header:
    #include <QJsonDocument>
    qmake:
    QT += core
    Since:
    Qt 5.0



  • @MOMO QTextCodec是可以将一种编码转换为unicode,然后再转换为另外一种编码格式。



  • @MOMO 现在4.7不用了,尽量迁移到5吧。因为最新的是5.7了。


Log in to reply
 

最近的回复

  • 就在不久前我分享了USD在Windows上的构建方法,其实我也一直没有放弃在开发领域最擅长的Linux中构建USD。不过,在Linux中要成功地构建USD,比Windows的要难不少。尤其是各种麻烦的依赖库,仍然要解决才行。之前一直在CentOS 7构建,没有成功,而且CentOS构建的话,相关的资料更少,坑更多,而Deepin是国产的Linux桌面系统,友好一些,这样可以少一些困难。目前成功地在Deepin Linux上顺利地编译成功了。

    那么,咱们开始在Linux构建USD吧。

    测试并且安装Python

    有些Linux发行版,默认安装了Python,有的则没。如果你安装了Python,可以测试一下,命令是:

    python --version

    如果报错,那么使用apt安装吧。

    sudo apt install python

    为了安装PyOpenGL等库,还是推荐安装pip。有关安装pip的资料还是挺多的,pip类似npm,是一个包管理器,非常方便,推荐安装。这里有一个获取pip的脚本。我发出来。获取pip的命令是:

    python -m get-pip.py

    拿到USD的代码

    毕竟是在github中获取的USD代码,那么最好安装git,并且设置github的账户以及公钥。然后熟练利用git命令进行如下的操作:

    git clone https://github.com/PixarAnimationStudios/USD

    获取USD依赖的库

    由于依然在github上获取相关的库,获取库的速度大家都知道比较慢,于是我将库上传到我创建的USD小组里了,大家感兴趣的话,可以加入这个QQ群(小组),获取相关的库,然后解压之。
    上海USD小组

    获取USD其它的依赖(包括cmake)

    由于Linux开源的特性,很多底层的库都要到包管理器中寻找,如果编译出错了。记得勤用apt来搜索相关的库。命令是:

    apt search cmake
    pip install pyside2

    值得注意的是,USD在19.11的时候,明确说不支持cmake2了,看来大家要在apt中安装cmake3了。

    编译

    USD在Linux的编译和Windows的差不多,差别在于一个是用Shell脚本,另外一个是用bat脚本。这里我将Shell脚本贴出来给大家参考:

    #!/bin/sh # 最后构建USD项目 baseDir=${baseDir:=$(cd `dirname $0`; pwd)} echo $baseDir pushd $baseDir sudo python $baseDir/USD/build_scripts/build_usd.py -j 4 -v --python --build-args=USD,"-DPYSIDE_USE_PYSIDE2=TRUE -DPYSIDE_BIN_DIR=/usr/local/lib/python2.7/dist-packages/PySide2 -DBOOST_LIBRARYDIR=" /usr/local/USD popd 编译可能遇到的问题 权限问题。这个是最常见的了。Windows的权限问题没有那么严重,而Linux是权限everywhere。于是安装USD的时候,它推荐的位置是/usr/local/USD,这个地方是要权限的。所以记得用sudo,没有设置密码的赶紧用passwd root设置密码了。 遇到找不到编译器的问题。很简单,没有安装编译器呗。Linux默认编译器是g++,所以一定要执行

    sudo apt install g++

    这样才能够解决找不到编译器的问题。同样的,如果想要以后对USD进行调试,那么gdb也是必不可少的,推荐一同安装。

    编译完成

    如果你到了这一步,那么非常恭喜,你已经克服了超多的难关,到达了胜利的彼岸。但是不是要测试一下是否成功地运行了USD呢?我们还是要运行一下USDView来测试一下的嘛。于是我们还是要写一段shell脚本来测试USDView的运行情况:

    #!/bin/sh export LD_LIBRARY_PATH=/usr/local/USD/lib64:$LD_LIBRARY_PATH export PYTHONPATH=$PYTHONPATH:/usr/local/USD/lib/python /usr/local/USD/bin/usdview /media/jiangyimin/Data/models/UsdSkelExamples/HumanFemale/HumanFemale.walk.usd

    由于要寻找库的路径,因此记得及时设置LD_LIBRARY_PATH环境变量。如果一切顺利的话,那么会出现这样的效果:Linux运行USDView

    read more
  • 记住了哦,USD不是咱们所说的美元哦,是迪士尼皮克斯工作室推出的一款动画全流程的工具,简单地说,是用来串流程的,USD的使用借鉴了脚本编程的一些思想,让动画的资产变得可配置,也变得可维护。让同时其提出的几个工具,使得它变成一个较为完整的工具链。
    USD的官方网站(开源)在这里。

    https://openusd.org

    接下来我将告诉大家如何在Windows下构建USD。

    安装Python

    首先呢,是安装USD的依赖项。USD的依赖项挺多,最重要的是Python,因为USD的构建脚本就是用Python写的。所以去Python官网下载Python吧,目前测试成功的是Python2.7。当然你也可以安装Python 3.5,只是我没有测试过,不清楚是否可用。Python的下载地址是:

    https://www.python.org/downloads

    一般来说,安装好了Python,它会给你设置环境变量,或者有一些教程让你们设定环境变量,不过呢,这里我不建议设定环境变量,这样让我们的所有软件运行环境都污染了(可能没有什么事),之后我会写一个脚本来教大家如何书写批处理来让简化操作,真正做到“即用即走”。

    下载Visual Studio 2017

    这不用强调了吧。目前VS2017是必备的软件了,而且有免费社区版,再也不用破解了,赶紧下载一个。安装在合适的位置就好了。

    安装Maya 2018

    一般来说,Maya每年都有发布一个版本,但是2018的格外稳定,推荐安装。为什么要安装Maya呢?因为Maya是一款几乎全能的DCC,可以导出很多模型到USD中,所以USD顺便构建了Maya的插件(这个插件名字叫usdMaya,不过核心代码转到了Autodesk里了,详见https://github.com/Autodesk/maya-usd,此插件除了PXR的USD,还有AL的USD),我也将Maya 2018放在了我们讨论小组群中,大家可以下载。
    USD研究小组.jpg
    我将Maya 2018安装到D:\Develop\Autodesk\Maya2018中。

    安装USD的其余依赖项

    由于USD的python脚本会使用curl或者是powershell的下载功能进行下载,但是由于很多依赖项是从github下载的,下载速度实在是太慢了,所以我将其余的依赖项打包好了,放在USD_dependencies文件夹中,供需要的朋友下载。USD的依赖项已经上传到我们讨论小组群群里了,大家可以下载。
    USD研究小组.jpg

    编写构建USD的脚本

    我的USD安装的位置是D:\Develop\USD,打算安装的位置是D:\Develop\USD_build_19_11,根据这两个路径开始编写构建USD的脚本:

    :: 构建USD的脚本 :: 设置编译器的很多环境变量 set Path=D:\Develop\Python27;^ D:\Develop\Python27\Scripts;^ D:\Develop\NASM;^ D:\Develop\Autodesk\Maya2018\bin;^ D:\Develop\cmake\bin;^ %Path% set PYTHONPATH=%PYTHONPATH%;D:\Develop\Autodesk\Maya2018\Python\Lib\site-packages;D:\Develop\Autodesk\Maya2018\Python\Lib\site-packages :: 复制pyside2-uic到pyside-uic.exe 中,使其造成能够找到pyside2-uic.exe的假象 copy D:\Develop\Autodesk\Maya2018\bin\pyside2-uic D:\Develop\Autodesk\Maya2018\bin\pyside2-uic.exe :: 使用pip安装PyOpenGL pip install PyOpenGL :: 复制本地build_usd_local.bat 到 目标的路径上 copy /Y %cd%\build_usd_local.py D:\Develop\USD\build_scripts call D:\Develop\VS2017\VC\Auxiliary\Build\vcvars64.bat :: 最后构建USD项目 python D:\Develop\USD\build_scripts\build_usd_local.py ^ -j4 ^ --build-args "USD,-DPYSIDE_USE_PYSIDE2=TRUE -DPYSIDE_BIN_DIR=D:\Develop\Autodesk\Maya2018\bin" ^ --maya --maya-location "D:\Develop\Autodesk\Maya2018\bin" ^ --materialx ^ D:\Develop\USD_build_19_11 :: 最后删除build_usd_local文件 del D:\Develop\USD\build_scripts\build_usd_local.py pause

    大家成功了吗?肯定有遇到很多问题,包括我遇到的一直卡住的Boost编译问题。大家遇到什么编译问题,可以在此留言,我会尽可能回答大家问题。

    成功编译USD后,可以编写插件来试试USDView,大家可以试试看吧,不过仍然要设置环境变量。USDView运行的脚本如下:

    set Path=^ D:\Develop\Python27;^ D:\Develop\USD_Build\lib;^ D:\Develop\USD_Build\bin;^ D:\Develop\USD_Build\third_party\maya\lib;^ D:\Develop\Autodesk\Maya2018\bin;^ %Path% set MAYA_PLUG_IN_PATH=%MAYA_PLUG_IN_PATH%;^ D:\Develop\USD_Build\third_party\maya\plugin set PYTHONPATH=%PYTHONPATH%;^ D:\Develop\USD_Build\lib\python;^ D:\Develop\Autodesk\Maya2018\Python\Lib\site-packages set MAYA_SCRIPT_PATH=%MAYA_SCRIPT_PATH%;^ D:\Develop\USD_Build\third_party\maya\lib\usd\usdMaya\resources;^ D:\Develop\USD_Build\third_party\maya\plugin\pxrUsdPreviewSurface\resources set XBMLANGPATH=%XBMLANGPATH%;^ D:\Develop\USD_Build\third_party\maya\lib\usd\usdMaya\resources @python "D:\Develop\USD_Build\bin\usdview" %cd%\7_29_1.usda

    USDView运行的截图是这样的:
    USDView运行效果

    看到最终结果,还是很有成就感的。

    read more
  • @天幸健 要么程序一启动就camera.start(),然后再camera.stop(),接着需要的时候再camera.start()。

    read more
  • @jcy 我现在程序一启动就加载了Camera 组件,但是当我要启动摄像头时,调用camera.start() 还是会卡一下

    read more

关注我们

微博
QQ群