明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 346|回复: 7

ObjectARX 使用vcpkg ,基于 WxWidgets 静态库界面开发

  [复制链接]
发表于 3 天前 | 显示全部楼层 |阅读模式
本帖最后由 枫叶棋语 于 2025-6-25 15:11 编辑


1. vcpkg 安装 wxwidgets, 命令  vcpkg install wxwidgets:x64-windows-static-md  --editable,几分钟时间安装完成,至于为什么选择x64-windows-static-md ,自行百度,静态编译,动态运行;

2. 添加项目配置文件Directory.Build.props ,与解决方案同级目录,配置文件中设置xrc 文件自动编译加载
配置文件如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  3.   <!-- 基础属性配置 -->
  4.   <PropertyGroup Label="Globals">
  5.     <SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
  6.     <ProjectName>$(MSBuildProjectName)</ProjectName>
  7.     <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
  8.     <PrecompiledHeaderOutputFile>$(IntDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>


  9.     <!-- VCPKG 配置 -->
  10.     <VcpkgEnabled>true</VcpkgEnabled>
  11.     <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static-md</VcpkgTriplet>
  12.     <VcpkgApplocalDeps>false</VcpkgApplocalDeps>
  13.     <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  14.     <PlatformToolset>v143</PlatformToolset>
  15.     <CharacterSet>Unicode</CharacterSet>
  16.     <TreatWarningAsError>false</TreatWarningAsError>

  17.     <!-- WXRC 工具路径 -->
  18.     <WXRC_ToolPath>C:\vcpkg\installed\x64-windows-static-md\tools\wxwidgets\wxrc.exe</WXRC_ToolPath>

  19.     <!-- XRC 输出目录 -->
  20.     <XrcOutputDir>$(Platform)\$(Configuration)\xrc\</XrcOutputDir>
  21.     <XrcOutputHeader>$(XrcOutputDir)%(Filename).h</XrcOutputHeader>
  22.     <XrcOutputSource>$(XrcOutputDir)%(Filename).cpp</XrcOutputSource>

  23.     <!-- ObjectARX 路径配置 -->
  24.     <ObjectARX_Root>C:\ObjectARX\2024</ObjectARX_Root>
  25.     <ObjectARX_Lib>$(ObjectARX_Root)\lib-x64</ObjectARX_Lib>
  26.     <ObjectARX_Inc>$(ObjectARX_Root)\inc</ObjectARX_Inc>
  27.     <ObjectARX_Inc_x64>$(ObjectARX_Root)\inc-x64</ObjectARX_Inc_x64>

  28.     <!-- 公共包含目录 -->
  29.     <CommonIncludePaths>
  30.       $(SolutionDir)Stdafx;
  31.       $(SolutionDir)ArxStatic;
  32.       $(ObjectARX_Inc);
  33.       $(ObjectARX_Inc_x64);
  34.       $(XrcOutputDir);
  35.       %(AdditionalIncludeDirectories)
  36.     </CommonIncludePaths>

  37. <!-- 系统库定义 -->
  38.     <WindowsSystemLibs>
  39.       vcruntime.lib;
  40.       user32.lib;
  41.       winmm.lib;
  42.       rpcrt4.lib;
  43.       comctl32.lib;
  44.     </WindowsSystemLibs>
  45.     <!-- ObjectARX 依赖库 -->
  46.     <ArxLib>
  47.       ac1st24.lib;acad.lib;acapp.lib;acapp_crx.lib;AcCamera.lib;
  48.       accore.lib;acdb24.lib;acdbmgd.lib;AcDbPointCloudObj.lib;
  49.       AcDrawBridge.lib;AcFdEval.lib;AcFdUi.lib;acge24.lib;
  50.       AcGeolocationObj.lib;acgeoment.lib;acgiapi.lib;acismobj24.lib;
  51.       AcJsCoreStub_crx.lib;acModelDocObj.lib;AcMPolygonObj.lib;
  52.       AcPal.lib;AcPublish_crx.lib;AcSceneOE.lib;AcTc.lib;
  53.       AcTcUi.lib;acui24.lib;AdApplicationFrame.lib;adui24.lib;
  54.       aNav.lib;axdb.lib;rxapi.lib;userdata.lib;
  55.     </ArxLib>
  56.   </PropertyGroup>

  57.   <PropertyGroup>
  58.     <UseIntellisensePCH>false</UseIntellisensePCH>
  59.   </PropertyGroup>

  60.   <!-- 配置特定属性 -->
  61.   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
  62.     <VcpkgUseStatic>true</VcpkgUseStatic>
  63.     <VcpkgUseMD>true</VcpkgUseMD>
  64.     <UseDebugLibraries>true</UseDebugLibraries>
  65.     <PreprocessorDefinitions>
  66.       _DEBUG;_WINSOCKAPI_;wxUSE_SOCKETS=0;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)
  67.     </PreprocessorDefinitions>
  68.   </PropertyGroup>

  69.   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  70.     <VcpkgUseStatic>true</VcpkgUseStatic>
  71.     <VcpkgUseMD>true</VcpkgUseMD>
  72.     <UseDebugLibraries>false</UseDebugLibraries>
  73.     <PreprocessorDefinitions>
  74.       NDEBUG;_WINSOCKAPI_;wxUSE_SOCKETS=0;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)
  75.     </PreprocessorDefinitions>
  76.   </PropertyGroup>

  77.   <!-- 预编译头配置 -->
  78.   <ItemGroup>
  79.     <ClInclude Include="$(SolutionDir)Stdafx\stdafx.h" />
  80.     <ClCompile Include="$(SolutionDir)Stdafx\stdafx.cpp">
  81.       <PrecompiledHeader>Create</PrecompiledHeader>
  82.     </ClCompile>
  83.   </ItemGroup>

  84.   <!-- 全局编译选项 -->
  85.   <ItemDefinitionGroup>
  86.     <ClCompile>
  87.       <LanguageStandard>stdcpp20</LanguageStandard>
  88.       <CLanguageStandard>stdc17</CLanguageStandard>
  89.       <WarningLevel>Level4</WarningLevel>
  90.       <SDLCheck>true</SDLCheck>
  91.       <PrecompiledHeader>Use</PrecompiledHeader>
  92.       <AdditionalOptions>/DNOMINMAX /wd4996 /wd4267 /wd4201 %(AdditionalOptions)</AdditionalOptions>
  93.       <PreprocessorDefinitions>_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
  94.       <AdditionalIncludeDirectories>$(CommonIncludePaths)</AdditionalIncludeDirectories>
  95.       <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MultiThreadedDebugDLL</RuntimeLibrary>
  96.       <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MultiThreadedDLL</RuntimeLibrary>
  97.     </ClCompile>

  98.     <Link>
  99.       <AdditionalLibraryDirectories>$(ObjectARX_Lib);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
  100.       <AdditionalDependencies>$(ArxLib);$(WindowsSystemLibs);%(AdditionalDependencies)</AdditionalDependencies>
  101.       <ModuleDefinitionFile></ModuleDefinitionFile>
  102.       <AdditionalOptions>/EXPORT:acrxEntryPoint /EXPORT:acrxGetApiVersion %(AdditionalOptions)</AdditionalOptions>
  103.       <SubSystem>Windows</SubSystem>
  104.      <IgnoreSpecificDefaultLibraries>
  105.         libcmt.lib;
  106.         libcpmt.lib;
  107.         %(IgnoreSpecificDefaultLibraries)
  108.       </IgnoreSpecificDefaultLibraries>
  109.     </Link>
  110.   </ItemDefinitionGroup>

  111.   <!-- Debug 配置优化选项 -->
  112.   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
  113.     <ClCompile>
  114.       <Optimization>Disabled</Optimization>
  115.       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
  116.       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
  117.       <AdditionalOptions>/ZI /DEBUG %(AdditionalOptions)</AdditionalOptions>
  118.     </ClCompile>
  119.     <Link>
  120.       <LinkIncremental>true</LinkIncremental>
  121.       <GenerateDebugInformation>DebugFull</GenerateDebugInformation>
  122.     </Link>
  123.   </ItemDefinitionGroup>

  124.   <!-- Release 配置优化选项 -->
  125.   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  126.     <ClCompile>
  127.       <Optimization>MaxSpeed</Optimization>
  128.       <IntrinsicFunctions>true</IntrinsicFunctions>
  129.       <FunctionLevelLinking>true</FunctionLevelLinking>
  130.       <EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
  131.       <FloatingPointModel>Fast</FloatingPointModel>
  132.       <OpenMPSupport>true</OpenMPSupport>
  133.       <WholeProgramOptimization>true</WholeProgramOptimization>
  134.     </ClCompile>
  135.     <Link>
  136.       <EnableCOMDATFolding>true</EnableCOMDATFolding>
  137.       <OptimizeReferences>true</OptimizeReferences>
  138.     </Link>
  139.   </ItemDefinitionGroup>

  140.   <!-- XRC 文件处理 -->
  141.   <Target Name="GenerateXrcFiles" BeforeTargets="PreBuildEvent">
  142.     <Message Text="[XRC] Preparing to generate XRC files..." Importance="high"/>
  143.    
  144.     <!-- 创建输出目录 -->
  145.     <MakeDir Directories="$(XrcOutputDir)" Condition="!Exists('$(XrcOutputDir)')" />
  146.    
  147.     <!-- 查找所有 XRC 文件 -->
  148.     <ItemGroup>
  149.       <XrcFiles Include="**\*.xrc"/>
  150.     </ItemGroup>
  151.    
  152.     <!-- 验证 wxrc.exe  存在 -->
  153.     <Error Condition="!Exists('$(WXRC_ToolPath)')"
  154.            Text="[XRC] wxrc.exe  not found at $(WXRC_ToolPath). Please verify wxWidgets installation."/>
  155.    
  156.     <!-- 对每个 XRC 文件执行生成 -->
  157.     <Exec Command=""$(WXRC_ToolPath)" -c -e "%(XrcFiles.FullPath)" -o "$(XrcOutputDir)%(XrcFiles.Filename).cpp""
  158.           Condition="'@(XrcFiles)' != ''"/>
  159.    
  160.     <Message Text="[XRC] Generated %(XrcFiles.Filename) to $(XrcOutputDir)" Importance="high"/>
  161.   </Target>

  162.   <!-- 自动包含XRC生成的CPP文件 -->
  163.   <Target Name="IncludeXrcGeneratedFiles" BeforeTargets="ClCompile">
  164.     <!-- 查找已经存在的XRC生成的cpp文件 -->
  165.     <ItemGroup>
  166.       <ExistingXrcGeneratedCppFiles Include="$(XrcOutputDir)*.cpp" Condition="Exists('$(XrcOutputDir)')"/>
  167.     </ItemGroup>
  168.    
  169.     <!-- 使用CreateItem避免元数据问题 -->
  170.     <CreateItem Include="@(ExistingXrcGeneratedCppFiles)"
  171.                 AdditionalMetadata="PrecompiledHeader=NotUsing">
  172.       <Output TaskParameter="Include" ItemName="FilesToCompile"/>
  173.     </CreateItem>
  174.    
  175.     <!-- 添加到ClCompile项 -->
  176.     <ItemGroup>
  177.       <ClCompile Include="@(FilesToCompile)"/>
  178.     </ItemGroup>
  179.   </Target>

  180.   <!-- 预编译头自动配置 -->
  181.   <Target Name="ConfigurePCH" BeforeTargets="ClCompile">
  182.     <ItemGroup>
  183.       <ClCompile Condition="!$([System.String]::Copy('%(Filename)%(Extension)').Equals('stdafx.cpp'))">
  184.         <PrecompiledHeader>Use</PrecompiledHeader>
  185.         <ForcedIncludeFiles>$(PrecompiledHeaderFile);%(ForcedIncludeFiles)</ForcedIncludeFiles>
  186.       </ClCompile>
  187.     </ItemGroup>
  188.   </Target>

  189.   <!-- 确保 Windows.h 不会覆盖定义 -->
  190.   <Target Name="EnsureNOMINMAX" BeforeTargets="ClCompile">
  191.     <ItemGroup>
  192.       <ClCompile>
  193.         <PreprocessorDefinitions>NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
  194.       </ClCompile>
  195.     </ItemGroup>
  196.   </Target>

  197.   <!-- 清理时删除生成的 XRC 文件 -->
  198.   <Target Name="CleanXrcFiles" AfterTargets="Clean">
  199.     <Message Text="[XRC] Cleaning generated XRC files..." Importance="high"/>
  200.     <ItemGroup>
  201.       <XrcGeneratedFiles Include="$(XrcOutputDir)*.*"/>
  202.       <!-- 从编译项中移除XRC生成的文件 -->
  203.       <ClCompile Remove="$(XrcOutputDir)*.cpp"/>
  204.     </ItemGroup>
  205.     <Delete Files="@(XrcGeneratedFiles)" />
  206.     <RemoveDir Directories="$(XrcOutputDir)" Condition="Exists('$(XrcOutputDir)') AND '@(XrcGeneratedFiles)' != ''"/>
  207.     <Message Text="[XRC] Cleaned XRC files in $(XrcOutputDir)" Importance="high"/>
  208.   </Target>

  209.   <!-- 自动包含资源文件 -->
  210.   <ItemGroup>
  211.     <ResourceCompile Include="*.rc" />
  212.   </ItemGroup>
  213. </Project>
3.  重新编译 wxrc.exe ,至于vcpkg 如何进行修改后重新编译,很简单,
3.1  先卸载 vcpkg remove wxwidgets:x64-windows-static-md  --recurse
3.2 将vcpkg 目录下buildtrees\wxwidgets\src\v3.2.7-90467b189b\utils\wxrc文件夹的     wxrc.cpp 替换掉;
3.3 重新编译
vcpkg install wxwidgets:x64-windows-static-md  --editable ,可以得到一个新的wxrc.exe  ,至于为什么要修改这个工具,自行领会
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        wxrc.cpp
  3. // Purpose:     XML resource compiler
  4. // Author:      Vaclav Slavik, Eduardo Marques <edrdo@netcabo.pt>
  5. // Created:     2000/03/05
  6. // Copyright:   (c) 2000 Vaclav Slavik
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////

  9. // For compilers that support precompilation, includes "wx/wx.h".
  10. #include "wx/wxprec.h"


  11. // for all others, include the necessary headers
  12. #ifndef WX_PRECOMP
  13. #include "wx/app.h"
  14. #include "wx/log.h"
  15. #include "wx/wxcrtvararg.h"
  16. #endif

  17. #include "wx/cmdline.h"
  18. #include "wx/xml/xml.h"
  19. #include "wx/ffile.h"
  20. #include "wx/filename.h"
  21. #include "wx/wfstream.h"
  22. #include "wx/utils.h"
  23. #include "wx/hashset.h"
  24. #include "wx/mimetype.h"
  25. #include "wx/vector.h"

  26. WX_DECLARE_HASH_SET(wxString, wxStringHash, wxStringEqual, StringSet);

  27. class XRCWidgetData
  28. {
  29. public:
  30.   XRCWidgetData(const wxString& vname, const wxString& vclass)
  31.     : m_class(vclass), m_name(vname) {
  32.   }
  33.   const wxString& GetName() const { return m_name; }
  34.   const wxString& GetClass() const { return m_class; }
  35. private:
  36.   wxString m_class;
  37.   wxString m_name;

  38. };

  39. #include "wx/arrimpl.cpp"
  40. WX_DECLARE_OBJARRAY(XRCWidgetData, ArrayOfXRCWidgetData);
  41. WX_DEFINE_OBJARRAY(ArrayOfXRCWidgetData)

  42. class XRCWndClassData
  43. {
  44. private:
  45.   wxString m_className;
  46.   wxString m_parentClassName;
  47.   StringSet m_ancestorClassNames;
  48.   ArrayOfXRCWidgetData m_wdata;

  49.   void BrowseXmlNode(wxXmlNode* node)
  50.   {
  51.     wxString classValue;
  52.     wxString nameValue;
  53.     wxXmlNode* children;
  54.     while (node)
  55.     {
  56.       if (node->GetName() == wxT("object")
  57.         && node->GetAttribute(wxT("class"), &classValue)
  58.         && node->GetAttribute(wxT("name"), &nameValue))
  59.       {
  60.         m_wdata.Add(XRCWidgetData(nameValue, classValue));
  61.       }
  62.       children = node->GetChildren();
  63.       if (children)
  64.         BrowseXmlNode(children);
  65.       node = node->GetNext();
  66.     }
  67.   }

  68. public:
  69.   XRCWndClassData(const wxString& className,
  70.     const wxString& parentClassName,
  71.     const wxXmlNode* node) :
  72.     m_className(className), m_parentClassName(parentClassName) {
  73.     if (className == wxT("wxMenu"))
  74.     {
  75.       m_ancestorClassNames.insert(wxT("wxMenu"));
  76.       m_ancestorClassNames.insert(wxT("wxMenuBar"));
  77.     }
  78.     else if (className == wxT("wxMDIChildFrame"))
  79.     {
  80.       m_ancestorClassNames.insert(wxT("wxMDIParentFrame"));
  81.     }
  82.     else if (className == wxT("wxMenuBar") ||
  83.       className == wxT("wxStatusBar") ||
  84.       className == wxT("wxToolBar"))
  85.     {
  86.       m_ancestorClassNames.insert(wxT("wxFrame"));
  87.     }
  88.     else
  89.     {
  90.       m_ancestorClassNames.insert(wxT("wxWindow"));
  91.     }

  92.     BrowseXmlNode(node->GetChildren());
  93.   }

  94.   const ArrayOfXRCWidgetData& GetWidgetData()
  95.   {
  96.     return m_wdata;
  97.   }

  98.   const wxString GeneratedClassName() {
  99.     return (wxT("XRC_") + m_className);
  100.   }

  101.   bool CanBeUsedWithXRCCTRL(const wxString& name)
  102.   {
  103.     if (name == wxT("tool") ||
  104.       name == wxT("data") ||
  105.       name == wxT("unknown") ||
  106.       name == wxT("notebookpage") ||
  107.       name == wxT("separator") ||
  108.       name == wxT("sizeritem") ||
  109.       name == wxT("wxMenu") ||
  110.       name == wxT("wxMenuBar") ||
  111.       name == wxT("wxMenuItem") ||
  112.       name.EndsWith(wxT("Sizer")))
  113.     {
  114.       return false;
  115.     }
  116.     return true;
  117.   }



  118.   void GenerateHeaderCode(wxFFile& file)
  119.   {
  120.     // 添加前缀到生成的类名
  121.     wxString generatedClassName = GeneratedClassName();
  122.     wxString namespaceName = generatedClassName + wxT("_NS");
  123.     file.Write(wxT("class ") + generatedClassName + wxT(" : public ") + m_parentClassName
  124.       + wxT(" {\npublic:\n"));

  125.     // 生成成员变量
  126.     size_t i;
  127.     for (i = 0; i < m_wdata.GetCount(); ++i)
  128.     {
  129.       const XRCWidgetData& w = m_wdata.Item(i);
  130.       if (!CanBeUsedWithXRCCTRL(w.GetClass())) continue;
  131.       if (w.GetName().empty()) continue;
  132.       file.Write(
  133.         wxT(" ") + w.GetClass() + wxT("* ") + w.GetName()
  134.         + wxT(";\n"));
  135.     }

  136.     // 生成初始化方法(保持使用原始类名)
  137.     file.Write(wxT("\npublic:\n void InitWidgetsFromXRC(wxWindow *parent){\n")
  138.       + namespaceName + wxT("::InitXmlResource();\n") +
  139.       wxT("  wxXmlResource::Get()->LoadObject(this,parent,wxT("")
  140.       + m_className  // 注意:这里使用原始类名,不是generatedClassName
  141.       + wxT(""), wxT("")
  142.       + m_parentClassName
  143.       + wxT(""));\n"));

  144.     // 生成控件初始化代码
  145.     for (i = 0; i < m_wdata.GetCount(); ++i)
  146.     {
  147.       const XRCWidgetData& w = m_wdata.Item(i);
  148.       if (!CanBeUsedWithXRCCTRL(w.GetClass())) continue;
  149.       if (w.GetName().empty()) continue;
  150.       file.Write(wxT("  ")
  151.         + w.GetName()
  152.         + wxT(" = XRCCTRL(*this,"")
  153.         + w.GetName()
  154.         + wxT("",")
  155.         + w.GetClass()
  156.         + wxT(");\n"));
  157.     }
  158.     file.Write(wxT(" }\n"));

  159.     file.Write(wxT("public:\n"));

  160.     // 生成构造函数(使用带前缀的类名)
  161.     if (m_ancestorClassNames.size() == 1)
  162.     {
  163.       file.Write(
  164.         generatedClassName +  // 使用带前缀的类名
  165.         wxT("(") +
  166.         *m_ancestorClassNames.begin() +
  167.         wxT(" *parent=NULL){\n") +

  168.         wxT("  InitWidgetsFromXRC((wxWindow *)parent);\n")
  169.         wxT(" }\n")
  170.         wxT("};\n")
  171.       );
  172.     }
  173.     else
  174.     {
  175.       file.Write(generatedClassName + wxT("(){\n") +  // 使用带前缀的类名
  176.         wxT("  InitWidgetsFromXRC(NULL);\n")
  177.         wxT(" }\n")
  178.         wxT("};\n"));

  179.       for (StringSet::const_iterator it = m_ancestorClassNames.begin();
  180.         it != m_ancestorClassNames.end();
  181.         ++it)
  182.       {
  183.         file.Write(generatedClassName + wxT("(") + *it + wxT(" *parent){\n") +  // 使用带前缀的类名
  184.           wxT("  InitWidgetsFromXRC((wxWindow *)parent);\n")
  185.           wxT(" }\n")
  186.           wxT("};\n"));
  187.       }
  188.     }
  189.   }
  190. };
  191. WX_DECLARE_OBJARRAY(XRCWndClassData, ArrayOfXRCWndClassData);
  192. WX_DEFINE_OBJARRAY(ArrayOfXRCWndClassData)

  193. struct ExtractedString
  194. {
  195.   ExtractedString() : lineNo(-1) {}
  196.   ExtractedString(const wxString& str_,
  197.     const wxString& filename_, int lineNo_)
  198.     : str(str_), filename(filename_), lineNo(lineNo_)
  199.   {
  200.   }

  201.   wxString str;

  202.   wxString filename;
  203.   int      lineNo;
  204. };

  205. typedef wxVector<ExtractedString> ExtractedStrings;


  206. class XmlResApp : public wxAppConsole
  207. {
  208. public:
  209.   // don't use builtin cmd line parsing:
  210.   virtual bool OnInit() wxOVERRIDE { return true; }
  211.   virtual int OnRun() wxOVERRIDE;

  212. private:
  213.   void ParseParams(const wxCmdLineParser& cmdline);
  214.   void CompileRes();
  215.   wxArrayString PrepareTempFiles();
  216.   void FindFilesInXML(wxXmlNode* node, wxArrayString& flist, const wxString& inputPath);

  217.   wxString GetInternalFileName(const wxString& name, const wxArrayString& flist);
  218.   wxString GeneratedNamespaceName() const;

  219.   void DeleteTempFiles(const wxArrayString& flist);
  220.   void MakePackageZIP(const wxArrayString& flist);
  221.   void MakePackageCPP(const wxArrayString& flist);
  222.   void MakePackagePython(const wxArrayString& flist);

  223.   void OutputGettext();
  224.   ExtractedStrings FindStrings();
  225.   ExtractedStrings FindStrings(const wxString& filename, wxXmlNode* node);

  226.   bool Validate();

  227.   bool flagVerbose, flagCPP, flagPython, flagGettext, flagValidate, flagValidateOnly;
  228.   wxString parOutput, parFuncname, parOutputPath, parSchemaFile;
  229.   wxArrayString parFiles;
  230.   int retCode;

  231.   ArrayOfXRCWndClassData aXRCWndClassData;
  232.   bool flagH;
  233.   void GenCPPHeader();
  234. };

  235. wxIMPLEMENT_APP_CONSOLE(XmlResApp);

  236. int XmlResApp::OnRun()
  237. {
  238.   static const wxCmdLineEntryDesc cmdLineDesc[] =
  239.   {
  240.     { wxCMD_LINE_SWITCH, "h", "help",  "show help imformation", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
  241.     { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
  242.     { wxCMD_LINE_SWITCH, "e", "extra-cpp-code",  "output C++ header file with XRC derived classes" },
  243.     { wxCMD_LINE_SWITCH, "c", "cpp-code",  "output C++ source rather than .rsc file" },
  244.     { wxCMD_LINE_SWITCH, "p", "python-code",  "output wxPython source rather than .rsc file" },
  245.     { wxCMD_LINE_SWITCH, "g", "gettext",  "output list of translatable strings (to stdout or file if -o used)" },
  246.     { wxCMD_LINE_OPTION, "n", "function",  "C++/Python function name (with -c or -p) [InitXmlResource]" },
  247.     { wxCMD_LINE_OPTION, "o", "output",  "output file [resource.xrs/cpp]" },
  248.     { wxCMD_LINE_SWITCH, "",  "validate", "check XRC correctness (in addition to other processing)" },
  249.     { wxCMD_LINE_SWITCH, "",  "validate-only", "check XRC correctness and do nothing else" },
  250.     { wxCMD_LINE_OPTION, "",  "xrc-schema", "RELAX NG schema file to validate against (optional)" },
  251. #if 0 // not yet implemented
  252.     { wxCMD_LINE_OPTION, "l", "list-of-handlers",  "output list of necessary handlers to this file" },
  253. #endif
  254.     { wxCMD_LINE_PARAM,  NULL, NULL, "input file(s)",
  255.         wxCMD_LINE_VAL_STRING,
  256.         wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_OPTION_MANDATORY },

  257.     wxCMD_LINE_DESC_END
  258.   };

  259.   wxCmdLineParser parser(cmdLineDesc, argc, argv);

  260.   switch (parser.Parse())
  261.   {
  262.   case -1:
  263.     return 0;

  264.   case 0:
  265.     retCode = 0;
  266.     ParseParams(parser);

  267.     if (flagValidate)
  268.     {
  269.       if (!Validate())
  270.         return 2;
  271.       if (flagValidateOnly)
  272.         return 0;
  273.     }

  274.     if (flagGettext)
  275.       OutputGettext();
  276.     else
  277.       CompileRes();
  278.     return retCode;
  279.   }
  280.   return 1;
  281. }

  282. wxString XmlResApp::GeneratedNamespaceName() const
  283. {

  284.   return aXRCWndClassData[0].GeneratedClassName() + "_NS";

  285. }


  286. void XmlResApp::ParseParams(const wxCmdLineParser& cmdline)
  287. {
  288.   flagGettext = cmdline.Found("g");
  289.   flagVerbose = cmdline.Found("v");
  290.   flagCPP = cmdline.Found("c");
  291.   flagPython = cmdline.Found("p");
  292.   flagH = flagCPP && cmdline.Found("e");
  293.   flagValidateOnly = cmdline.Found("validate-only");
  294.   flagValidate = flagValidateOnly || cmdline.Found("validate");

  295.   cmdline.Found("xrc-schema", &parSchemaFile);

  296.   if (!cmdline.Found("o", &parOutput))
  297.   {
  298.     if (flagGettext)
  299.       parOutput = wxEmptyString;
  300.     else
  301.     {
  302.       if (flagCPP)
  303.         parOutput = wxT("resource.cpp");
  304.       else if (flagPython)
  305.         parOutput = wxT("resource.py");
  306.       else
  307.         parOutput = wxT("resource.xrs");
  308.     }
  309.   }
  310.   if (!parOutput.empty())
  311.   {
  312.     parOutput = wxFileName(parOutput).GetAbsolutePath();
  313.     parOutputPath = wxPathOnly(parOutput);
  314.   }
  315.   if (!parOutputPath) parOutputPath = wxT(".");

  316.   if (!cmdline.Found("n", &parFuncname))
  317.     parFuncname = wxT("InitXmlResource");

  318.   for (size_t i = 0; i < cmdline.GetParamCount(); i++)
  319.   {
  320. #ifdef __WINDOWS__
  321.     wxString fn = wxFindFirstFile(cmdline.GetParam(i), wxFILE);
  322.     while (!fn.empty())
  323.     {
  324.       parFiles.Add(fn);
  325.       fn = wxFindNextFile();
  326.     }
  327. #else
  328.     parFiles.Add(cmdline.GetParam(i));
  329. #endif
  330.   }
  331. }




  332. void XmlResApp::CompileRes()
  333. {
  334.   wxArrayString files = PrepareTempFiles();

  335.   if (wxFileExists(parOutput))
  336.     wxRemoveFile(parOutput);

  337.   if (!retCode)
  338.   {
  339.     if (flagCPP) {
  340.       MakePackageCPP(files);
  341.       if (flagH)
  342.         GenCPPHeader();
  343.     }
  344.     else if (flagPython)
  345.       MakePackagePython(files);
  346.     else
  347.       MakePackageZIP(files);
  348.   }

  349.   DeleteTempFiles(files);
  350. }


  351. wxString XmlResApp::GetInternalFileName(const wxString& name, const wxArrayString& flist)
  352. {
  353.   wxString name2 = name;
  354.   name2.Replace(wxT(":"), wxT("_"));
  355.   name2.Replace(wxT("/"), wxT("_"));
  356.   name2.Replace(wxT("\"), wxT("_"));
  357.   name2.Replace(wxT("*"), wxT("_"));
  358.   name2.Replace(wxT("?"), wxT("_"));

  359.   wxString s = wxFileNameFromPath(parOutput) + wxT("$") + name2;

  360.   if (wxFileExists(s) && flist.Index(s) == wxNOT_FOUND)
  361.   {
  362.     for (int i = 0;; i++)
  363.     {
  364.       s.Printf(wxFileNameFromPath(parOutput) + wxT("$%03i-") + name2, i);
  365.       if (!wxFileExists(s) || flist.Index(s) != wxNOT_FOUND)
  366.         break;
  367.     }
  368.   }
  369.   return s;
  370. }

  371. wxArrayString XmlResApp::PrepareTempFiles()
  372. {
  373.   wxArrayString flist;

  374.   for (size_t i = 0; i < parFiles.GetCount(); i++)
  375.   {
  376.     if (flagVerbose)
  377.       wxPrintf(wxT("processing ") + parFiles[i] + wxT("...\n"));

  378.     wxXmlDocument doc;

  379.     if (!doc.Load(parFiles[i]))
  380.     {
  381.       wxLogError(wxT("Error parsing file ") + parFiles[i]);
  382.       retCode = 1;
  383.       continue;
  384.     }

  385.     wxString name, ext, path;
  386.     wxFileName::SplitPath(parFiles[i], &path, &name, &ext);

  387.     FindFilesInXML(doc.GetRoot(), flist, path);
  388.     if (flagH)
  389.     {
  390.       wxXmlNode* node = (doc.GetRoot())->GetChildren();
  391.       wxString classValue, nameValue;
  392.       while (node) {
  393.         if (node->GetName() == wxT("object")
  394.           && node->GetAttribute(wxT("class"), &classValue)
  395.           && node->GetAttribute(wxT("name"), &nameValue)) {

  396.           aXRCWndClassData.Add(
  397.             XRCWndClassData(nameValue, classValue, node)
  398.           );
  399.         }
  400.         node = node->GetNext();
  401.       }
  402.     }
  403.     wxString internalName = GetInternalFileName(parFiles[i], flist);

  404.     doc.Save(parOutputPath + wxFILE_SEP_PATH + internalName);
  405.     flist.Add(internalName);
  406.   }

  407.   return flist;
  408. }


  409. // Does 'node' contain filename information at all?
  410. static bool NodeContainsFilename(wxXmlNode* node)
  411. {
  412.   const wxString name = node->GetName();

  413.   // Any bitmaps (bitmap2 is used for disabled toolbar buttons):
  414.   if (name == wxT("bitmap") || name == wxT("bitmap2"))
  415.     return true;

  416.   if (name == wxT("icon"))
  417.     return true;

  418.   // wxBitmapButton:
  419.   wxXmlNode* parent = node->GetParent();
  420.   if (parent != NULL &&
  421.     parent->GetAttribute(wxT("class"), wxT("")) == wxT("wxBitmapButton") &&
  422.     (name == wxT("focus") ||
  423.       name == wxT("disabled") ||
  424.       name == wxT("current") ||
  425.       name == wxT("pressed") ||
  426.       name == wxT("hover") ||
  427.       name == wxT("selected")))
  428.     return true;

  429.   // wxBitmap or wxIcon toplevel resources:
  430.   if (name == wxT("object"))
  431.   {
  432.     wxString klass = node->GetAttribute(wxT("class"), wxEmptyString);
  433.     if (klass == wxT("wxBitmap") ||
  434.       klass == wxT("wxIcon") ||
  435.       klass == wxT("data"))
  436.       return true;
  437.   }

  438.   // wxAnimationCtrl animations:
  439.   if (name == wxS("animation"))
  440.     return true;

  441.   // URLs in wxHtmlWindow:
  442.   if (name == wxT("url") &&
  443.     parent != NULL &&
  444.     parent->GetAttribute(wxT("class"), wxT("")) == wxT("wxHtmlWindow"))
  445.   {
  446.     // FIXME: this is wrong for e.g. http:// URLs
  447.     return true;
  448.   }

  449.   return false;
  450. }

  451. // find all files mentioned in structure, e.g. <bitmap>filename</bitmap>
  452. void XmlResApp::FindFilesInXML(wxXmlNode* node, wxArrayString& flist, const wxString& inputPath)
  453. {
  454.   // Is 'node' XML node element?
  455.   if (node == NULL) return;
  456.   if (node->GetType() != wxXML_ELEMENT_NODE) return;

  457.   bool containsFilename = NodeContainsFilename(node);

  458.   wxXmlNode* n = node->GetChildren();
  459.   while (n)
  460.   {
  461.     if (containsFilename &&
  462.       (n->GetType() == wxXML_TEXT_NODE ||
  463.         n->GetType() == wxXML_CDATA_SECTION_NODE))
  464.     {
  465.       // At least <bitmap> content can include several semi-colon
  466.       // separated paths corresponding to the different resolutions of
  467.       // the bitmap, so check for this.
  468.       wxArrayString internalNames;
  469.       const wxArrayString paths = wxSplit(n->GetContent(), ';', '\0');
  470.       for (size_t i = 0; i < paths.size(); ++i)
  471.       {
  472.         const wxString& path = paths[i];

  473.         wxString fullname;
  474.         if (wxIsAbsolutePath(path) || inputPath.empty())
  475.           fullname = path;
  476.         else
  477.           fullname = inputPath + wxFILE_SEP_PATH + path;

  478.         if (flagVerbose)
  479.           wxPrintf(wxT("adding     %s...\n"), fullname);

  480.         wxFileInputStream sin(fullname);
  481.         if (!sin)
  482.         {
  483.           // Note that the full name was already given in the error
  484.           // message logged by wxFileInputStream itself, so don't repeat
  485.           // it here.
  486.           wxLogError("Failed to read file referenced by "%s" at %d",
  487.             node->GetName(), node->GetLineNumber());
  488.           retCode = 1;
  489.         }
  490.         else
  491.         {
  492.           wxString filename = GetInternalFileName(path, flist);

  493.           // Copy the entire stream to the output file.
  494.           wxFileOutputStream sout(parOutputPath + wxFILE_SEP_PATH + filename);
  495.           if (sin.Read(sout).GetLastError() != wxSTREAM_EOF || !sout)
  496.           {
  497.             wxLogError("Failed to save "%s" referenced by "%s" at %d"
  498.               " to a temporary file",
  499.               fullname, node->GetName(), node->GetLineNumber());
  500.             retCode = 1;
  501.           }
  502.           else
  503.           {
  504.             internalNames.push_back(filename);

  505.             if (flist.Index(filename) == wxNOT_FOUND)
  506.               flist.Add(filename);
  507.           }
  508.         }
  509.       }

  510.       n->SetContent(wxJoin(internalNames, ';', '\0'));
  511.     }

  512.     // subnodes:
  513.     if (n->GetType() == wxXML_ELEMENT_NODE)
  514.       FindFilesInXML(n, flist, inputPath);

  515.     n = n->GetNext();
  516.   }
  517. }



  518. void XmlResApp::DeleteTempFiles(const wxArrayString& flist)
  519. {
  520.   for (size_t i = 0; i < flist.GetCount(); i++)
  521.     wxRemoveFile(parOutputPath + wxFILE_SEP_PATH + flist[i]);
  522. }



  523. void XmlResApp::MakePackageZIP(const wxArrayString& flist)
  524. {
  525.   wxString files;

  526.   for (size_t i = 0; i < flist.GetCount(); i++)
  527.     files += flist[i] + wxT(" ");
  528.   files.RemoveLast();

  529.   if (flagVerbose)
  530.     wxPrintf(wxT("compressing ") + parOutput + wxT("...\n"));

  531.   wxString cwd = wxGetCwd();
  532.   wxSetWorkingDirectory(parOutputPath);
  533.   int execres = wxExecute(wxT("zip -9 -j ") +
  534.     wxString(flagVerbose ? wxT(""") : wxT("-q "")) +
  535.     parOutput + wxT("" ") + files,
  536.     wxEXEC_BLOCK);
  537.   wxSetWorkingDirectory(cwd);
  538.   if (execres == -1)
  539.   {
  540.     wxLogError(wxT("Unable to execute zip program. Make sure it is in the path."));
  541.     wxLogError(wxT("You can download it at http://www.cdrom.com/pub/infozip/"));
  542.     retCode = 1;
  543.     return;
  544.   }
  545. }



  546. static wxString FileToCppArray(wxString filename, int num)
  547. {
  548.   wxString output;
  549.   wxString tmp;
  550.   wxString snum;
  551.   wxFFile file(filename, wxT("rb"));
  552.   wxFileOffset offset = file.Length();
  553.   wxASSERT_MSG(offset >= 0, wxT("Invalid file length"));

  554.   const size_t lng = wx_truncate_cast(size_t, offset);
  555.   wxASSERT_MSG(static_cast<wxFileOffset>(lng) == offset,
  556.     wxT("Huge file not supported"));

  557.   snum.Printf(wxT("%i"), num);
  558.   output.Printf(wxT("static size_t xml_res_size_") + snum + wxT(" = %lu;\n"),
  559.     static_cast<unsigned long>(lng));
  560.   output += wxT("static unsigned char xml_res_file_") + snum + wxT("[] = {\n");
  561.   // we cannot use string literals because MSVC is dumb wannabe compiler
  562.   // with arbitrary limitation to 2048 strings :(

  563.   unsigned char* buffer = new unsigned char[lng];
  564.   file.Read(buffer, lng);

  565.   for (size_t i = 0, linelng = 0; i < lng; i++)
  566.   {
  567.     tmp.Printf(wxT("%i"), buffer[i]);
  568.     if (i != 0) output << wxT(',');
  569.     if (linelng > 70)
  570.     {
  571.       linelng = 0;
  572.       output << wxT("\n");
  573.     }
  574.     output << tmp;
  575.     linelng += tmp.Length() + 1;
  576.   }

  577.   delete[] buffer;

  578.   output += wxT("};\n\n");

  579.   return output;
  580. }


  581. void XmlResApp::MakePackageCPP(const wxArrayString& flist) {
  582.   wxFFile file(parOutput, wxT("wt"));
  583.   unsigned i;

  584.   if (flagVerbose)
  585.     wxPrintf(wxT("creating C++ source file ") + parOutput + wxT("...\n"));

  586.   file.Write(""
  587.     "//\n"
  588.     "// This file was automatically generated by wxrc, do not edit by hand.\n"
  589.     "//\n\n"
  590.     "#include <wx/wxprec.h>\n"
  591.     "\n"
  592.     "#include <wx/filesys.h>\n"
  593.     "#include <wx/fs_mem.h>\n"
  594.     "#include <wx/xrc/xmlres.h>\n"
  595.     "#include <wx/xrc/xh_all.h>\n"
  596.     "\n"
  597.     "#if wxCHECK_VERSION(2,8,5) && wxABI_VERSION >= 20805\n"
  598.     "    #define XRC_ADD_FILE(name, data, size, mime) \\\n"
  599.     "        wxMemoryFSHandler::AddFileWithMimeType(name, data, size, mime)\n"
  600.     "#else\n"
  601.     "    #define XRC_ADD_FILE(name, data, size, mime) \\\n"
  602.     "        wxMemoryFSHandler::AddFile(name, data, size)\n"
  603.     "#endif\n"
  604.     "\n");

  605.   // 获取命名空间名称(与头文件一致)
  606.   wxString namespaceName;
  607.   if (aXRCWndClassData.GetCount() > 0) {
  608.     namespaceName = GeneratedNamespaceName();
  609.   }

  610.   // 开始命名空间
  611.   file.Write("\nnamespace " + namespaceName + " {\n\n");

  612.   // 将资源数组定义放在命名空间内
  613.   for (i = 0; i < flist.GetCount(); i++) {
  614.     file.Write(FileToCppArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));
  615.   }

  616.   file.Write("void " + parFuncname + "()\n"
  617.     "{\n"
  618.     "\n"
  619.     "    // Check for memory FS. If not present, load the handler:\n"
  620.     "    {\n"
  621.     "        wxMemoryFSHandler::AddFile(wxT("XRC_resource/dummy_file"), wxT("dummy one"));\n"
  622.     "        wxFileSystem fsys;\n"
  623.     "        wxFSFile *f = fsys.OpenFile(wxT("memory:XRC_resource/dummy_file"));\n"
  624.     "        wxMemoryFSHandler::RemoveFile(wxT("XRC_resource/dummy_file"));\n"
  625.     "        if (f) delete f;\n"
  626.     "        else wxFileSystem::AddHandler(new wxMemoryFSHandler);\n"
  627.     "    }\n"
  628.     "\n");

  629.   for (i = 0; i < flist.GetCount(); i++) {
  630.     wxString s;
  631.     wxString mime;
  632.     wxString ext = wxFileName(flist[i]).GetExt();
  633.     if (ext.Lower() == wxT("xrc"))
  634.       mime = wxT("text/xml");
  635. #if wxUSE_MIMETYPE
  636.     else {
  637.       wxFileType* ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
  638.       if (ft) {
  639.         ft->GetMimeType(&mime);
  640.         delete ft;
  641.       }
  642.     }
  643. #endif // wxUSE_MIMETYPE

  644.     s.Printf("    XRC_ADD_FILE(wxT("XRC_resource/" + flist[i] +
  645.       ""), xml_res_file_%u, xml_res_size_%u, wxT("%s"));\n",
  646.       i, i, mime.c_str());
  647.     file.Write(s);
  648.   }

  649.   for (i = 0; i < parFiles.GetCount(); i++) {
  650.     file.Write("    wxXmlResource::Get()->Load(wxT("memory:XRC_resource/" +
  651.       GetInternalFileName(parFiles[i], flist) + ""));\n");
  652.   }

  653.   file.Write("}\n\n");

  654.   // 结束命名空间
  655.   file.Write("} // namespace " + namespaceName + "\n");
  656. }


  657. void XmlResApp::GenCPPHeader()
  658. {
  659.   // Generate the output header in the same directory as the source file.
  660.   wxFileName headerName(parOutput);
  661.   headerName.SetExt("h");

  662.   wxFFile file(headerName.GetFullPath(), wxT("wt"));
  663.   file.Write(
  664.     "//\n"
  665.     "// This file was automatically generated by wxrc, do not edit by hand.\n"
  666.     "//\n\n"
  667.     "#ifndef __" + headerName.GetName() + "_h__\n"
  668.     "#define __" + headerName.GetName() + "_h__\n"
  669.     "#include <wx/wxprec.h>\n"
  670.     "\n"
  671.     "#include <wx/filesys.h>\n"
  672.     "#include <wx/fs_mem.h>\n"
  673.     "#include <wx/xrc/xmlres.h>\n"
  674.     "#include <wx/xrc/xh_all.h>\n"
  675.   );

  676.   if (aXRCWndClassData.GetCount() > 0) {
  677.     wxString namespaceName = GeneratedNamespaceName();
  678.     file.Write("\nnamespace " + namespaceName + " {\n");
  679.     file.Write("void " + parFuncname + "();\n");
  680.     file.Write("}\n");
  681.   }

  682.   for (size_t i = 0; i < aXRCWndClassData.GetCount(); ++i) {
  683.     aXRCWndClassData.Item(i).GenerateHeaderCode(file);
  684.   }
  685.   // 修改后的片段




  686.   file.Write("#endif\n");
  687. }

  688. static wxString FileToPythonArray(wxString filename, int num)
  689. {
  690.   wxString output;
  691.   wxString tmp;
  692.   wxString snum;
  693.   wxFFile file(filename, wxT("rb"));
  694.   wxFileOffset offset = file.Length();
  695.   wxASSERT_MSG(offset >= 0, wxT("Invalid file length"));

  696.   const size_t lng = wx_truncate_cast(size_t, offset);
  697.   wxASSERT_MSG(static_cast<wxFileOffset>(lng) == offset,
  698.     wxT("Huge file not supported"));

  699.   snum.Printf(wxT("%i"), num);
  700.   output = "    xml_res_file_" + snum + " = '''\\\n";

  701.   unsigned char* buffer = new unsigned char[lng];
  702.   file.Read(buffer, lng);

  703.   for (size_t i = 0, linelng = 0; i < lng; i++)
  704.   {
  705.     unsigned char c = buffer[i];
  706.     if (c == '\n')
  707.     {
  708.       tmp = (wxChar)c;
  709.       linelng = 0;
  710.     }
  711.     else if (c < 32 || c > 127 || c == '\'')
  712.       tmp.Printf(wxT("\\x%02x"), c);
  713.     else if (c == '\\')
  714.       tmp = wxT("\\\");
  715.     else
  716.       tmp = (wxChar)c;
  717.     if (linelng > 70)
  718.     {
  719.       linelng = 0;
  720.       output << wxT("\\\n");
  721.     }
  722.     output << tmp;
  723.     linelng += tmp.Length();
  724.   }

  725.   delete[] buffer;

  726.   output += wxT("'''\n\n");

  727.   return output;
  728. }


  729. void XmlResApp::MakePackagePython(const wxArrayString& flist)
  730. {
  731.   wxFFile file(parOutput, wxT("wt"));
  732.   unsigned i;

  733.   if (flagVerbose)
  734.     wxPrintf(wxT("creating Python source file ") + parOutput + wxT("...\n"));

  735.   file.Write(
  736.     "#\n"
  737.     "# This file was automatically generated by wxrc, do not edit by hand.\n"
  738.     "#\n\n"
  739.     "import wx\n"
  740.     "import wx.xrc\n\n"
  741.   );


  742.   file.Write("def " + parFuncname + "():\n");

  743.   for (i = 0; i < flist.GetCount(); i++)
  744.     file.Write(
  745.       FileToPythonArray(parOutputPath + wxFILE_SEP_PATH + flist[i], i));

  746.   file.Write(
  747.     "    # check if the memory filesystem handler has been loaded yet, and load it if not\n"
  748.     "    wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value')\n"
  749.     "    fsys = wx.FileSystem()\n"
  750.     "    f = fsys.OpenFile('memory:XRC_resource/dummy_file')\n"
  751.     "    wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file')\n"
  752.     "    if f is not None:\n"
  753.     "        f.Destroy()\n"
  754.     "    else:\n"
  755.     "        wx.FileSystem.AddHandler(wx.MemoryFSHandler())\n"
  756.     "\n"
  757.     "    # load all the strings as memory files and load into XmlRes\n"
  758.   );


  759.   for (i = 0; i < flist.GetCount(); i++)
  760.   {
  761.     wxString s;
  762.     s.Printf("    wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] +
  763.       "', xml_res_file_%u)\n", i);
  764.     file.Write(s);
  765.   }
  766.   for (i = 0; i < parFiles.GetCount(); i++)
  767.   {
  768.     file.Write("    wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
  769.       GetInternalFileName(parFiles[i], flist) + "')\n");
  770.   }

  771.   file.Write("\n");
  772. }



  773. void XmlResApp::OutputGettext()
  774. {
  775.   ExtractedStrings str = FindStrings();

  776.   wxFFile fout;
  777.   if (parOutput.empty())
  778.     fout.Attach(stdout);
  779.   else
  780.     fout.Open(parOutput, wxT("wt"));

  781.   for (ExtractedStrings::const_iterator i = str.begin(); i != str.end(); ++i)
  782.   {
  783.     const wxFileName filename(i->filename);

  784.     wxString s;
  785.     s.Printf("#line %d "%s"\n",
  786.       i->lineNo, filename.GetFullPath(wxPATH_UNIX));

  787.     fout.Write(s);
  788.     fout.Write("_("" + i->str + "");\n");
  789.   }

  790.   if (!parOutput) fout.Detach();
  791. }



  792. ExtractedStrings XmlResApp::FindStrings()
  793. {
  794.   ExtractedStrings arr, a2;

  795.   for (size_t i = 0; i < parFiles.GetCount(); i++)
  796.   {
  797.     if (flagVerbose)
  798.       wxPrintf(wxT("processing ") + parFiles[i] + wxT("...\n"));

  799.     wxXmlDocument doc;
  800.     if (!doc.Load(parFiles[i]))
  801.     {
  802.       wxLogError(wxT("Error parsing file ") + parFiles[i]);
  803.       retCode = 1;
  804.       continue;
  805.     }
  806.     a2 = FindStrings(parFiles[i], doc.GetRoot());

  807.     WX_APPEND_ARRAY(arr, a2);
  808.   }

  809.   return arr;
  810. }



  811. static wxString ConvertText(const wxString& str)
  812. {
  813.   wxString str2;
  814.   const wxChar* dt;

  815.   for (dt = str.c_str(); *dt; dt++)
  816.   {
  817.     if (*dt == wxT('_'))
  818.     {
  819.       if (*(dt + 1) == 0)
  820.         str2 << wxT('_');
  821.       else if (*(++dt) == wxT('_'))
  822.         str2 << wxT('_');
  823.       else
  824.         str2 << wxT('&') << *dt;
  825.     }
  826.     else
  827.     {
  828.       switch (*dt)
  829.       {
  830.       case wxT('\n'): str2 << wxT("\\n"); break;
  831.       case wxT('\t'): str2 << wxT("\\t"); break;
  832.       case wxT('\r'): str2 << wxT("\\r"); break;
  833.       case wxT('\\'): if ((*(dt + 1) != 'n') &&
  834.         (*(dt + 1) != 't') &&
  835.         (*(dt + 1) != 'r'))
  836.         str2 << wxT("\\\");
  837.               else
  838.         str2 << wxT("\");
  839.         break;
  840.       case wxT('"'): str2 << wxT("\\""); break;
  841.       default: str2 << *dt; break;
  842.       }
  843.     }
  844.   }

  845.   return str2;
  846. }


  847. enum ContentsKind
  848. {
  849.   Contents_NotTrans,  // Not a translatable text at all.
  850.   Contents_TransOnly, // Translatable but not escaped text.
  851.   Contents_Text       // Text, i.e. both translatable and escaped.
  852. };

  853. // Check if the given node contains translatable text and, if it does, whether
  854. // it's escaped (i.e. parsed using GetText()) or not.
  855. ContentsKind
  856. GetNodeContentsKind(wxXmlNode& node, const wxString& contents)
  857. {
  858.   if (node.GetName() == wxT("label") ||
  859.     (node.GetName() == wxT("value") && !contents.IsNumber()) ||
  860.     node.GetName() == wxT("help") ||
  861.     node.GetName() == wxT("hint") ||
  862.     node.GetName() == wxT("longhelp") ||
  863.     node.GetName() == wxT("tooltip") ||
  864.     node.GetName() == wxT("htmlcode") ||
  865.     node.GetName() == wxT("title") ||
  866.     node.GetName() == wxT("message") ||
  867.     node.GetName() == wxT("note") ||
  868.     node.GetName() == wxT("defaultdirectory") ||
  869.     node.GetName() == wxT("defaultfilename") ||
  870.     node.GetName() == wxT("defaultfolder") ||
  871.     node.GetName() == wxT("filter") ||
  872.     node.GetName() == wxT("caption"))
  873.   {
  874.     return Contents_Text;
  875.   }

  876.   // This one is special: it is translated in XRC, but its contents is not
  877.   // escaped, except for the special case of wxRadioBox when it can be, if
  878.   // "label" attribute is supplied.
  879.   if (node.GetName() == wxT("item"))
  880.   {
  881.     return node.GetAttribute(wxT("label"), wxT("0")) == wxT("1")
  882.       ? Contents_Text
  883.       : Contents_TransOnly;
  884.   }

  885.   return Contents_NotTrans;
  886. }


  887. ExtractedStrings
  888. XmlResApp::FindStrings(const wxString& filename, wxXmlNode* node)
  889. {
  890.   ExtractedStrings arr;

  891.   wxXmlNode* n = node;
  892.   if (n == NULL) return arr;
  893.   n = n->GetChildren();

  894.   while (n)
  895.   {
  896.     if ((node->GetType() == wxXML_ELEMENT_NODE) &&
  897.       // parent is an element, i.e. has subnodes...
  898.       (n->GetType() == wxXML_TEXT_NODE ||
  899.         n->GetType() == wxXML_CDATA_SECTION_NODE))
  900.       // ...it is textnode...
  901.     {
  902.       wxString s = n->GetContent();
  903.       switch (GetNodeContentsKind(*node, s))
  904.       {
  905.       case Contents_NotTrans:
  906.         break;

  907.       case Contents_Text:
  908.         s = ConvertText(s);
  909.         wxFALLTHROUGH;

  910.       case Contents_TransOnly:
  911.         if (!flagGettext ||
  912.           node->GetAttribute(wxT("translate"), wxT("1")) != wxT("0"))
  913.         {
  914.           arr.push_back(ExtractedString(s, filename, n->GetLineNumber()));
  915.         }
  916.         break;
  917.       }
  918.     }

  919.     // subnodes:
  920.     if (n->GetType() == wxXML_ELEMENT_NODE)
  921.     {
  922.       ExtractedStrings a2 = FindStrings(filename, n);
  923.       WX_APPEND_ARRAY(arr, a2);
  924.     }

  925.     n = n->GetNext();
  926.   }
  927.   return arr;
  928. }


  929. bool XmlResApp::Validate()
  930. {
  931.   if (flagVerbose)
  932.     wxPuts("validating XRC files...");

  933.   wxString schemaURI;

  934.   if (!parSchemaFile.empty())
  935.   {
  936.     schemaURI = parSchemaFile;
  937.   }
  938.   else
  939.   {
  940.     schemaURI = "http://www.wxwidgets.org/wxxrc";

  941.     // Normally, we'd use an OASIS XML catalog to map the URI to a local copy,
  942.     // but Jing's catalog support (-C catalogFile) requires additional
  943.     // dependency, resolver.jar, that is not commonly installed alongside Jing
  944.     // by systems that package Jing. So do the (trivial) mapping manually here:
  945.     wxString wxWinRoot;
  946.     if (wxGetEnv("WXWIN", &wxWinRoot))
  947.     {
  948.       wxString schemaFile(wxWinRoot + "/misc/schema/xrc_schema.rnc");
  949.       if (wxFileExists(schemaFile))
  950.         schemaURI = schemaFile;
  951.     }
  952.   }

  953.   wxString cmdline = wxString::Format("jing -c "%s"", schemaURI);
  954.   for (size_t i = 0; i < parFiles.GetCount(); i++)
  955.     cmdline << wxString::Format(" "%s"", parFiles[i]);

  956.   int res = wxExecute(cmdline, wxEXEC_BLOCK);
  957.   if (res == -1)
  958.   {
  959.     wxLogError("Running RELAX NG validator failed.");
  960.     wxLogError("Please install Jing (http://www.thaiopensource.com/relaxng/jing.html).");
  961.     wxLogError("See https://github.com/wxWidgets/wxWidgets/blob/master/misc/schema/README for more information.");
  962.     return false;
  963.   }

  964.   if (flagVerbose)
  965.   {
  966.     if (res == 0)
  967.       wxPuts("XRC validation passed without errors.");
  968.     else
  969.       wxPuts("XRC validation failed, there are errors.");
  970.   }

  971.   return res == 0;
  972. }


4. 在项目中使用 wx 窗体,需要一些准备;
4.1 添加一个 GlobalWxApp.h 文件,代码如下:
  1. #pragma once
  2. #include <wx/wx.h>

  3. #include <acedads.h>
  4. #include <singleInstance.h>
  5. #include <wx/msw/app.h>
  6. #include <wx/xrc/xmlres.h>
  7. #include <wx/event.h>
  8. // 精简版全局应用管理器
  9. class GlobalWxApp : public wxApp, public SingleInstance<GlobalWxApp> {
  10. private:
  11.   HWND m_hwndAcad; // 存储AutoCAD主窗口句柄
  12. public:
  13.   GlobalWxApp() {
  14.     // 初始化设置cad 窗口句柄
  15.     m_hwndAcad = adsw_acadMainWnd();
  16.     //初始化xrc资源预设
  17.     wxXmlResource::Get()->InitAllHandlers();
  18.   }
  19.   bool OnInit() override {

  20.     if (!wxApp::OnInit())
  21.       return false;

  22.     // 设置wxWidgets使用的父窗口
  23.     if (m_hwndAcad) {
  24.       // 获取当前的顶级窗口
  25.       wxWindow* topWindow = GetTopWindow();
  26.       if (topWindow) {
  27.         // 设置AutoCAD为父窗口
  28.         ::SetParent((HWND)topWindow->GetHWND(), m_hwndAcad);
  29.       }
  30.     }
  31.     return true;
  32.   }

  33.   //显示任意窗口
  34.   void Show(wxWindow* window) {
  35.     window->Show();
  36.     window->Raise();
  37.   }
  38. };


  39. class WxConnect {
  40. public:
  41.   template <typename TControl, typename TEvent>
  42.   static void Connect(TControl* control, TEvent eventType, void (*func)()) {
  43.     control->Bind(eventType, [func](wxEvent&) { func(); });
  44.   }

  45.   template <typename TControl, typename TEvent, typename TEventArg>
  46.   static void Connect(TControl* control, TEvent eventType, void (*func)(TEventArg&)) {
  47.     control->Bind(eventType, [func](wxEvent& e) { func(static_cast<TEventArg&>(e)); });
  48.   }
  49. };
4.2 xrc 文件如下:

  1. <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
  2. <resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
  3.   <object class="wxDialog" name="MainFrame">
  4.     <style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSTAY_ON_TOP</style>
  5.     <size>800,500</size>
  6.     <title>几何算法工具箱</title>
  7.     <object class="wxBoxSizer">
  8.       <orient>wxVERTICAL</orient>
  9.       <object class="sizeritem">
  10.         <option>1</option>
  11.         <flag>wxEXPAND|wxALL</flag>
  12.         <border>10</border>
  13.         <object class="wxBoxSizer">
  14.           <orient>wxHORIZONTAL</orient>
  15.           <object class="sizeritem">
  16.             <option>1</option>
  17.             <flag>wxEXPAND|wxRIGHT</flag>
  18.             <border>5</border>
  19.             <object class="wxPanel" name="frameParallel">
  20.               <style>wxTAB_TRAVERSAL|wxBORDER_SIMPLE</style>
  21.               <object class="wxBoxSizer">
  22.                 <orient>wxVERTICAL</orient>
  23.                 <object class="sizeritem">
  24.                   <option>0</option>
  25.                   <flag>wxALIGN_CENTER|wxTOP|wxBOTTOM</flag>
  26.                   <border>10</border>
  27.                   <object class="wxStaticText" name="lblParallel">
  28.                     <font>
  29.                       <size>12</size>
  30.                       <style>normal</style>
  31.                       <weight>bold</weight>
  32.                       <underlined>0</underlined>
  33.                     </font>
  34.                     <label>并行处理</label>
  35.                     <wrap>0</wrap>
  36.                   </object>
  37.                 </object>
  38.                 <object class="sizeritem">
  39.                   <option>0</option>
  40.                   <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
  41.                   <border>15</border>
  42.                   <object class="wxButton" name="btnCreateData">
  43.                     <label>数据创建</label>
  44.                     <default>0</default>
  45.                     <markup>0</markup>
  46.                     <bitmap />
  47.                   </object>
  48.                 </object>
  49.                 <object class="sizeritem">
  50.                   <option>0</option>
  51.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  52.                   <border>15</border>
  53.                   <object class="wxButton" name="btnSingleProcess">
  54.                     <label>单线程变换</label>
  55.                     <default>0</default>
  56.                     <markup>0</markup>
  57.                     <bitmap />
  58.                   </object>
  59.                 </object>
  60.                 <object class="sizeritem">
  61.                   <option>0</option>
  62.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  63.                   <border>15</border>
  64.                   <object class="wxButton" name="btnOpenMp">
  65.                     <label>OpenMP加速</label>
  66.                     <default>0</default>
  67.                     <markup>0</markup>
  68.                     <bitmap />
  69.                   </object>
  70.                 </object>
  71.                 <object class="sizeritem">
  72.                   <option>0</option>
  73.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  74.                   <border>15</border>
  75.                   <object class="wxButton" name="btnOpenCL">
  76.                     <label>OpenCL加速</label>
  77.                     <default>0</default>
  78.                     <markup>0</markup>
  79.                     <bitmap />
  80.                   </object>
  81.                 </object>
  82.               </object>
  83.             </object>
  84.           </object>
  85.           <object class="sizeritem">
  86.             <option>1</option>
  87.             <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
  88.             <border>5</border>
  89.             <object class="wxPanel" name="framePointCloud">
  90.               <style>wxTAB_TRAVERSAL|wxBORDER_SIMPLE</style>
  91.               <object class="wxBoxSizer">
  92.                 <orient>wxVERTICAL</orient>
  93.                 <object class="sizeritem">
  94.                   <option>0</option>
  95.                   <flag>wxALIGN_CENTER|wxTOP|wxBOTTOM</flag>
  96.                   <border>10</border>
  97.                   <object class="wxStaticText" name="lblPointCloud">
  98.                     <font>
  99.                       <size>12</size>
  100.                       <style>normal</style>
  101.                       <weight>bold</weight>
  102.                       <underlined>0</underlined>
  103.                     </font>
  104.                     <label>点云算法</label>
  105.                     <wrap>0</wrap>
  106.                   </object>
  107.                 </object>
  108.                 <object class="sizeritem">
  109.                   <option>0</option>
  110.                   <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
  111.                   <border>15</border>
  112.                   <object class="wxButton" name="btnConvexHull">
  113.                     <label>求凸包</label>
  114.                     <default>0</default>
  115.                     <markup>0</markup>
  116.                     <bitmap />
  117.                   </object>
  118.                 </object>
  119.                 <object class="sizeritem">
  120.                   <option>0</option>
  121.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  122.                   <border>15</border>
  123.                   <object class="wxButton" name="btnRotatingCalipers">
  124.                     <label>旋转卡壳包围盒</label>
  125.                     <default>0</default>
  126.                     <markup>0</markup>
  127.                     <bitmap />
  128.                   </object>
  129.                 </object>
  130.                 <object class="sizeritem">
  131.                   <option>0</option>
  132.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  133.                   <border>15</border>
  134.                   <object class="wxButton" name="btnMinEnclosingCircle">
  135.                     <label>求最小外接圆</label>
  136.                     <default>0</default>
  137.                     <markup>0</markup>
  138.                     <bitmap />
  139.                   </object>
  140.                 </object>
  141.                 <object class="sizeritem">
  142.                   <option>0</option>
  143.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  144.                   <border>15</border>
  145.                   <object class="wxButton" name="btnDT">
  146.                     <label>三角网构建</label>
  147.                     <default>0</default>
  148.                     <markup>0</markup>
  149.                     <bitmap />
  150.                   </object>
  151.                 </object>
  152.                 <object class="sizeritem">
  153.                   <option>0</option>
  154.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  155.                   <border>15</border>
  156.                   <object class="wxButton" name="btnVD">
  157.                     <label>Voronoi构建</label>
  158.                     <default>0</default>
  159.                     <markup>0</markup>
  160.                     <bitmap />
  161.                   </object>
  162.                 </object>
  163.               </object>
  164.             </object>
  165.           </object>
  166.           <object class="sizeritem">
  167.             <option>1</option>
  168.             <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
  169.             <border>5</border>
  170.             <object class="wxPanel" name="framePixel">
  171.               <style>wxTAB_TRAVERSAL|wxBORDER_SIMPLE</style>
  172.               <object class="wxBoxSizer">
  173.                 <orient>wxVERTICAL</orient>
  174.                 <object class="sizeritem">
  175.                   <option>0</option>
  176.                   <flag>wxALIGN_CENTER|wxTOP|wxBOTTOM</flag>
  177.                   <border>10</border>
  178.                   <object class="wxStaticText" name="lblPixel">
  179.                     <font>
  180.                       <size>12</size>
  181.                       <style>normal</style>
  182.                       <weight>bold</weight>
  183.                       <underlined>0</underlined>
  184.                     </font>
  185.                     <label>像素法</label>
  186.                     <wrap>0</wrap>
  187.                   </object>
  188.                 </object>
  189.                 <object class="sizeritem">
  190.                   <option>0</option>
  191.                   <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
  192.                   <border>15</border>
  193.                   <object class="wxButton" name="btnInnerContour">
  194.                     <label>求单个内轮廓</label>
  195.                     <default>0</default>
  196.                     <markup>0</markup>
  197.                     <bitmap />
  198.                   </object>
  199.                 </object>
  200.                 <object class="sizeritem">
  201.                   <option>0</option>
  202.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  203.                   <border>15</border>
  204.                   <object class="wxButton" name="btnAllInnerContours">
  205.                     <label>求所有内轮廓</label>
  206.                     <default>0</default>
  207.                     <markup>0</markup>
  208.                     <bitmap />
  209.                   </object>
  210.                 </object>
  211.                 <object class="sizeritem">
  212.                   <option>0</option>
  213.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  214.                   <border>15</border>
  215.                   <object class="wxButton" name="btnOuterContour">
  216.                     <label>求外轮廓</label>
  217.                     <default>0</default>
  218.                     <markup>0</markup>
  219.                     <bitmap />
  220.                   </object>
  221.                 </object>
  222.               </object>
  223.             </object>
  224.           </object>
  225.           <object class="sizeritem">
  226.             <option>1</option>
  227.             <flag>wxEXPAND|wxLEFT</flag>
  228.             <border>5</border>
  229.             <object class="wxPanel" name="frameCGAL">
  230.               <style>wxTAB_TRAVERSAL|wxBORDER_SIMPLE</style>
  231.               <object class="wxBoxSizer">
  232.                 <orient>wxVERTICAL</orient>
  233.                 <object class="sizeritem">
  234.                   <option>0</option>
  235.                   <flag>wxALIGN_CENTER|wxTOP|wxBOTTOM</flag>
  236.                   <border>10</border>
  237.                   <object class="wxStaticText" name="lblCGAL">
  238.                     <font>
  239.                       <size>12</size>
  240.                       <style>normal</style>
  241.                       <weight>bold</weight>
  242.                       <underlined>0</underlined>
  243.                     </font>
  244.                     <label>CGAL应用</label>
  245.                     <wrap>0</wrap>
  246.                   </object>
  247.                 </object>
  248.                 <object class="sizeritem">
  249.                   <option>0</option>
  250.                   <flag>wxEXPAND|wxLEFT|wxRIGHT</flag>
  251.                   <border>15</border>
  252.                   <object class="wxButton" name="btnCenterLine">
  253.                     <label>CenterLine1</label>
  254.                     <default>0</default>
  255.                     <markup>0</markup>
  256.                     <bitmap />
  257.                   </object>
  258.                 </object>
  259.                 <object class="sizeritem">
  260.                   <option>0</option>
  261.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  262.                   <border>15</border>
  263.                   <object class="wxButton" name="btnCDT">
  264.                     <label>CDT</label>
  265.                     <default>0</default>
  266.                     <markup>0</markup>
  267.                     <bitmap />
  268.                   </object>
  269.                 </object>
  270.                 <object class="sizeritem">
  271.                   <option>0</option>
  272.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  273.                   <border>15</border>
  274.                   <object class="wxButton" name="btnSDG">
  275.                     <label>SDG</label>
  276.                     <default>0</default>
  277.                     <markup>0</markup>
  278.                     <bitmap />
  279.                   </object>
  280.                 </object>
  281.                 <object class="sizeritem">
  282.                   <option>0</option>
  283.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  284.                   <border>15</border>
  285.                   <object class="wxButton" name="btnVoronoi">
  286.                     <label>Voronoi图</label>
  287.                     <default>0</default>
  288.                     <markup>0</markup>
  289.                     <bitmap />
  290.                   </object>
  291.                 </object>
  292.                 <object class="sizeritem">
  293.                   <option>0</option>
  294.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  295.                   <border>15</border>
  296.                   <object class="wxButton" name="btnSkeleton">
  297.                     <label>直骨架线</label>
  298.                     <default>0</default>
  299.                     <markup>0</markup>
  300.                     <bitmap />
  301.                   </object>
  302.                 </object>
  303.                 <object class="sizeritem">
  304.                   <option>0</option>
  305.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  306.                   <border>15</border>
  307.                   <object class="wxButton" name="btnMaxInsideCircle">
  308.                     <label>求最大内接圆</label>
  309.                     <default>0</default>
  310.                     <markup>0</markup>
  311.                     <bitmap />
  312.                   </object>
  313.                 </object>
  314.                 <object class="sizeritem">
  315.                   <option>0</option>
  316.                   <flag>wxEXPAND|wxLEFT|wxRIGHT|wxTOP</flag>
  317.                   <border>15</border>
  318.                   <object class="wxButton" name="btnMaxInsideCircleWithHole">
  319.                     <label>带孔内接圆</label>
  320.                     <default>0</default>
  321.                     <markup>0</markup>
  322.                     <bitmap />
  323.                   </object>
  324.                 </object>
  325.               </object>
  326.             </object>
  327.           </object>
  328.         </object>
  329.       </object>
  330.     </object>
  331.   </object>
  332. </resource>
复制代码


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
大佬牛逼,用python搞二开的作者,明经好像就此一人
回复 支持 反对

使用道具 举报

 楼主| 发表于 3 天前 | 显示全部楼层
lxl217114 发表于 2025-6-25 16:21
大佬牛逼,用python搞二开的作者,明经好像就此一人

不敢当,我就是小卡拉米
回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
感觉很高级,虽然看不懂。
回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
用C++写界面真是太辛苦了...
回复 支持 反对

使用道具 举报

 楼主| 发表于 3 天前 来自手机 | 显示全部楼层
你有种再说一遍 发表于 2025-6-25 18:09
用C++写界面真是太辛苦了...

用qt或者wx就没这个烦恼了,只是没想到怎么能像mfc那样嵌进去
回复 支持 反对

使用道具 举报

发表于 前天 16:11 | 显示全部楼层
懒得嵌入,直接调用exe,激活CAD窗口.发送命令完事,优点是什么样式的面板都能做出来.
回复 支持 反对

使用道具 举报

 楼主| 发表于 前天 17:28 | 显示全部楼层
kiloleo2 发表于 2025-6-26 16:11
懒得嵌入,直接调用exe,激活CAD窗口.发送命令完事,优点是什么样式的面板都能做出来.

总之,也算是解决Object 界面痛点的方法之一吧
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-6-28 05:24 , Processed in 0.222898 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表