跳转至

MyBlog

ObjectARX加载菜单

使用ObjectARX有几种加载菜单的方式

使用aced函数加载

LocadMenu.h

C++
#pragma once
#include "stdafx.h"

class Menu
{
public:
    Menu();
    ~Menu();
    static bool    IsFileExists(LPCTSTR szPath);
    static CString GetFolder(LPCTSTR szPath);
    static CString GetCurDir();
    static CString FindConPath(CString FileName);
    static void    CLoadMenu(CString sName, CString szPath);
    static void    CUnLoadMenu(CString sName, CString szPath);
    static void    RemoveMenuCache(CString sName, CString szPath);
};

LocadMenu.cpp

C++
#include "stdafx.h"
#include "LoadMenu.h"

Menu::Menu() {}

Menu::~Menu() {}

bool Menu::IsFileExists(LPCTSTR szPath)
{
    CFileStatus st;
    return CFile::GetStatus(szPath, st);
}

CString Menu::GetFolder(LPCTSTR szPath)
{
    CString strPath(szPath);
    strPath.TrimRight(_T("\\/"));

    int pos = strPath.ReverseFind(_T('\\'));
    int pos2 = strPath.ReverseFind(_T('/'));
    pos = max(pos, pos2);

    if (pos < 0)
    {
        return _T("");
    }

    return strPath.Left(pos + 1);
}

CString Menu::GetCurDir()
{
    TCHAR szPath[_MAX_PATH];
    ::GetModuleFileName(_hdllInstance, szPath, _MAX_PATH);

    TCHAR szDrive[_MAX_DRIVE];
    TCHAR szDir[_MAX_DIR];
    TCHAR szFname[_MAX_FNAME];
    TCHAR szExt[_MAX_EXT];
    _tsplitpath_s(szPath, szDrive, szDir, szFname, szExt);

    return CString(szDrive) + szDir;
}

CString Menu::FindConPath(CString FileName)
{
    CString sDir = GetCurDir();

    CString sPath = sDir + FileName;
    while (!IsFileExists(sPath))
    {
        sDir = GetFolder(sDir);
        if (sDir.IsEmpty())
        {
            return _T("");
        }

        sPath = sDir + FileName;
    }
    return sPath;
}

void Menu::CLoadMenu(CString sName, CString szPath)
{
    //加载菜单
    if (!acedIsMenuGroupLoaded(sName))
    {
        CString str;

        str = FindConPath(szPath + _T(".cuix"));
        if (str.IsEmpty())
        {
            str = FindConPath(szPath + _T(".mnu"));
        }

        acedLoadPartialMenu(str);
    }
}

void Menu::CUnLoadMenu(CString sName, CString szPath)
{
    //卸载菜单
    if (acedIsMenuGroupLoaded(sName))
    {
        CString str;

        str = FindConPath(szPath + _T(".cuix"));
        if (str.IsEmpty())
        {
            str = FindConPath(szPath + _T(".mnu"));
        }

        acedUnloadPartialMenu(str);
    }
}

void Menu::RemoveMenuCache(CString sName, CString szPath)
{
    if (acedIsMenuGroupLoaded(sName))
    {
        CString str;

        str = FindConPath(szPath + _T(".cuix"));
        if (str.IsEmpty())
        {
            return;
        }
        int   len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
        char* ptxtTemp = new char[len + 1];
        WideCharToMultiByte(CP_ACP, 0, str, -1, ptxtTemp, len, NULL, NULL);
        remove(ptxtTemp);
        delete[] ptxtTemp;
    }
}

使用方式

C++
virtual AcRx::AppRetCode On_kInitAppMsg(void *pkt)
{
    // You *must* call On_kInitAppMsg here
    AcRx::AppRetCode retCode = AcRxArxApp::On_kInitAppMsg(pkt);
    Menu::CUnLoadMenu(_T("SHRoad"), _T("Library\\Menu\\SHGLJTDZKFXM"));
    Menu::CLoadMenu(_T("SHRoad"), _T("Library\\Menu\\SHGLJTDZKFXM"));

    return (retCode);
}

virtual AcRx::AppRetCode On_kUnloadAppMsg(void *pkt)
{
    AcRx::AppRetCode retCode = AcRxArxApp::On_kUnloadAppMsg(pkt);
    Menu::CUnLoadMenu(_T("SHGLJTDZKFXM"), _T("Library\\Menu\\SHGLJTDZKFXM"));
    return (retCode);
}

第二种方式使用com加载

C++
#include "CAcadApplication.h"
#include "CAcadDocument.h"
#include "CAcadMenuBar.h"
#include "CAcadMenuGroup.h"
#include "CAcadMenuGroups.h"
#include "CAcadPopupMenu.h"
#include "CAcadPopupMenus.h"
//加载cui文件
bool LoadPartialMenu(
    const TCHAR* filePath //局部菜单文件名
    ,
    const TCHAR* menuGroupName)

{
    //如果有的话先卸载

    long menuGroupNum; //菜单组数目

    VARIANT index;

    VariantInit(&index);

    index.vt = VT_I4;

    CString strGroupName(menuGroupName);

    CAcadApplication acadApp(acedGetAcadWinApp()->GetIDispatch(TRUE));

    CAcadMenuGroups menuGroups(acadApp.get_MenuGroups());

    CAcadMenuGroup menuGroup;

    menuGroupNum = menuGroups.get_Count();

    for (long i = 0; i < menuGroupNum; i++)
    {
        index.lVal = i;

        menuGroup = menuGroups.Item(index);
        CString strName = menuGroup.get_Name();
        if (strName.CompareNoCase(strGroupName) == 0)
        {
            menuGroup.Unload();

            break;
            //return false;
        }
    }

    //加载菜单

    VARIANT BaseMenu; //是否加载为基础菜单

    VariantInit(&BaseMenu);

    BaseMenu.vt = VT_BOOL;

    BaseMenu.boolVal = FALSE;

    menuGroups.Load(CString(filePath), BaseMenu);
    // 把菜单在菜单条上显示出来

    //CAcadMenuBar menuBar(acadApp.get_MenuBar());  //当前菜单条

    //CAcadPopupMenus popupMenus(menuGroup.get_Menus()); //要加入的菜单条

    //CAcadPopupMenu popupMenu;

    //long curPopupMenuNum = menuBar.get_Count();   //当前菜单条上菜单的数目

    //long n = popupMenus.get_Count();
    ////bool beExit = false;
    //for (long i = 0; i < n; i++) {

    //  index.lVal = i;

    //  popupMenu = popupMenus.Item(index);

    //  index.lVal = i + curPopupMenuNum;

    //  popupMenu.InsertInMenuBar(index);
    //  CString strName = popupMenu.get_Name();
    //  if (strName.CompareNoCase(_T("TaiyuanBoilerElevation")) == 0)
    //  {
    //      //beExit = TRUE;
    //      break;
    //  }
    //}
    return true;
}
static void initLoadMenu()
{
    CString strPath = CUtility::GetAppPath();
    strPath = strPath.Left(strPath.ReverseFind('\\'));
    if (strPath != _T(""))
    {
        strPath += _T("\\xhhk.cuix");
    }
    LoadPartialMenu(strPath, _T("xhhk"));
}

On_kInitAppMsg

initLoadMenu();

推荐使用第一种方式,不需要加载那么多的头文件

image-20250604151542564

CAD.net调用内置对话框

C#
[CommandMethod("CmdTest_ShowDialog")]
public void CmdTest_ShowDialog()
{
    var dm = ZwSoft.ZwCAD.ApplicationServices.Application.DocumentManager;
    var doc = dm.MdiActiveDocument;
    var ed = doc.Editor;
    var db = doc.Database;
    ed.WriteMessage("\n测试cad颜色面板+线型面板");

    var cd = new ZwSoft.ZwCAD.Windows.ColorDialog();
    var dr = cd.ShowDialog();
    if (dr == System.Windows.Forms.DialogResult.OK)
        ed.WriteMessage("\ncad颜色选择了: " + cd.Color.ToString());

    var ld = new ZwSoft.ZwCAD.Windows.LinetypeDialog();
    dr = ld.ShowDialog();
    if (dr == System.Windows.Forms.DialogResult.OK)
        ed.WriteMessage("\ncad线型选择了: " + ld.Linetype.ToString());

    var dlg = new System.Windows.Forms.ColorDialog();
    dr = dlg.ShowDialog();
    if (dr == System.Windows.Forms.DialogResult.OK)
        ed.WriteMessage("\n系统颜色选择了: " + dlg.Color.ToString());
}

动画

====

CSS3,我们可以创建动画,它可以取代许多网页动画图像,Flash 动画,和 Javascripts。

CSS3 @keyframes 规则

要创建CSS3动画,你将不得不了解@keyframes规则。

@keyframes规则是用来创建动画。 @keyframes规则内指定一个 CSS样式和动画将逐步从目前的样式更改为新的样式。

**注意:**Internet Explorer 10、Firefox 以及 Opera 支持 @keyframes 规则和 animation 属性。 Chrome 和 Safari 需要前缀 -webkit-。

CSS3 动画

当在@keyframe创建动画,把它绑定到一个选择器,否则动画不会有任何效果。

指定至少这两个 CSS3 的动画属性绑定向一个选择器:

  • 规定动画的名称
  • 规定动画的时长

例子:

Text Only
1
2
3
4
5
#animated_div {
    animation: animated_div 5s infinite;
    -moz-animation: animated_div 5s infinite;
    -webkit-animation: animated_div 5s infinite;
}

CSS3动画是什么?

  • 动画是使元素从一种样式逐渐变化为另一种样式的效果。
  • 您可以改变任意多的样式任意多的次数。
  • 请用百分比来规定变化发生的时间,或用关键词 "from" 和 "to",等同于 0% 和 100%。
  • 0% 是动画的开始,100% 是动画的完成。
  • 为了得到最佳的浏览器支持,您应该始终定义 0% 和 100% 选择器。

例子:

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@keyframes animated_div {
    0% {
        left: 0px;
    }
    20% {
        left: 50px;
        background-color: green;
    }
    40% {
        left: 140px;
        background-color: red;
    }
    60% {
        left: 280px;
        background-color: yellow;
    }
    80% {
        left: 425px;
        background-color: blue;
    }
    100% {
        left: 0px;
        background-color: pink;
    }
}

常用属性

属性 描述 CSS
@keyframes 规定动画。 3
animation 所有动画属性的简写属性,除了 animation-play-state 属性。 3
animation-name 规定 @keyframes 动画的名称。 3
animation-duration 规定动画完成一个周期所花费的秒或毫秒。默认是 0。 3
animation-timing-function 规定动画的速度曲线。默认是 "ease"。 3
animation-delay 规定动画何时开始。默认是 0。 3
animation-iteration-count 规定动画被播放的次数。默认是 1。 3
animation-direction 规定动画是否在下一周期逆向地播放。默认是 "normal"。 3
animation-play-state 规定动画是否正在运行或暂停。默认是 "running"。 3

ObjectARX ucs和wcs

ucs和wcs转换

No Description
0 World (WCS)
1 User (current UCS)
2 Display:DCS of current viewport when used with code 0 or 1DCS of current model space viewport when used with code 3
3 Paper space DCS (PSDCS; used only with code 2)
C++
//0表示wcs 1表示ucs 2 DCS, 3 PSDCS
AcGePoint3d CGlobalHelper::TransformPoint(const AcGePoint3d &point, int nFromType, int nToType)
{
    AcGePoint3d pt;
    //从ucs转到wcs
    struct resbuf rbFrom, rbTo;
    rbFrom.restype = RTSHORT;
    rbFrom.resval.rint = nFromType; // from wcs
    rbTo.restype = RTSHORT;
    rbTo.resval.rint = nToType;     // from ucs
    acedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));
    return pt;
}

常见的wcs

AcDbEntity中存储和返回的都是wcs,比如

C++
//直线 点都必须在WCS坐标中
AcDbLine(const AcGePoint3d& start, const AcGePoint3d& end);

//圆 中心和法向量必须是WCS坐标
AcDbCircle(const AcGePoint3d& cntr, const AcGeVector3d& nrm, double radius);

//圆弧 中心必须位于WCS坐标中
AcDbArc(const AcGePoint3d& center, const AcGeVector3d& normal, double radius, double startAngle, double endAngle);

//多段线 注意!!!点必须位于ECS坐标中
AcDbPolyline::addVertexAt(unsigned int index,  const AcGePoint2d& pt, double bulge = 0., double startWidth = -1.,  double endWidth = -1., Adesk::Int32 vertexIdentifier = 0);

//椭圆 中心必须位于WCS坐标中
AcDbEllipse( const AcGePoint3d& center, const AcGeVector3d& unitNormal, const AcGeVector3d& majorAxis, double radiusRatio, double startAngle = 0.0, double endAngle = 2*PI);

//引线 点必须位于WCS坐标中
AcDbLeader::appendVertex(const AcGePoint3d&);
view相关的点也是wcs
C++
void CGlobalHelper::ZOOMWINDOW(AcGePoint3d minPt, AcGePoint3d maxPt)
{
    // get the extents of the drawing
    AcDbViewTableRecord view;

    AcGePoint2d max_2d(maxPt[X], maxPt[Y]);
    AcGePoint2d min_2d(minPt[X], minPt[Y]);
    // now set the view centre point
    view.setCenterPoint(min_2d + (max_2d - min_2d) / 2.0);
    // now height and width of view
    view.setHeight(max_2d[Y] - min_2d[Y]);
    view.setWidth(max_2d[X] - min_2d[X]);
    // set the view
    acedSetCurrentView(&view, NULL);
    // updates the extents
    acdbHostApplicationServices()->workingDatabase()->updateExt(TRUE);
}

jig中交互的点都是wcs

C++
1
2
3
4
5
6
7
8
9
//WCS 
//JIG获取点,即传入的basePnt、返回的resPnt 均为WCS中的点
AcEdJig::acquirePoint(AcGePoint3d& resPnt , const AcGePoint3d& basePnt);

//JIG获取角度,即传入的basePnt为WCS中的点
AcEdJig::acquireAngle( double & ang, const AcGePoint3d& basePnt);

//JIG获取距离,即传入的basePnt为WCS中的点
AcEdJig::acquireDist( double & dist, const AcGePoint3d& basePnt);

常见的UCS

常用API接口返回参数

C++
//UCS
//获取点,即传入的pt、返回的result均为UCS中的点
int acedGetPoint(const ads_point pt, const ACHAR * prompt, ads_point result);

//获取实体,返回的ptres均为UCS中的点
int acedEntSel(const ACHAR * str, ads_name entres, ads_point ptres);

//获取角度,传入的pt为UCS中的点
int acedGetAngle(const ads_point pt, const ACHAR * prompt, ads_real * result);

//获取距离,传入的pt为UCS中的点
int acedGetDist(const ads_point pt, const ACHAR * prompt, ads_real * result);

//动态拖拽移动 ,即传入的pmt、回调函数中的pt、返回的p均为UCS中的点
int acedDragGen(const ads_name ss, const ACHAR * pmt, int cursor, int (*scnf) (ads_point pt, ads_matrix mt), ads_point p);

AcDbMText::rotation 

//传入的点是ucs,这个比较重要

C++
int nRet = acedSSGet(_T("C"), asDblArray(minPt), asDblArray(maxPt), rb, ssname);

AcDbMText::rotation setRotation 这里的角度是相对于UCS的x轴,所以需要处理,特别注意

DCS

目前已知的dcs就是plot中的点坐标

C++
struct resbuf rbFrom, rbTo;
rbFrom.restype = RTSHORT;
rbFrom.resval.rint = 0; // from WCS
rbTo.restype = RTSHORT;
if (m_bISModelType)
{
    rbTo.resval.rint = 2; // to dcs
}
else
{
    rbTo.resval.rint = 2; // to pdcs
    acedTrans(asDblArray(maxPt), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(maxPt));
    acedTrans(asDblArray(minPt), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(minPt));
    rbFrom.resval.rint = 2; // from UCS
    rbTo.resval.rint = 3;
}
int nCvport = 2;
utils.GetVar(_T("CVPORT"), &nCvport);
if (nCvport >= 2)
{
    acedTrans(asDblArray(maxPt), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(maxPt));
    acedTrans(asDblArray(minPt), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(minPt));
}

es = pPSV->setPlotWindowArea(pPlotSettings, minPt.x, minPt.y, maxPt.x, maxPt.y);

未完待补充

其它的wcs和ucs的待补充

GetClosestPointTo() on a BlockReference returns which coordinate system in AutoCAD using ObjectARX

Issue

Why are the coordinates of a closest point (using GetClosestPointTo()) obtained from a block reference relative to neither WCS nor UCS?

Solution
HTML
1
2
3
4
5
6
7
8
The points that you receive are relative to the coordinate system of the owning
AcDbBlockTableRecord. If you want to convert them to coordinate system of the
AcDbBlockTableRecord in which you have the AcDbBlockReference, you must
transform them by the AcDbBlockReference::blockTransform().

You probably first want to transform the "specified point" by the inverse of
AcDbBlockReference::blockTransform(), do the closest point calculation, then
convert the resulting point back to the original space.

CXTPPropertyGrid控件使用

xtp配置

C++
1
2
3
4
5
6
7
8
9
inc 默认安装目录
C:\Program Files (x86)\Codejock Software\MFC\Xtreme ToolkitPro v20.3.0\Source
lib 默认安装目录
C:\Program Files (x86)\Codejock Software\MFC\Xtreme ToolkitPro v20.3.0\Lib\vc150x64
在stdafx.h中添加

#include <XTToolkitPro.h>

//#include "arxHeaders.h"

image-20240401160031481

在对话框中拉一个picture control控件

client Edge设置为true visible 设置为false

DDX_Control(pDX, IDC_PLACEHOLDER, m_wndPlaceHolder);

加载控件

C++
CString strVal;
//map<pair<int, int>, CString> mp = GetXrecord();
vector<CString> vec{ _T("类型"), _T("长"), _T("宽"), _T("高"), _T("其它"), _T("其它1"), _T("其它2"), _T("其它3"), _T("其它4"), _T("其它5"), _T("其它6"), _T("其它7"), _T("其它8") };
CRect rc;
m_wndPlaceHolder.GetWindowRect(&rc);
ScreenToClient(&rc);

if (m_wndPropertyGrid.Create(rc, this, IDC_PROPERTY_GRID))
{
    m_wndPropertyGrid.SetVariableItemsHeight(TRUE);

    LOGFONT lf;
    GetFont()->GetLogFont(&lf);

    CXTPPropertyGridItem* pStandard = m_wndPropertyGrid.AddCategory(_T("属性数据"));
    pStandard->AddChildItem(new CXTPPropertyGridItem(_T("String item"), _T("测试")));
    pStandard->AddChildItem(new CXTPPropertyGridItemNumber(_T("Integer item")));
    pStandard->AddChildItem(new CXTPPropertyGridItemDouble(_T("Double item")));

    //下拉框
    CXTPPropertyGridItem* pItem = pStandard->AddChildItem(
        new CXTPPropertyGridItemEnum(_T("Enum item"), 2));
    pItem->GetConstraints()->AddConstraint(_T("一型"), 1);
    pItem->GetConstraints()->AddConstraint(_T("L型"), 2);
    pItem->GetConstraints()->AddConstraint(_T("R型"), 3);
    //////////////////////////////////////////////////////////////////////////


    //下拉形式
    //CXTPPropertyGridItem* pItemLanguage = pStandard->AddChildItem(new CXTPPropertyGridItem(strLabel, strDeFault));
    //CXTPPropertyGridItemConstraints* pList = pItemLanguage->GetConstraints();
    //for (auto it : tmpVec)
    //{
    //    pList->AddConstraint(it);
    //}
    //pItemLanguage->SetFlags(xtpGridItemHasComboButton | xtpGridItemHasEdit);

    //pStandard->Expand();
}
  • 隐藏Category
C++
m_wndPropertyGrid.SetPropertySort(xtpGridSortNoSort);//将Category隐藏
  • 清空所有数据
C++
m_wndPropertyGrid.ResetContent();
  • 读取数据
C++
//读取数据
CString strItem;        
CXTPPropertyGridItem* pItems = m_wndPropertyGrid.GetItem(0);
if (pItems != NULL)
{
    int nCount = pItems->GetChilds()->GetCount();
    for (int i = 0; i < nCount; i++)
    {
        CXTPPropertyGridItem* pItem = pItems->GetChilds()->GetAt(i);
        strItem = pItem->GetCaption();
        strVal = pItem->GetValue();
        acutPrintf(_T("\nitem:%s,val:%s"), strItem, strVal);
    }
}
  • 消息响应
C++
ON_MESSAGE(XTPWM_PROPERTYGRID_NOTIFY, OnGridNotify)
C++
LRESULT CDlgShowTk::OnGridNotify(WPARAM wParam, LPARAM lParam)
{
    if (wParam == XTP_PGN_ITEMVALUE_CHANGED)
    {
        CXTPPropertyGridItem* pItem = (CXTPPropertyGridItem*)lParam;
        TRACE(_T("Value Changed. Caption = %s, ID = %i, Value = %s\n"), pItem->GetCaption(),
            pItem->GetID(), pItem->GetValue());

        if (DYNAMIC_DOWNCAST(CXTPPropertyGridItemEnum, pItem))
        {
            if (pItem->GetMetrics(TRUE, FALSE))
            {
                pItem->GetMetrics(TRUE, FALSE)->m_nImage =
                    ((CXTPPropertyGridItemEnum*)pItem)->GetEnum();
            }
        }

        if (pItem->GetID() == 501) // Dynamic Options
        {
            CXTPPropertyGridItems* pSiblingItems = pItem->GetParentItem()->GetChilds();

            for (int i = 0; i < pSiblingItems->GetCount(); i++)
            {
                if (pSiblingItems->GetAt(i) != pItem)
                {
                    pSiblingItems->GetAt(i)->SetHidden(
                        !((CXTPPropertyGridItemBool*)pItem)->GetBool());
                }
            }
        }
    }
    if (wParam == XTP_PGN_EDIT_CHANGED)
    {
        CXTPPropertyGridInplaceEdit* pEdit = DYNAMIC_DOWNCAST(CXTPPropertyGridInplaceEdit,
            (CWnd*)lParam);
        if (pEdit && pEdit->GetItem())
        {
            // Custom Validation
            if (pEdit->GetItem()->GetID() == ID_ITEM_VERSION_LANGUAGE)
            {
                CString str;
                pEdit->CEdit::GetWindowText(str);

                if (str.GetLength() > 30)
                {
                    MessageBeep((UINT)-1);
                    pEdit->SetSel(0, -1);
                    pEdit->ReplaceSel(str.Left(30));
                }
            }
            // Custom Validation
            if (pEdit->GetItem()->GetCaption() == _T("ItemsInMRUList"))
            {
                CString str;
                pEdit->CEdit::GetWindowText(str);

                int i = _ttoi(str);
                if (i > 20)
                {
                    MessageBeep((UINT)-1);
                    pEdit->SetSel(0, -1);
                    pEdit->ReplaceSel(_T("20"));
                }
            }
        }
    }
    return 0;
}

联动修改

ID_ITEM_CORNER ID_ITEM_CONFIG 在resource.h中定义

C++
LRESULT CDlgCategory::OnGridNotify(WPARAM wParam, LPARAM lParam)
{
    if (wParam == XTP_PGN_ITEMVALUE_CHANGED)
    {
        CXTPPropertyGridItem* pItem = (CXTPPropertyGridItem*)lParam;
        if (pItem->GetID() == ID_ITEM_CONFIG) // Dynamic Options
        {
            CString strConfig = pItem->GetValue();
            CXTPPropertyGridItems* pSiblingItems = pItem->GetParentItem()->GetChilds();

            for (int i = 0; i < pSiblingItems->GetCount(); i++)
            {
                if (pSiblingItems->GetAt(i)->GetID() == ID_ITEM_CORNER)
                {
                    //我们在选择了“一型”就自动关联选择下面转角的”否“;选择其余配置就是自动关联选择“是”。
                    //The Cognitive Complexity of this function is 16 which is greater than 15 authorized.
                    pSiblingItems->GetAt(i)->SetValue(
                        (strConfig.CompareNoCase(_T("一型")) == 0) ? _T("否") : _T("是"));
                }
            }
        }
    }
    return 0;
}
  • 参考C:\Program Files (x86)\Codejock Software\MFC\Xtreme ToolkitPro v20.3.0\Samples\PropertyGrid\GridSample\PropertyGrid_vc150.sln里的PropertyGrid

CAD.net 处理菜单相关功能

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        ToolbarButton buttonCopy = barModify.AddToolbarButton(-1, "复制", "ID_MyCopy");
        ToolbarButton buttonErase = barModify.AddToolbarButton(-1, "删除", "ID_MyErase");
        ToolbarButton buttonMove = barModify.AddToolbarButton(-1, "移动", "ID_MyMove");
        ToolbarButton buttonRotate = barModify.AddToolbarButton(-1, "旋转", "ID_MyRotate");
        //将“修改工具栏”附着到“我的工具栏”的最后
        barDraw.AttachToolbarToFlyout(-1, barModify);
        //barDraw.ToolbarVisible = ToolbarVisible.show;
        cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单
    }
    [CommandMethod("AddDoubleClick")]
    public void AddDoubleClick()
    {
        //装载局部CUI文件,若不存在,则创建
        CustomizationSection cs = activeDoc.AddCui(cuiFile, menuGroupName);
        //添加表示双击多段线动作的命令宏  
        MenuMacro macro = cs.AddMacro("多段线 - 双击", "^C^C_DoubleClickPline ", "ID_PlineDoubleClick", "调用自定义命令", null);
        //创建双击动作
        DoubleClickAction action = new DoubleClickAction(cs.MenuGroup, "优化多段线", -1);
        action.ElementID = "EID_mydblclick";//双击动作的标识号
        //设置双击动作的对象为多段线
        action.DxfName = RXClass.GetClass(typeof(Polyline)).DxfName;
        //创建一个双击命令对象,指定双击对象时执行的命令宏
        DoubleClickCmd cmd = new DoubleClickCmd(action, macro);
        action.DoubleClickCmd = cmd;//指定双击动作的命令对象
        cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单
    }
    [CommandMethod("DoubleClickPline")]
    public void DoubleClickPline()
    {
        Application.ShowAlertDialog("你双击了多段线!");
    }
    [CommandMethod("AddDefaultContextMenu")]
    public void AddDefaultContextMenu()
    {
        //定义一个ContextMenuExtension对象,用于表示快捷菜单
        ContextMenuExtension contextMenu = new ContextMenuExtension();
        contextMenu.Title = "我的快捷菜单";//设置快捷菜单的标题
        MenuItem mi = new MenuItem("复制");//添加名为"复制"的菜单项
        //为"复制"菜单项添加单击事件
        mi.Click += new EventHandler(mi_Click);
        contextMenu.MenuItems.Add(mi);//将"复制"菜单项添加到快捷菜单中
        mi = new MenuItem("删除");//添加名为"删除"的菜单项
        //mi.Icon = new Icon(GetProgramDir() + "\\Image\\copy.ico");
        //为"删除"菜单项添加单击事件
        mi.Click += new EventHandler(mi_Click);
        contextMenu.MenuItems.Add(mi);//将"删除"菜单项添加到快捷菜单中
        //为应用程序添加定义的快捷菜单
        Application.AddDefaultContextMenuExtension(contextMenu);
    }
    void mi_Click(object sender, EventArgs e)
    {
        MenuItem mi = sender as MenuItem;//获取发出命令的快捷菜单项
        //根据快捷菜单项的名字,分别调用对应的命令
        if (mi.Text == "复制")
            activeDoc.SendStringToExecute("_Copy ", true, false, true);
        else if (mi.Text == "删除")
            activeDoc.SendStringToExecute("_Erase ", true, false, true);
    }
    [CommandMethod("AddObjectContextMenu")]
    public void AddObjectContextMenu()
    {
        //定义一个ContextMenuExtension对象,用于表示快捷菜单
        ContextMenuExtension contextMenu = new ContextMenuExtension();
        //添加一个名为"统计个数"的菜单项,用于在AutoCAD命令行上显示所选择实体的个数
        MenuItem miCircle = new MenuItem("统计个数");
        //为"统计个数"菜单项添加单击事件,事件处理函数为调用自定义的Count命令
        miCircle.Click += delegate (object sender, EventArgs e)
        {
            activeDoc.SendStringToExecute("_Count ", true, false, false);
        };
        contextMenu.MenuItems.Add(miCircle);//将"统计个数"菜单项添加到快捷菜单中
        //获得实体所属的RXClass类型
        RXClass rx = RXClass.GetClass(typeof(Entity));
        //为实体对象添加定义的快捷菜单
        Application.AddObjectContextMenuExtension(rx, contextMenu);
    }
    [CommandMethod("Count", CommandFlags.UsePickSet)]
    public void CountEnts()
    {
        Editor ed = activeDoc.Editor;
        PromptSelectionResult result = ed.SelectImplied();
        if (result.Status == PromptStatus.OK)
            ed.WriteMessage("共选择了" + result.Value.Count + "个实体\n");
    }
}

} `CUITools.cs` ​csharp using System.Collections.Specialized; using System.IO; using ZwSoft.ZwCAD.ApplicationServices; using ZwSoft.ZwCAD.Customization; namespace CuiDemo { ///

/// 操作CUI的类 /// public static class CUITools { [DllImport("zwcad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "zcedPostCommand")] extern static private int zcedPostCommand(string strExpr); /// /// 调用C++的acedPostCommand函数 /// /// 无意义,只是为了定义扩展函数 /// 要执行的命令字符串 public static void PostCommand(this Editor ed, string expression) { zcedPostCommand(expression); } /// /// 获取并打开主CUI文件 /// /// AutoCAD文档对象 /// 返回主CUI文件 public static CustomizationSection GetMainCustomizationSection(this Document doc) { //获得主CUI文件所在的位置 string mainCuiFile=Application.GetSystemVariable("MENUNAME") + ".cuix"; //打开主CUI文件 return new CustomizationSection(mainCuiFile); } /// /// 创建局部CUI文件 /// /// AutoCAD文档对象 /// CUI文件名 /// 菜单组的名称 /// 返回创建的CUI文件 public static CustomizationSection AddCui(this Document doc, string cuiFile, string menuGroupName) { CustomizationSection cs;//声明CUI文件对象 if (!File.Exists(cuiFile))//如果要创建的文件不存在 { cs = new CustomizationSection();//创建CUI文件对象 cs.MenuGroupName = menuGroupName;//指定菜单组名称 cs.SaveAs(cuiFile);//保存CUI文件 } //如果已经存在指定的CUI文件,则打开该文件 else cs = new CustomizationSection(cuiFile); return cs;//返回CUI文件对象 } /// /// 装载指定的局部CUI文件 /// /// CUI文件 public static void LoadCui(this CustomizationSection cs) { if (cs.IsModified) cs.Save();//如果CUI文件被修改,则保存 //保存CMDECHO及FILEDIA系统变量 object oldCmdEcho = Application.GetSystemVariable("CMDECHO"); object oldFileDia = Application.GetSystemVariable("FILEDIA"); //设置CMDECHO=0,控制不在命令行上回显提示和输入信息 Application.SetSystemVariable("CMDECHO", 0); //设置FILEDIA=0,禁止显示文件对话框,这样可以通过程序输入文件名 Application.SetSystemVariable("FILEDIA", 0); //获取当前活动文档 Document doc=Application.DocumentManager.MdiActiveDocument; //获取主CUI文件 CustomizationSection mainCs=doc.GetMainCustomizationSection(); //如果已存在局部CUI文件,则先卸载 if (mainCs.PartialCuiFiles.Contains(cs.CUIFileName)) doc.SendStringToExecute(".cuiunload " + cs.CUIFileBaseName + " ", false, false, false); //装载CUI文件,注意文件名必须是带路径的 doc.SendStringToExecute(".cuiload " + cs.CUIFileName + " ", false, false, false); //恢复CMDECHO及FILEDIA系统变量的初始值 doc.SendStringToExecute("(setvar \"FILEDIA\" " + oldFileDia.ToString() + ")(princ) ", false, false, false); doc.SendStringToExecute("(setvar \"CMDECHO\" " + oldCmdEcho.ToString() + ")(princ) ", false, false, false); } /// /// 添加菜单项所要执行的宏 /// /// CUI文件 /// 宏的显示名称 /// 宏的具体命令 /// 宏的标识符 /// 宏的状态栏提示信息 /// 宏的图标 /// 返回创建的宏 public static MenuMacro AddMacro(this CustomizationSection source, string name, string command, string tag, string helpString, string imagePath) { MenuGroup menuGroup=source.MenuGroup;//获取CUI文件中的菜单组 //判断菜单组中是否已经定义与菜单组名相同的宏集合 MacroGroup mg=menuGroup.FindMacroGroup(menuGroup.Name); if (mg == null)//如果宏集合没有定义,则创建一个与菜单组名相同的宏集合 mg = new MacroGroup(menuGroup.Name, menuGroup); //如果已经宏已经被定义,则返回 foreach (MenuMacro macro in mg.MenuMacros) { if (macro.ElementID == tag) return null; } //在宏集合中创建一个命令宏 MenuMacro MenuMacro=new MenuMacro(mg, name, command, tag); //指定命令宏的说明信息,在状态栏中显示 MenuMacro.macro.HelpString = helpString; //指定命令宏的大小图像的路径 MenuMacro.macro.LargeImage = MenuMacro.macro.SmallImage = imagePath; return MenuMacro;//返回命令宏 } /// /// 添加下拉菜单 /// /// 包含菜单的菜单组 /// 菜单名 /// 菜单的别名 /// 菜单的标识字符串 /// 返回下拉菜单对象 public static PopMenu AddPopMenu(this MenuGroup menuGroup, string name, StringCollection aliasList, string tag) { PopMenu pm=null;//声明下拉菜单对象 //如果菜单组中没有名称为name的下拉菜单 if (menuGroup.PopMenus.IsNameFree(name)) { //为下拉菜单指定显示名称、别名、标识符和所属的菜单组 pm = new PopMenu(name, aliasList, tag, menuGroup); } return pm;//返回下拉菜单对象 } /// /// 为菜单添加菜单项 /// /// 菜单项所属的菜单 /// 菜单项的位置 /// 菜单项的显示名称 /// 菜单项的命令宏的Id /// 返回添加的菜单项 public static PopMenuItem AddMenuItem(this PopMenu parentMenu, int index, string name, string macroId) { PopMenuItem newPmi=null; //如果存在名为name的菜单项,则返回 foreach (PopMenuItem pmi in parentMenu.PopMenuItems) if (pmi.Name == name) return newPmi; //定义一个菜单项对象,指定所属的菜单及位置 newPmi = new PopMenuItem(parentMenu, index); ////如果name不为空,则指定菜单项的显示名为name,否则会使用命令宏的名称 if (name != null) newPmi.Name = name; newPmi.MacroID = macroId;//菜单项的命令宏的ID

CAD.net 处理菜单相关功能

PixPin_2024-10-24_15-37-38 PixPin_2024-10-24_15-37-56

csharp [CommandMethod("AddMenu")] public void AddMenu() { string currentPath = GetProgramDir();//当前运行目录 //装载局部CUI文件,若不存在,则创建 CustomizationSection cs = activeDoc.AddCui(cuiFile, menuGroupName); //添加表示绘制直线、多段线、矩形和圆的命令宏 cs.AddMacro("直线", "^C^C_Line ", "ID_MyLine", "创建直线段: LINE", currentPath + "\\Image\\Line.BMP"); cs.AddMacro("多段线", "^C^C_Pline ", "ID_MyPLine", "创建二维多段线: PLINE", currentPath + "\\Image\\Polyline.BMP"); cs.AddMacro("矩形", "^C^C_Rectang ", "ID_MyRectang", "创建矩形多段线: RECTANG", currentPath + "\\Image\\Rectangle.BMP"); cs.AddMacro("圆", "^C^C_circle ", "ID_MyCircle", "用指定半径创建圆: CIRCLE", currentPath + "\\Image\\Circle.BMP"); //添加表示复制、删除、移动及旋转操作的命令宏 cs.AddMacro("复制", "^C^CCopy ", "ID_MyCopy", "复制对象: COPY", currentPath + "\\Image\\Copy.BMP"); cs.AddMacro("删除", "^C^CErase ", "ID_MyErase", "从图形删除对象: ERASE", currentPath + "\\Image\\Erase.BMP"); cs.AddMacro("移动", "^C^CMove ", "ID_MyMove", "将对象在指定方向上平移指定的距离: MOVE", currentPath + "\\Image\\Move.BMP"); cs.AddMacro("旋转", "^C^CRotate ", "ID_MyRotate", "绕基点旋转对象: ROTATE", currentPath + "\\Image\\Rotate.BMP"); //设置用于下拉菜单别名的字符串集合 StringCollection sc = new StringCollection(); sc.Add("MyPop1"); //添加名为“我的菜单”的下拉菜单,如果已经存在,则返回null PopMenu myMenu = cs.MenuGroup.AddPopMenu("我的菜单", sc, "ID_MyMenu"); if (myMenu != null)//如果“我的菜单”还没有被添加,则添加菜单项 { //从上到下为“我的菜单”添加绘制直线、多段线、矩形和圆的菜单项 myMenu.AddMenuItem(-1, "直线", "ID_MyLine"); myMenu.AddMenuItem(-1, "多段线", "ID_MyPLine"); myMenu.AddMenuItem(-1, "矩形", "ID_MyRectang"); myMenu.AddMenuItem(-1, "圆", "ID_MyCircle"); myMenu.AddSeparator(-1);//为菜单添加一分隔条 //添加一个名为“修改”的子菜单 PopMenu menuModify = myMenu.AddSubMenu(-1, "修改", "ID_MyModify"); //从上到下为“修改”子菜单添加复制、删除、移动及旋转操作的菜单项 menuModify.AddMenuItem(-1, "复制", "ID_MyCopy"); menuModify.AddMenuItem(-1, "删除", "ID_MyErase"); menuModify.AddMenuItem(-1, "移动", "ID_MyMove"); menuModify.AddMenuItem(-1, "旋转", "ID_MyRotate"); } cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单 }

增加toolbar

C#
[CommandMethod("AddToolbar")]
public void AddToolbar()
{
    //装载局部CUI文件,若不存在,则创建
    CustomizationSection cs = activeDoc.AddCui(cuiFile, menuGroupName);
    //添加名为“我的工具栏”的工具栏
    Toolbar barDraw = cs.MenuGroup.AddToolbar("我的工具栏");
    if (barDraw == null)
        return;
    //为“我的工具栏”添加绘制直线、多段线、矩形和圆的按钮
    barDraw.AddToolbarButton(-1, "直线", "ID_MyLine");
    barDraw.AddToolbarButton(-1, "多段线", "ID_MyPLine");
    barDraw.AddToolbarButton(-1, "矩形", "ID_MyRectang");
    barDraw.AddToolbarButton(-1, "圆", "ID_MyCircle");
    //添加名为“修改工具栏”的工具栏,用于弹出式工具栏
    Toolbar barModify = cs.MenuGroup.AddToolbar("修改工具栏");
    if (barModify == null)
    {
        cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单
        return;
    }
    //为“修改工具栏”添加复制、删除、移动及旋转操作的按钮
    ToolbarButton buttonCopy = barModify.AddToolbarButton(-1, "复制", "ID_MyCopy");
    ToolbarButton buttonErase = barModify.AddToolbarButton(-1, "删除", "ID_MyErase");
    ToolbarButton buttonMove = barModify.AddToolbarButton(-1, "移动", "ID_MyMove");
    ToolbarButton buttonRotate = barModify.AddToolbarButton(-1, "旋转", "ID_MyRotate");
    //将“修改工具栏”附着到“我的工具栏”的最后
    barDraw.AttachToolbarToFlyout(-1, barModify);
    //barDraw.ToolbarVisible = ToolbarVisible.show;
    cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单
}

增加右键菜单

C#
[CommandMethod("AddDefaultContextMenu")]
public void AddDefaultContextMenu()
{
    //定义一个ContextMenuExtension对象,用于表示快捷菜单
    ContextMenuExtension contextMenu = new ContextMenuExtension();
    contextMenu.Title = "我的快捷菜单";//设置快捷菜单的标题
    MenuItem mi = new MenuItem("复制");//添加名为"复制"的菜单项
    //为"复制"菜单项添加单击事件
    mi.Click += new EventHandler(mi_Click);
    contextMenu.MenuItems.Add(mi);//将"复制"菜单项添加到快捷菜单中
    mi = new MenuItem("删除");//添加名为"删除"的菜单项
    //mi.Icon = new Icon(GetProgramDir() + "\\Image\\copy.ico");
    //为"删除"菜单项添加单击事件
    mi.Click += new EventHandler(mi_Click);
    contextMenu.MenuItems.Add(mi);//将"删除"菜单项添加到快捷菜单中
    //为应用程序添加定义的快捷菜单
    Application.AddDefaultContextMenuExtension(contextMenu);
}
void mi_Click(object sender, EventArgs e)
{
    MenuItem mi = sender as MenuItem;//获取发出命令的快捷菜单项
    //根据快捷菜单项的名字,分别调用对应的命令
    if (mi.Text == "复制")
        activeDoc.SendStringToExecute("_Copy ", true, false, true);
    else if (mi.Text == "删除")
        activeDoc.SendStringToExecute("_Erase ", true, false, true);
}

完整代码如下所示:

image-20241024163522376

Class1.cs

C#
using System;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using ZwSoft.ZwCAD.ApplicationServices;
using ZwSoft.ZwCAD.Customization;
using ZwSoft.ZwCAD.DatabaseServices;
using ZwSoft.ZwCAD.EditorInput;
using ZwSoft.ZwCAD.Runtime;
using ZwSoft.ZwCAD.Windows;

namespace CuiDemo
{
    public class Class1
    {
        //设置CUI文件的名字,将其路径设置为当前运行目录
        string cuiFile = GetProgramDir() + "\\MyCustom.cuix";
        string menuGroupName = "MyCustom";//菜单组名
        //获得活动文档
        Document activeDoc = ZwSoft.ZwCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument;
        public static string GetProgramDir()
        {
            string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            return directory;
        }
        public Class1()
        {
            //添加程序退出时事件处理
            Application.QuitWillStart += new EventHandler(Application_QuitWillStart);
        }
        void Application_QuitWillStart(object sender, EventArgs e)
        {
            //由于触发此事件前文档已关闭,所以需通过模板重建,以便命令能够执行
            Document doc = Application.DocumentManager.Add("acadiso.dwt");
            //获取FILEDIA系统变量的值
            object oldFileDia = Application.GetSystemVariable("FILEDIA");
            //设置FILEDIA = 0,禁止显示文件对话框,这样可以通过程序输入文件名
            Application.SetSystemVariable("FILEDIA", 0);
            //获取主CUI
            CustomizationSection mainCs = doc.GetMainCustomizationSection();
            //如果存在指定的局部CUI文件,则进行卸载
            if (mainCs.PartialCuiFiles.Contains(cuiFile))
                doc.Editor.PostCommand("cuiunload " + menuGroupName + " ");
            //doc.SendStringToExecute("cuiunload " + menuGroupName + " ", false, false, false);
            //恢复FILEDIA系统变量的值
            Application.SetSystemVariable("FILEDIA", oldFileDia);
        }
        [CommandMethod("AddMenu")]
        public void AddMenu()
        {
            string currentPath = GetProgramDir();//当前运行目录
            //装载局部CUI文件,若不存在,则创建
            CustomizationSection cs = activeDoc.AddCui(cuiFile, menuGroupName);
            //添加表示绘制直线、多段线、矩形和圆的命令宏            
            cs.AddMacro("直线", "^C^C_Line ", "ID_MyLine", "创建直线段:   LINE", currentPath + "\\Image\\Line.BMP");
            cs.AddMacro("多段线", "^C^C_Pline ", "ID_MyPLine", "创建二维多段线:  PLINE", currentPath + "\\Image\\Polyline.BMP");
            cs.AddMacro("矩形", "^C^C_Rectang ", "ID_MyRectang", "创建矩形多段线:  RECTANG", currentPath + "\\Image\\Rectangle.BMP");
            cs.AddMacro("圆", "^C^C_circle ", "ID_MyCircle", "用指定半径创建圆:   CIRCLE", currentPath + "\\Image\\Circle.BMP");
            //添加表示复制、删除、移动及旋转操作的命令宏
            cs.AddMacro("复制", "^C^CCopy ", "ID_MyCopy", "复制对象:   COPY", currentPath + "\\Image\\Copy.BMP");
            cs.AddMacro("删除", "^C^CErase ", "ID_MyErase", "从图形删除对象:   ERASE", currentPath + "\\Image\\Erase.BMP");
            cs.AddMacro("移动", "^C^CMove ", "ID_MyMove", "将对象在指定方向上平移指定的距离:  MOVE", currentPath + "\\Image\\Move.BMP");
            cs.AddMacro("旋转", "^C^CRotate ", "ID_MyRotate", "绕基点旋转对象:  ROTATE", currentPath + "\\Image\\Rotate.BMP");
            //设置用于下拉菜单别名的字符串集合
            StringCollection sc = new StringCollection();
            sc.Add("MyPop1");
            //添加名为“我的菜单”的下拉菜单,如果已经存在,则返回null
            PopMenu myMenu = cs.MenuGroup.AddPopMenu("我的菜单", sc, "ID_MyMenu");
            if (myMenu != null)//如果“我的菜单”还没有被添加,则添加菜单项
            {
                //从上到下为“我的菜单”添加绘制直线、多段线、矩形和圆的菜单项
                myMenu.AddMenuItem(-1, "直线", "ID_MyLine");
                myMenu.AddMenuItem(-1, "多段线", "ID_MyPLine");
                myMenu.AddMenuItem(-1, "矩形", "ID_MyRectang");
                myMenu.AddMenuItem(-1, "圆", "ID_MyCircle");
                myMenu.AddSeparator(-1);//为菜单添加一分隔条
                //添加一个名为“修改”的子菜单
                PopMenu menuModify = myMenu.AddSubMenu(-1, "修改", "ID_MyModify");
                //从上到下为“修改”子菜单添加复制、删除、移动及旋转操作的菜单项
                menuModify.AddMenuItem(-1, "复制", "ID_MyCopy");
                menuModify.AddMenuItem(-1, "删除", "ID_MyErase");
                menuModify.AddMenuItem(-1, "移动", "ID_MyMove");
                menuModify.AddMenuItem(-1, "旋转", "ID_MyRotate");
            }
            cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单
        }
        [CommandMethod("AddToolbar")]
        public void AddToolbar()
        {
            //装载局部CUI文件,若不存在,则创建
            CustomizationSection cs = activeDoc.AddCui(cuiFile, menuGroupName);
            //添加名为“我的工具栏”的工具栏
            Toolbar barDraw = cs.MenuGroup.AddToolbar("我的工具栏");
            if (barDraw == null)
                return;
            //为“我的工具栏”添加绘制直线、多段线、矩形和圆的按钮
            barDraw.AddToolbarButton(-1, "直线", "ID_MyLine");
            barDraw.AddToolbarButton(-1, "多段线", "ID_MyPLine");
            barDraw.AddToolbarButton(-1, "矩形", "ID_MyRectang");
            barDraw.AddToolbarButton(-1, "圆", "ID_MyCircle");
            //添加名为“修改工具栏”的工具栏,用于弹出式工具栏
            Toolbar barModify = cs.MenuGroup.AddToolbar("修改工具栏");
            if (barDraw == null)
{
    cs.LoadCui();//必须装载CUI文件,才能看到添加的菜单
    return;
}
            //为“修改工具栏”添加复制、删除、移动及旋转操作的按钮
            return newPmi;//返回菜单项对象
        }

        /// <summary>
        /// 为下拉菜单添加子菜单
        /// </summary>
        /// <param name="parentMenu">下拉菜单</param>
        /// <param name="index">子菜单的位置</param>
        /// <param name="name">子菜单的显示名称</param>
        /// <param name="tag">子菜单的标识字符串</param>
        /// <returns>返回添加的子菜单</returns>
        public static PopMenu AddSubMenu(this PopMenu parentMenu, int index, string name, string tag)
        {
            PopMenu pm=null;//声明子菜单对象(属于下拉菜单类)
            //如果菜单组中没有名称为name的下拉菜单
            if (parentMenu.CustomizationSection.MenuGroup.PopMenus.IsNameFree(name))
            {
                //为子菜单指定显示名称、标识符和所属的菜单组,别名设为null
                pm = new PopMenu(name, null, tag, parentMenu.CustomizationSection.MenuGroup);
                //为子菜单指定其所属的菜单
                PopMenuRef menuRef=new PopMenuRef(pm, parentMenu, index);
            }
            return pm;//返回子菜单对象
        }

        /// <summary>
        /// 为菜单添加分隔条
        /// </summary>
        /// <param name="parentMenu">下拉菜单</param>
        /// <param name="index">分隔条的位置</param>
        /// <returns>返回添加的分隔条</returns>
        public static PopMenuItem AddSeparator(this PopMenu parentMenu, int index)
        {
            //定义一个分隔条并返回
            return new PopMenuItem(parentMenu, index);
        }

        /// <summary>
        /// 添加工具栏
        /// </summary>
        /// <param name="menuGroup">工具栏所属的菜单组</param>
        /// <param name="name">工具栏的显示名称</param>
        /// <returns>返回添加的工具栏</returns>
        public static Toolbar AddToolbar(this MenuGroup menuGroup, string name)
        {
            Toolbar tb=null;//声明一个工具栏对象
            //如果菜单组中没有名称为name的工具栏
            if (menuGroup.Toolbars.IsNameFree(name))
            {
                //为工具栏指定显示名称和所属的菜单组
                tb = new Toolbar(name, menuGroup);
                //设置工具栏为浮动工具栏
                tb.ToolbarOrient = ToolbarOrient.floating;
                //设置工具栏可见
                tb.ToolbarVisible = ToolbarVisible.show;
            }
            return tb;//返回工具栏对象
        }

        /// <summary>
        /// 向工具栏添加按钮
        /// </summary>
        /// <param name="parent">按钮所属的工具栏</param>
        /// <param name="index">按钮在工具栏上的位置</param>
        /// <param name="name">按钮的显示名称</param>
        /// <param name="macroId">按钮的命令宏的Id</param>
        /// <returns>返回工具栏按钮对象</returns>
        public static ToolbarButton AddToolbarButton(this Toolbar parent, int index, string name, string macroId)
        {
            //创建一个工具栏按钮对象,指定其命令宏Id、显示名称、所属的工具栏和位置
            ToolbarButton button=new ToolbarButton(macroId, name, parent, index);
            return button;//返回工具栏按钮对象
        }

        /// <summary>
        /// 向工具栏添加弹出式工具栏
        /// </summary>
        /// <param name="parent">工具栏所属的父工具栏</param>
        /// <param name="index">弹出式工具栏在父工具栏上的位置</param>
        /// <param name="toolbarRef">弹出式工具栏所引用的工具栏</param>
        public static void AttachToolbarToFlyout(this Toolbar parent, int index, Toolbar toolbarRef)
        {
            //创建一个弹出式工具栏,指定其所属的工具栏和位置
            ToolbarFlyout flyout=new ToolbarFlyout(parent, index);
            //指定弹出式工具栏所引用的工具栏 
            flyout.ToolbarReference = toolbarRef.Name;
            //引用的工具栏初始状态不可见
            toolbarRef.ToolbarVisible = ToolbarVisible.show;
        }
    }
}

找到PostCommand

打开命令行

image-20241119092752464

将目录切换到CAD安装目录

运行命令

Bash
dumpbin.exe /exports zwcad.exe >D:\zwcad.txt

对照txt中zcedPostCommand的函数,写出如下代码:

C#
[DllImport("zwcad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "zcedPostCommand")]
extern static private int zcedPostCommand(string strExpr);
/// <summary>
/// 调用C++的acedPostCommand函数
/// </summary>
/// <param name="ed">无意义,只是为了定义扩展函数</param>
/// <param name="expression">要执行的命令字符串</param>
public static void PostCommand(this Editor ed, string expression)
{
    zcedPostCommand(expression);
}

WPF里引用svg图标

第一种方式

引入xmlns:svgc="http://sharpvectors.codeplex.com/svgc/" https://elinamllc.github.io/SharpVectors/articles/index.html

下载sharpvectors

C#
<Image Source="{svgc:SvgImage Source=/Images/SVG/email 33.svg}" />

第二种方式

将Path路径提出来,设置key值,放置在资源里

C#
<Window.Resources>
    <!--Close Image-->
    <PathFigureCollection x:Key="ClosePathData">
        M482.048 0h64v533.333h-64V0z
        M695.381 132.864v54.187c128 69.845 225.494 208.618 225.494 368.469 0 230.08-184.939 416.64-415.019 416.64-230.123 0-406.016-186.56-406.016-416.64 0-159.85 83.541-298.624 232.875-368.47v-54.186C162.048 206.528 52.075 368 52.075 555.52c0 256.96 203.37 465.259 460.33 465.259 256.939 0 459.52-208.299 459.52-465.259 0-187.52-105.877-348.992-276.544-422.656z
    </PathFigureCollection>
    <DrawingImage x:Key="CloseImage">
        <DrawingImage.Drawing>
            <GeometryDrawing>
                <GeometryDrawing.Brush>
                    <SolidColorBrush  Color="#666D73"/>
                </GeometryDrawing.Brush>
                <GeometryDrawing.Geometry>
                    <PathGeometry FillRule="Nonzero"  Figures="{StaticResource ClosePathData}" />
                </GeometryDrawing.Geometry>
            </GeometryDrawing>
        </DrawingImage.Drawing>
    </DrawingImage>
</Window.Resources>

多条Path就放多个PathFigureCollection里,使用时,直接调用

C#
<Image Source="{StaticResource CloseImage}" />

显示图标

使用SvgToXaml工具

资源文件

C#
 <!--  Close Image  -->
        <PathFigureCollection x:Key="ClosePathData">
            M482.048 0h64v533.333h-64V0z
            M695.381 132.864v54.187c128 69.845 225.494 208.618 225.494 368.469 0 230.08-184.939 416.64-415.019 416.64-230.123 0-406.016-186.56-406.016-416.64 0-159.85 83.541-298.624 232.875-368.47v-54.186C162.048 206.528 52.075 368 52.075 555.52c0 256.96 203.37 465.259 460.33 465.259 256.939 0 459.52-208.299 459.52-465.259 0-187.52-105.877-348.992-276.544-422.656z
        </PathFigureCollection>
        <DrawingImage x:Key="CloseImage">
            <DrawingImage.Drawing>
                <GeometryDrawing>
                    <GeometryDrawing.Brush>
                        <SolidColorBrush Color="Gray" />
                    </GeometryDrawing.Brush>
                    <GeometryDrawing.Geometry>
                        <PathGeometry Figures="{StaticResource ClosePathData}" FillRule="Nonzero" />
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingImage.Drawing>
        </DrawingImage>

        <!--BoxIcons_LogosBlenderGeometryKey-->
        <Geometry x:Key="BoxIcons_LogosBlenderGeometryKey">F1 M48,48z M0,0z M530.219,404.864C531.798,433.323 545.707,458.368 566.742,476.16 587.693,493.682 614.924,504.322 644.639,504.322 644.913,504.322 645.187,504.321 645.461,504.319L645.419,504.319C675.712,504.319 703.446,493.652 724.139,476.159 745.131,458.367 759.083,433.279 760.662,404.863 762.283,375.594 750.55,348.415 729.899,328.276 708.276,307.619 678.912,294.906 646.578,294.906 646.185,294.906 645.793,294.908 645.401,294.912L645.461,294.912C645.109,294.908 644.693,294.906 644.277,294.906 611.938,294.906 582.567,307.62 560.892,328.321L560.939,328.277C540.331,348.416,528.555,375.594,530.219,404.864z M346.624,347.264C346.837,336.171 350.421,314.539 355.712,297.6 367.982,259.513 387.391,226.735 412.548,199.316L412.373,199.509C439.559,169.668,472.554,145.638,509.633,129.121L511.487,128.383C549.32,111.262 593.517,101.286 640.045,101.286 640.599,101.286 641.153,101.287 641.706,101.29L641.62,101.29C641.736,101.29 641.874,101.29 642.012,101.29 688.999,101.29 733.619,111.424 773.807,129.625L771.796,128.81C810.672,146.268,843.623,170.392,870.613,200.04L870.826,200.277C895.749,227.577,915.125,260.406,926.878,296.668L927.402,298.538C932.668,314.564,936.452,333.214,938.012,352.493L938.069,353.365C938.518,359.018 938.773,365.605 938.773,372.251 938.773,422.081 924.397,468.553 899.566,507.747L900.18,506.709C882.233,535.122,860.325,559.175,834.892,578.899L834.26,579.37 834.303,579.413 566.996,784.768C549.46,798.165 520.02,798.123 500.82,784.683 481.321,771.072 479.145,748.587 496.383,734.336L496.34,734.293 607.529,643.797 268.116,643.413C240.127,643.413 213.204,624.981 207.871,601.77 202.41,578.09 221.439,558.463 250.58,558.378L250.537,558.25 422.356,558.591 114.516,322.346C85.6310000000001,300.202 76.2870000000001,263.381 94.4630000000001,240.042 112.98,216.319 152.234,216.319 181.503,239.957L348.842,376.874C348.885,376.874,346.453,358.399,346.623,347.263z M776.619,285.397C742.144,250.24 693.931,230.314 641.664,230.229 589.355,230.144 541.141,249.898 506.624,284.97 490.736,300.874 478.188,320.117 470.123,341.556L469.76,342.656C464.013,357.906 460.687,375.534 460.687,393.939 460.687,398.581 460.899,403.174 461.313,407.708L461.27,407.125C463.147,428.672 469.505,449.237 479.787,467.797 489.856,486.101 503.766,502.57 520.832,516.608 553.277,542.868 595.049,558.766 640.534,558.766 640.931,558.766 641.328,558.765 641.725,558.762L641.664,558.762C642.121,558.766 642.661,558.768 643.201,558.768 688.501,558.768 730.118,543.003 762.866,516.66L762.496,516.948C779.52,503.039 793.429,486.612 803.499,468.351 813.739,449.748 820.139,429.268 822.016,407.722 822.385,403.772 822.596,399.18 822.596,394.538 822.596,376.136 819.286,358.507 813.23,342.214L813.568,343.252C805.052,320.672,792.485,301.385,776.609,285.386L776.619,285.396z</Geometry>
        <DrawingGroup x:Key="BoxIcons_LogosBlenderDrawingGroupKey" ClipGeometry="M0,0 V48 H48 V0 H0 Z">
            <DrawingGroup Transform="0.0562308674397924,0,0,-0.0562308674397924,-4.78802069564223,49.1935494114674">
                <GeometryDrawing Brush="#FFD3D3D3" Geometry="{StaticResource BoxIcons_LogosBlenderGeometryKey}">
                    <GeometryDrawing.Pen>
                        <Pen
                            Brush="#FF000000"
                            EndLineCap="Flat"
                            LineJoin="Miter"
                            StartLineCap="Flat"
                            Thickness="1" />
                    </GeometryDrawing.Pen>
                </GeometryDrawing>
            </DrawingGroup>
        </DrawingGroup>
        <DrawingImage x:Key="BoxIcons_LogosBlenderDrawingImageKey" Drawing="{StaticResource BoxIcons_LogosBlenderDrawingGroupKey}" />

image-20240907113623699

C#
 <WrapPanel>
                <Image Margin="0,0,10,0" Source="{StaticResource BoxIcons_LogosBlenderDrawingImageKey}" />
                <Viewbox
                    Grid.Row="1"
                    Grid.Column="2"
                    Margin="0,0,10,0">
                    <Path
                        Data="M839.040 242.731c-13.009-30.022-27.582-55.778-44.492-79.769l0.93 1.39c-22.912-32.725-41.728-55.339-56.149-67.925-22.4-20.565-46.464-31.147-72.192-31.744-18.432 0-40.704 5.248-66.645 15.915-26.027 10.624-49.92 15.829-71.808 15.829-22.912 0-47.488-5.205-73.813-15.829-26.283-10.667-47.531-16.256-63.787-16.768-24.619-1.067-49.237 9.771-73.771 32.597-15.659 13.653-35.243 37.12-58.752 70.315-25.173 35.371-45.867 76.544-62.080 123.349-17.365 50.645-26.069 99.627-26.069 147.072 0 54.315 11.733 101.205 35.243 140.459 18.116 31.030 43.055 56.256 72.877 74.187l0.936 0.522c28.511 17.374 62.912 27.821 99.722 28.244l0.118 0.001c19.627 0 45.355-6.059 77.227-18.005s52.352-18.005 61.269-18.005c6.741 0 29.397 7.125 67.968 21.248 36.395 13.099 67.115 18.517 92.288 16.384 68.267-5.504 119.509-32.384 153.6-80.853-61.013-36.992-91.179-88.747-90.581-155.179 0.512-51.755 19.328-94.805 56.192-128.981 15.812-15.151 34.402-27.559 54.904-36.362l1.202-0.459c-4.523-13.099-9.301-25.6-14.336-37.632zM682.581 858.453c0-40.533-14.848-78.421-44.331-113.451-35.669-41.643-78.763-65.749-125.483-61.952-0.571 4.506-0.896 9.719-0.896 15.009 0 0.124 0 0.247 0.001 0.371v-0.019c0 38.955 16.896 80.597 47.061 114.688 15.019 17.237 34.133 31.616 57.301 43.051 23.125 11.264 44.971 17.493 65.536 18.56 0.555-5.461 0.811-10.88 0.811-16.256z"
                        Fill="Gray"
                        StrokeThickness="1" />
                </Viewbox>
                <Image Margin="0,0,10,0" Source="{StaticResource CloseImage}" />
                <Image Margin="0,0,10,0" Source="{svgc:SvgImage Source=/Images/SVG/email 33.svg}" />
            </WrapPanel>

在Button中使用

C#
 <local:ImageButton
            x:Name="btn_Image"
            Grid.Row="3"
            HorizontalContentAlignment="Center"
            VerticalContentAlignment="Center"
            Background="White"
            Content="播放"
            FontSize="16"
            Foreground="Gray"
            Icon="{StaticResource edit_13DrawingImage}"
            IconContentMargin="10,0,0,0"
            IconHeight="32"
            IconMouseOver="{StaticResource discount_21DrawingImage}"
            IconWidth="32"
            MouseDownForeground="Blue"
            MouseOverForeground="#FFFFFF"
            ToolTip="播放" />
        <local:ButtonEx
            Grid.Row="4"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            ButtonType="IconText"
            Content="11122"
            Icon="{StaticResource discount_21DrawingImage}" />

Rapidjson代码封装

https://github.com/57559684/JsonUtils

基础文件

jsonutils.h

C++
#ifndef JSON_UTILS_H
#define JSON_UTILS_H

#include "rapidjson/document.h"
#include "rapidjson/istreamwrapper.h"
#include "rapidjson/ostreamwrapper.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/prettywriter.h" // for stringify JSON
#include "rapidjson/filewritestream.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/encodings.h"


using namespace rapidjson;
//使用UTF-16的doc,在rapidjson命名空间里包含UTF8的Document和Value的定义,但是不包含UTF16的
typedef rapidjson::GenericDocument<rapidjson::UTF16<>> DocumentW;
typedef rapidjson::GenericValue<rapidjson::UTF16<>> ValueW;
typedef rapidjson::GenericStringStream<rapidjson::UTF16<>> StringStreamW;
typedef rapidjson::GenericStringBuffer<rapidjson::UTF16<>> StringBufferW;


/**
 * Json对象类,封装Json操作的插入等方法
 * 使用范例如下:
 * CJsonUtils json;
 * json["a"] = "a";
 * json["b"] = "123";
 * json["c"] = 123;
 * json["d"] = "1.5";
 * json["e"] = 1.5
 * json["child"]["a"] = "1";
 * json["child"]["b"] = "2";
 * json["array"][0] = 1;
 * json["array"][1] = 2;
 *
 * std::string strJsonText = json.GetJsonText();
 *
 * CJsonUtils json2;
 * json2.Parse(strJsonText);
 *
 * std::string a1 = json2["a"];
 * int a2 = json2["a"];
 * double a3 = json2["a"];
 * int ca1 = json["child"]["a"];
 * int aa1 = json["array"][0];
 */
class CJsonUtils
{
private:
    CJsonUtils(rapidjson::Document* pDoc, rapidjson::Value* pValue);

public:
    CJsonUtils();
    CJsonUtils(const CJsonUtils& other);
    ~CJsonUtils();

    CJsonUtils& operator=(const CJsonUtils& Other);

    /**
     * 解析Json文本
     * @param strJsonText
     * @return
     */
    bool Parse(const char* strJsonText);
    bool Parse(const std::string& strJsonText);

    /**
     * 生成Json本文
     * @return Json文本字符串
     */
    std::string GetJsonText(bool isPretty = false) const;

public:
    /**
     * 判断当前存储的内容的什么类型
     * IsNumber = IsInt32|IsInt64|IsUint32|IsUint64|IsDouble
     *
     * @return
     *      true    是
     *      false   不是
     *
     * 注意:
     *      1.字符串数字,类型为字符串,而不是数字,因此请正确的存储值的类型
     *      2.对于整形而言,若值能正确转换为某种类型,则IsType=true.以下为举例:
     *           1:     IsInt32、IsInt64、IsUint32、IsUint64 = true
     *          -1:     IsInt32、IsInt64   = true;
     *                  IsUint32、IsUint64 = false
     *          50亿:    IsInt64、IsUint64  = true;
     *                  IsInt32、 IsUint32 = false
     */
    bool IsObject() const;
    bool IsString() const;
    bool IsNumber() const;
    bool IsStringNumber() const;
    bool IsInt32() const;
    bool IsInt64() const;
    bool IsUint32() const;
    bool IsUint64() const;
    bool IsDouble() const;
    bool IsBool() const;

    /**
     * 判断是否存在制定的键值对
     * @param[in] strKey 键字符串
     * @return
     */
    bool IsExists(const char* strKey) const;
    bool IsExists(const std::string& strKey) const;


    /**
     * 删除指定键值对
     * @param[in] strKey 键字符串
     * @return
     */
    bool Remove(const char* strKey) const;
    bool Remove(const std::string& strKey) const;

    /**
     * 删除指定数组元素
     * @param[in] iArrayIndex 数组索引号
     * @return
     */
    bool Remove(int32_t iArrayIndex) const;

public:
    /**
     * 键值对操作,得到值对象
     * @param[in] strKey 键字符串
     * @return 值对象
     */
    CJsonUtils operator[](const char* strKey);
    CJsonUtils operator[](const std::string& strKey);
    const CJsonUtils operator[](const char* strKey) const;
    const CJsonUtils operator[](const std::string& strKey) const;

    /**
     * 返回数组中元素的个数
     * @return
     *      >=0 元素个数
     *      <0  不是数组
     */
    int32_t ArrayCount() const;

    /**
     * 得到数组中指定索引的对象
     * @param[in] iArrayIndex 数组索引号
     * @return 值对象
     */
    CJsonUtils operator[](int32_t iArrayIndex);
    const CJsonUtils operator[](int32_t iArrayIndex) const;

public:
    /**
     * 赋值操作,修改对象存储的内容
     * @param[in] 各种Value
     * @return 对象自身的引用
     */
    CJsonUtils& operator=(const char* strValue);
    CJsonUtils& operator=(const std::string& strValue);
    CJsonUtils& operator=(int32_t iValue);
    CJsonUtils& operator=(int64_t i64Value);
    CJsonUtils& operator=(uint32_t uValue);
    CJsonUtils& operator=(uint64_t u64Value);
    CJsonUtils& operator=(double dValue);
    CJsonUtils& operator=(bool bValue);

    /**
     * 隐式转换,取值
     * @return
     *      std::string 若存储的是字符串,则的得到字符串
     *                  若存储的是数值,则得到转换后的字符串
     *                  若存储的是其他对象,则得到Json文本
     *
     *      int32_t、uint32_t、int64_t、uint64_t、double
     *                  若存储的是数值,则返回数值本身
     *                  若存储的是字符串形式的数值,则自动转换为对应的数值
     *                  若存储的是其他类型,则返回0
     *
     * 注意:
     *      取值不会破坏原本的存储类型,例如:原本存储的 "1234" - 字符串1234,若用int来取值,
     *      得到的虽然是整形的1234,但是存储的内容还是字符串1234,不会改变
     */
    operator std::string() const;
    operator int32_t() const;
    operator uint32_t() const;
    operator int64_t() const;
    operator uint64_t() const;
    operator double() const;
    operator bool() const;

private:
    template<typename _TYPE_, typename _CONVERT_FUNC_, typename _DEF_VAL>
    _TYPE_ ConvertToNumber(_CONVERT_FUNC_ pFunc, _DEF_VAL tDefValue) const;

    bool                    m_bRoot;
    rapidjson::Document*    m_pDoc;
    rapidjson::Value*       m_pValue;
} ;

class CJsonUtilsW
{
private:
    CJsonUtilsW(DocumentW* pDoc, ValueW* pValue);

public:
    CJsonUtilsW();
    CJsonUtilsW(const CJsonUtilsW& other);
    ~CJsonUtilsW();

    CJsonUtilsW& operator=(const CJsonUtilsW& Other);

    /**
     * 解析Json文本
     * @param strJsonText
     * @return
     */
    bool Parse(const wchar_t* strJsonText);
    bool Parse(const std::wstring& strJsonText);

    /**
     * 生成Json本文
     * @return Json文本字符串
     */
    std::wstring GetJsonText(bool isPretty = false) const;

public:
    /**
     * 判断当前存储的内容的什么类型
     * IsNumber = IsInt32|IsInt64|IsUint32|IsUint64|IsDouble
     *
     * @return
     *      true    是
     *      false   不是
     *
     * 注意:
     *      1.字符串数字,类型为字符串,而不是数字,因此请正确的存储值的类型
     *      2.对于整形而言,若值能正确转换为某种类型,则IsType=true.以下为举例:
     *           1:     IsInt32、IsInt64、IsUint32、IsUint64 = true
     *          -1:     IsInt32、IsInt64   = true;
     *                  IsUint32、IsUint64 = false
     *          50亿:    IsInt64、IsUint64  = true;
     *                  IsInt32、 IsUint32 = false
     */
    bool IsObject() const;
    bool IsString() const;
    bool IsNumber() const;
    bool IsStringNumber() const;
    bool IsInt32() const;
    bool IsInt64() const;
    bool IsUint32() const;
    bool IsUint64() const;
    bool IsDouble() const;
    bool IsBool() const;

    /**
     * 判断是否存在制定的键值对
     * @param[in] strKey 键字符串
     * @return
     */
    bool IsExists(const wchar_t* strKey) const;
    bool IsExists(const std::wstring& strKey) const;

     /**
     * 删除指定键值对
     * @param[in] strKey 键字符串
     * @return
     */
    bool Remove(const wchar_t* strKey) const;
    bool Remove(const std::wstring& strKey) const;

    /**
     * 删除指定数组元素
     * @param[in] iArrayIndex 数组索引号
     * @return
     */
    bool Remove(int32_t iArrayIndex) const;

public:
    /**
     * 键值对操作,得到值对象
     * @param[in] strKey 键字符串
     * @return 值对象
     */
    CJsonUtilsW operator[](const wchar_t* strKey);
    CJsonUtilsW operator[](const std::wstring& strKey);
    const CJsonUtilsW operator[](const wchar_t* strKey) const;
    const CJsonUtilsW operator[](const std::wstring& strKey) const;

    /**
     * 返回数组中元素的个数
     * @return
     *      >=0 元素个数
     *      <0  不是数组
     */
    int32_t ArrayCount() const;

    /**
     * 得到数组中指定索引的对象
     * @param[in] iArrayIndex 数组索引号
     * @return 值对象
     */
    CJsonUtilsW operator[](int32_t iArrayIndex);
    const CJsonUtilsW operator[](int32_t iArrayIndex) const;

public:
    /**
     * 赋值操作,修改对象存储的内容
     * @param[in] 各种Value
     * @return 对象自身的引用
     */
    CJsonUtilsW& operator=(const wchar_t* strValue);
    CJsonUtilsW& operator=(const std::wstring& strValue);
    CJsonUtilsW& operator=(int32_t iValue);
    CJsonUtilsW& operator=(int64_t i64Value);
    CJsonUtilsW& operator=(uint32_t uValue);
    CJsonUtilsW& operator=(uint64_t u64Value);
    CJsonUtilsW& operator=(double dValue);
    CJsonUtilsW& operator=(bool bValue);

    /**
     * 隐式转换,取值
     * @return
     *      std::string 若存储的是字符串,则的得到字符串
     *                  若存储的是数值,则得到转换后的字符串
     *                  若存储的是其他对象,则得到Json文本
     *
     *      int32_t、uint32_t、int64_t、uint64_t、double
     *                  若存储的是数值,则返回数值本身
     *                  若存储的是字符串形式的数值,则自动转换为对应的数值
     *                  若存储的是其他类型,则返回0
     *
     * 注意:
     *      取值不会破坏原本的存储类型,例如:原本存储的 "1234" - 字符串1234,若用int来取值,
     *      得到的虽然是整形的1234,但是存储的内容还是字符串1234,不会改变
     */
    operator std::wstring() const;
    operator int32_t() const;
    operator uint32_t() const;
    operator int64_t() const;
    operator uint64_t() const;
    operator double() const;
    operator bool() const;

private:
    template<typename _TYPE_, typename _CONVERT_FUNC_, typename _DEF_VAL>
    _TYPE_ ConvertToNumber(_CONVERT_FUNC_ pFunc, _DEF_VAL tDefValue) const;

    bool                    m_bRoot;
    DocumentW*              m_pDoc;
    ValueW*                 m_pValue;
};


#endif //JSON_UTILS_H

CPP

在unicode环境下主要使用CJsonUtilsW

jsonutils.cpp文件

C++
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
#include <cstdio>
#include <string>
#include <ctype.h>
#include "jsonutils.h"


using namespace std;

//静态空值对象,用于构造空值的const CJobject对象
static Value gNullValue(kNullType);
static ValueW gNullValueW(kNullType);

/****************************************************
 * CJson的对象类
 ***************************************************/
CJsonUtils::CJsonUtils() : m_bRoot(true), m_pDoc(new Document()), m_pValue(new Value(kObjectType))
{

}

CJsonUtils::CJsonUtils(Document* pDoc, Value* pValue) : m_bRoot(false), m_pDoc(pDoc), m_pValue(pValue)
{
}

CJsonUtils::CJsonUtils(const CJsonUtils& other) : m_bRoot(false), m_pDoc(other.m_pDoc), m_pValue(other.m_pValue)
{
}

CJsonUtils::~CJsonUtils()
{
    if (true == m_bRoot)
    {
        delete m_pDoc;
        delete m_pValue;
    }
}

CJsonUtils& CJsonUtils::operator=(const CJsonUtils& Other)
{
    m_pValue->CopyFrom(*Other.m_pValue, m_pDoc->GetAllocator());
    return *this;
}

bool CJsonUtils::Parse(const char* strJsonText)
{
    if (false == m_bRoot)
        return false;

    m_pDoc->Parse(strJsonText);
    if (kParseErrorNone != m_pDoc->GetParseError())
        return false;

    *m_pValue = m_pDoc->Move();
    return true;
}

bool CJsonUtils::Parse(const string& strJsonText)
{
    return Parse(strJsonText.c_str());
}

string CJsonUtils::GetJsonText(bool isPretty) const
{
    StringBuffer stBuffer;
    if (isPretty)
    {
        PrettyWriter<StringBuffer> stWriter(stBuffer);
        m_pValue->Accept(stWriter);
    }
    else
    {
        Writer<StringBuffer> stWriter(stBuffer);
        m_pValue->Accept(stWriter);
    }


    return string(stBuffer.GetString(), stBuffer.GetSize());
}

bool CJsonUtils::IsObject() const
{
    switch (m_pValue->GetType())
    {
        case kStringType:
        case kNumberType:
        case kTrueType:
        case kFalseType:
            return false;

        default:
            return true;
    }
}

bool CJsonUtils::IsString() const
{
    return m_pValue->IsString();
}

bool CJsonUtils::IsNumber() const
{
    return m_pValue->IsNumber();
}

bool CJsonUtils::IsStringNumber() const
{
    if (false == IsString())
        return false;

    const char* cch = m_pValue->GetString();
    if ('-' == *cch)
        ++cch;

    int iDotCount = 0;
    for (; *cch != 0; ++cch)
    {
        if (0 == isdigit(*cch))
        {
            if ('.' != *cch)
                return false;

            ++iDotCount;
            if (1 < iDotCount)
                return false;
        }
    }

    return true;
}

bool CJsonUtils::IsInt32() const
{
    return m_pValue->IsInt();
}

bool CJsonUtils::IsInt64() const
{
    return m_pValue->IsInt64();
}

bool CJsonUtils::IsUint32() const
{
    return m_pValue->IsUint();
}

bool CJsonUtils::IsUint64() const
{
    return m_pValue->IsUint64();
}

bool CJsonUtils::IsDouble() const
{
    return m_pValue->IsDouble();
}

bool CJsonUtils::IsBool() const
{
    switch (m_pValue->GetType())
    {
    case kTrueType:
    case kFalseType:
        return true;
    }

    return m_pValue->IsBool();
}

bool CJsonUtils::IsExists(const char* strKey) const
{
    return m_pValue->HasMember(strKey);
}

bool CJsonUtils::IsExists(const std::string& strKey) const
{
    return IsExists(strKey.c_str());
}

bool CJsonUtils::Remove(const char* strKey) const
{
    if (m_pValue->HasMember(strKey))
    {
        return m_pValue->RemoveMember(strKey);
    }

    return false;
}

bool CJsonUtils::Remove(const std::string& strKey) const
{
    return Remove(strKey.c_str());
}

bool CJsonUtils::Remove(int32_t iArrayIndex) const
{
    if (false == m_pValue->IsArray())
        return false;

    if (m_pValue->Size() < iArrayIndex)
        return false;

    int index = 0;
    for (rapidjson::Value::ValueIterator iter = m_pValue->Begin(); iter != m_pValue->End();)
    {
        if (index == iArrayIndex)
        {
            m_pValue->Erase(iter);
            break;
        }
        ++index;
        ++iter;
    }

    return true;
}

CJsonUtils CJsonUtils::operator[](const char* strKey)
{
    Value::MemberIterator iter = m_pValue->FindMember(strKey);
    if (m_pValue->MemberEnd() == iter)
    {
        Value tKey(strKey, m_pDoc->GetAllocator());
        Value tValue(kObjectType);
        m_pValue->AddMember(tKey, tValue, m_pDoc->GetAllocator());

        iter = m_pValue->FindMember(strKey);
    }

    return CJsonUtils(m_pDoc, &iter->value);
}

CJsonUtils CJsonUtils::operator[](const string& strKey)
{
    Value::MemberIterator iter = m_pValue->FindMember(strKey.c_str());
    if (m_pValue->MemberEnd() == iter)
    {
        Value tKey(strKey.c_str(), strKey.length(), m_pDoc->GetAllocator());
        Value tValue(kObjectType);
        m_pValue->AddMember(tKey, tValue, m_pDoc->GetAllocator());

        iter = m_pValue->FindMember(strKey.c_str());
    }

    return CJsonUtils(m_pDoc, &iter->value);
}

const CJsonUtils CJsonUtils::operator[](const char* strKey) const
{
    Value::MemberIterator iter = m_pValue->FindMember(strKey);
    if (m_pValue->MemberEnd() == iter)
    {
        return CJsonUtils(m_pDoc, &gNullValue);
    }

    return CJsonUtils(m_pDoc, &iter->value);
}

const CJsonUtils CJsonUtils::operator[](const std::string& strKey) const
{
    return operator[](strKey.c_str());
}

int32_t CJsonUtils::ArrayCount() const
{
    if (false == m_pValue->IsArray())
        return -1;

    return m_pValue->Size();
}

CJsonUtils CJsonUtils::operator[](int32_t iArrayIndex)
{
    if (false == m_pValue->IsArray())
        m_pValue->SetArray();

    int32_t iSize = m_pValue->Size();
    for (int32_t i = iSize; i < iArrayIndex + 1; ++i)
    {
        Value tValue(kObjectType);
        m_pValue->PushBack(tValue, m_pDoc->GetAllocator());
    }

    Value& tValue = (*m_pValue)[iArrayIndex];
    return CJsonUtils(m_pDoc, &tValue);
}

const CJsonUtils CJsonUtils::operator[](int32_t iArrayIndex) const
{
    if (false == m_pValue->IsArray())
        return CJsonUtils(m_pDoc, &gNullValue);

    if ((SizeType)iArrayIndex >= m_pValue->Size())
        return CJsonUtils(m_pDoc, &gNullValue);

    Value& tValue = (*m_pValue)[iArrayIndex];
    return CJsonUtils(m_pDoc, &tValue);
}

CJsonUtils& CJsonUtils::operator=(const char* strValue)
{
    m_pValue->SetString(strValue, m_pDoc->GetAllocator());
    return *this;
}

CJsonUtils& CJsonUtils::operator=(const std::string& strValue)
{
    m_pValue->SetString(strValue.c_str(), strValue.length(), m_pDoc->GetAllocator());
    return *this;
}

CJsonUtils& CJsonUtils::operator=(int32_t iValue)
{
    m_pValue->SetInt(iValue);
    return *this;
}

CJsonUtils& CJsonUtils::operator=(int64_t i64Value)
{
    m_pValue->SetInt64(i64Value);
    return *this;
}

CJsonUtils& CJsonUtils::operator=(uint32_t uValue)
{
    m_pValue->SetUint(uValue);
    return *this;
}

CJsonUtils& CJsonUtils::operator=(uint64_t u64Value)
{
    m_pValue->SetUint64(u64Value);
    return *this;
}

CJsonUtils& CJsonUtils::operator=(double dValue)
{
    m_pValue->SetDouble(dValue);
    return *this;
}

CJsonUtils& CJsonUtils::operator=(bool bValue)
{
    m_pValue->SetBool(bValue);
    return *this;
}

CJsonUtils::operator string() const
{
    if (true == m_pValue->IsString())
    {
        return string(m_pValue->GetString(), m_pValue->GetStringLength());
    }
    else if (m_pValue->IsInt())
    {
        char szBuf[64] = {0};
        snprintf(szBuf, sizeof(szBuf), "%d", m_pValue->GetInt());
        return szBuf;
    }
    else if (m_pValue->IsInt64())
    {
        char szBuf[64] = {0};
        snprintf(szBuf, sizeof(szBuf), "%jd", m_pValue->GetInt64());
        return szBuf;
    }
    else if (m_pValue->IsUint())
    {
        char szBuf[64] = {0};
        snprintf(szBuf, sizeof(szBuf), "%u", m_pValue->GetUint());
        return szBuf;
    }
    else if (true == m_pValue->IsUint64())
    {
        char szBuf[64] = {0};
        snprintf(szBuf, sizeof(szBuf), "%ju", m_pValue->GetUint64());
        return szBuf;
    }
    else if (true == m_pValue->IsDouble())
    {
        char szBuf[64] = {0};
        snprintf(szBuf, sizeof(szBuf), "%g", m_pValue->GetDouble());
        return szBuf;
    }
    else
    {
        return GetJsonText();
    }
}

CJsonUtils::operator int32_t() const
{
    return ConvertToNumber<int32_t>(atoi, 0);
}

CJsonUtils::operator uint32_t() const
{
    return ConvertToNumber<uint32_t>(atoi, 0);
}

CJsonUtils::operator int64_t() const
{
    return ConvertToNumber<int64_t>(atoll, 0L);
}

CJsonUtils::operator uint64_t() const
{
    return ConvertToNumber<uint64_t>(atoll, 0L);
}

CJsonUtils::operator double() const
{
    return ConvertToNumber<double>(atof, 0.0);
}

CJsonUtils::operator bool() const
{
    return ConvertToNumber<bool>(atoi, 0);
}

template<typename _TYPE_, typename _CONVERT_FUNC_, typename _DEF_VAL>
_TYPE_ CJsonUtils::ConvertToNumber(_CONVERT_FUNC_ pFunc, _DEF_VAL tDefValue) const
{
    if (true == m_pValue->IsString())
    {
        return pFunc(m_pValue->GetString());
    }
    else if (true == m_pValue->IsInt())
    {
        return m_pValue->GetInt();
    }
    else if (true == m_pValue->IsInt64())
    {
        return m_pValue->GetInt64();
    }
    else if (true == m_pValue->IsUint())
    {
        return m_pValue->GetUint();
    }
    else if (true == m_pValue->IsUint64())
    {
        return m_pValue->GetUint64();
    }
    else if (true == m_pValue->IsDouble())
    {
        return m_pValue->GetDouble();
    }
    else if (true == m_pValue->IsBool())
    {
        return m_pValue->GetBool();
    }
    else
    {
        return tDefValue;
    }
}


CJsonUtilsW::CJsonUtilsW() : m_bRoot(true), m_pDoc(new DocumentW()), m_pValue(new ValueW(kObjectType))
{

}

CJsonUtilsW::CJsonUtilsW(DocumentW* pDoc, ValueW* pValue) : m_bRoot(false), m_pDoc(pDoc), m_pValue(pValue)
{
}

CJsonUtilsW::CJsonUtilsW(const CJsonUtilsW& other) : m_bRoot(false), m_pDoc(other.m_pDoc), m_pValue(other.m_pValue)
{
}

CJsonUtilsW::~CJsonUtilsW()
{
    if (true == m_bRoot)
    {
        delete m_pDoc;
        delete m_pValue;
    }
}

CJsonUtilsW& CJsonUtilsW::operator=(const CJsonUtilsW& Other)
{
    m_pValue->CopyFrom(*Other.m_pValue, m_pDoc->GetAllocator());
    return *this;
}

bool CJsonUtilsW::Parse(const wchar_t* strJsonText)
{
    if (false == m_bRoot)
        return false;

    m_pDoc->Parse(strJsonText);
    if (kParseErrorNone != m_pDoc->GetParseError())
        return false;

    *m_pValue = m_pDoc->Move();
    return true;
}

bool CJsonUtilsW::Parse(const wstring& strJsonText)
{
    return Parse(strJsonText.c_str());
}

wstring CJsonUtilsW::GetJsonText(bool isPretty) const
{
    StringBufferW stBuffer;
    if (isPretty)
    {
        PrettyWriter<StringBufferW, UTF16<>, UTF16<> > stWriter(stBuffer);
        m_pValue->Accept(stWriter);
    }
    else
    {
        Writer<StringBufferW, UTF16<>, UTF16<> > stWriter(stBuffer);
        m_pValue->Accept(stWriter);
    }


    return wstring(stBuffer.GetString(), stBuffer.GetSize());
}

bool CJsonUtilsW::IsObject() const
{
    switch (m_pValue->GetType())
    {
    case kStringType:
    case kNumberType:
    case kTrueType:
    case kFalseType:
        return false;

    default:
        return true;
    }
}

bool CJsonUtilsW::IsString() const
{
    return m_pValue->IsString();
}

bool CJsonUtilsW::IsNumber() const
{
    return m_pValue->IsNumber();
}

bool CJsonUtilsW::IsStringNumber() const
{
    if (false == IsString())
        return false;

    const wchar_t* cch = m_pValue->GetString();
    if (L'-' == *cch)
        ++cch;

    int iDotCount = 0;
    for (; *cch != 0; ++cch)
    {
        if (0 == isdigit(*cch))
        {
            if ('.' != *cch)
                return false;

            ++iDotCount;
            if (1 < iDotCount)
                return false;
        }
    }

    return true;
}

bool CJsonUtilsW::IsInt32() const
{
    return m_pValue->IsInt();
}

bool CJsonUtilsW::IsInt64() const
{
    return m_pValue->IsInt64();
}

bool CJsonUtilsW::IsUint32() const
{
    return m_pValue->IsUint();
}

bool CJsonUtilsW::IsUint64() const
{
    return m_pValue->IsUint64();
}

bool CJsonUtilsW::IsDouble() const
{
    return m_pValue->IsDouble();
}

bool CJsonUtilsW::IsBool() const
{
    switch (m_pValue->GetType())
    {
    case kTrueType:
    case kFalseType:
        return true;
    }

    return m_pValue->IsBool();
}

bool CJsonUtilsW::IsExists(const wchar_t* strKey) const
{
    return m_pValue->HasMember(strKey);
}

bool CJsonUtilsW::IsExists(const std::wstring& strKey) const
{
    return IsExists(strKey.c_str());
}

bool CJsonUtilsW::Remove(const wchar_t* strKey) const
{
    if (m_pValue->HasMember(strKey))
    {
        return m_pValue->RemoveMember(strKey);
    }

    return false;
}

bool CJsonUtilsW::Remove(const std::wstring& strKey) const
{
    return Remove(strKey.c_str());
}

bool CJsonUtilsW::Remove(int32_t iArrayIndex) const
{
    if (false == m_pValue->IsArray())
        return false;

    if (m_pValue->Size() < iArrayIndex)
        return false;

    int index = 0;
    for (ValueW::ValueIterator iter = m_pValue->Begin(); iter != m_pValue->End();)
    {
        if (index == iArrayIndex)
        {
            m_pValue->Erase(iter);
            break;
        }
        ++index;
        ++iter;
    }

    return true;
}

CJsonUtilsW CJsonUtilsW::operator[](const wchar_t* strKey)
{
    ValueW::MemberIterator iter = m_pValue->FindMember(strKey);
    if (m_pValue->MemberEnd() == iter)
    {
        ValueW tKey(strKey, m_pDoc->GetAllocator());
        ValueW tValue(kObjectType);
        m_pValue->AddMember(tKey, tValue, m_pDoc->GetAllocator());

        iter = m_pValue->FindMember(strKey);
    }

    return CJsonUtilsW(m_pDoc, &iter->value);
}

CJsonUtilsW CJsonUtilsW::operator[](const wstring& strKey)
{
    ValueW::MemberIterator iter = m_pValue->FindMember(strKey.c_str());
    if (m_pValue->MemberEnd() == iter)
    {
        ValueW tKey(strKey.c_str(), strKey.length(), m_pDoc->GetAllocator());
        ValueW tValue(kObjectType);
        m_pValue->AddMember(tKey, tValue, m_pDoc->GetAllocator());

        iter = m_pValue->FindMember(strKey.c_str());
    }

    return CJsonUtilsW(m_pDoc, &iter->value);
}

const CJsonUtilsW CJsonUtilsW::operator[](const wchar_t* strKey) const
{
    ValueW::MemberIterator iter = m_pValue->FindMember(strKey);
    if (m_pValue->MemberEnd() == iter)
    {
        return CJsonUtilsW(m_pDoc, &gNullValueW);
    }

    return CJsonUtilsW(m_pDoc, &iter->value);
}

const CJsonUtilsW CJsonUtilsW::operator[](const std::wstring& strKey) const
{
    return operator[](strKey.c_str());
}

int32_t CJsonUtilsW::ArrayCount() const
{
    if (false == m_pValue->IsArray())
        return -1;

    return m_pValue->Size();
}

CJsonUtilsW CJsonUtilsW::operator[](int32_t iArrayIndex)
{
    if (false == m_pValue->IsArray())
        m_pValue->SetArray();

    int32_t iSize = m_pValue->Size();
    for (int32_t i = iSize; i < iArrayIndex + 1; ++i)
    {
        ValueW tValue(kObjectType);
        m_pValue->PushBack(tValue, m_pDoc->GetAllocator());
    }

    ValueW& tValue = (*m_pValue)[iArrayIndex];
    return CJsonUtilsW(m_pDoc, &tValue);
}

const CJsonUtilsW CJsonUtilsW::operator[](int32_t iArrayIndex) const
{
    if (false == m_pValue->IsArray())
        return CJsonUtilsW(m_pDoc, &gNullValueW);

    if ((SizeType)iArrayIndex >= m_pValue->Size())
        return CJsonUtilsW(m_pDoc, &gNullValueW);

    ValueW& tValue = (*m_pValue)[iArrayIndex];
    return CJsonUtilsW(m_pDoc, &tValue);
}

CJsonUtilsW& CJsonUtilsW::operator=(const wchar_t* strValue)
{
    m_pValue->SetString(strValue, m_pDoc->GetAllocator());
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(const std::wstring& strValue)
{
    m_pValue->SetString(strValue.c_str(), strValue.length(), m_pDoc->GetAllocator());
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(int32_t iValue)
{
    m_pValue->SetInt(iValue);
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(int64_t i64Value)
{
    m_pValue->SetInt64(i64Value);
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(uint32_t uValue)
{
    m_pValue->SetUint(uValue);
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(uint64_t u64Value)
{
    m_pValue->SetUint64(u64Value);
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(double dValue)
{
    m_pValue->SetDouble(dValue);
    return *this;
}

CJsonUtilsW& CJsonUtilsW::operator=(bool bValue)
{
    m_pValue->SetBool(bValue);
    return *this;
}

CJsonUtilsW::operator wstring() const
{
    if (true == m_pValue->IsString())
    {
        return wstring(m_pValue->GetString(), m_pValue->GetStringLength());
    }
    else if (m_pValue->IsInt())
    {
        wchar_t szBuf[64] = { 0 };
        _snwprintf(szBuf, sizeof(szBuf), L"%d", m_pValue->GetInt());
        return szBuf;
    }
    else if (m_pValue->IsInt64())
    {
        wchar_t szBuf[64] = { 0 };
        _snwprintf(szBuf, sizeof(szBuf), L"%jd", m_pValue->GetInt64());
        return szBuf;
    }
    else if (m_pValue->IsUint())
    {
        wchar_t szBuf[64] = { 0 };
        _snwprintf(szBuf, sizeof(szBuf), L"%u", m_pValue->GetUint());
        return szBuf;
    }
    else if (true == m_pValue->IsUint64())
    {
        wchar_t szBuf[64] = { 0 };
        _snwprintf(szBuf, sizeof(szBuf), L"%ju", m_pValue->GetUint64());
        return szBuf;
    }
    else if (true == m_pValue->IsDouble())
    {
        wchar_t szBuf[64] = { 0 };
        _snwprintf(szBuf, sizeof(szBuf), L"%g", m_pValue->GetDouble());
        return szBuf;
    }
    else
    {
        return GetJsonText();
    }
}

CJsonUtilsW::operator int32_t() const
{
    return ConvertToNumber<int32_t>(_wtoi, 0);
}

CJsonUtilsW::operator uint32_t() const
{
    return ConvertToNumber<uint32_t>(_wtoi, 0);
}

CJsonUtilsW::operator int64_t() const
{
    return ConvertToNumber<int64_t>(_wtoll, 0L);
}

CJsonUtilsW::operator uint64_t() const
{
    return ConvertToNumber<uint64_t>(_wtoll, 0L);
}

CJsonUtilsW::operator double() const
{
    return ConvertToNumber<double>(_wtof, 0.0);
}

CJsonUtilsW::operator bool() const
{
    return ConvertToNumber<bool>(_wtoi, 0);
}

template<typename _TYPE_, typename _CONVERT_FUNC_, typename _DEF_VAL>
_TYPE_ CJsonUtilsW::ConvertToNumber(_CONVERT_FUNC_ pFunc, _DEF_VAL tDefValue) const
{
    if (true == m_pValue->IsString())
    {
        return pFunc(m_pValue->GetString());
    }
    else if (true == m_pValue->IsInt())
    {
        return m_pValue->GetInt();
    }
    else if (true == m_pValue->IsInt64())
    {
        return m_pValue->GetInt64();
    }
    else if (true == m_pValue->IsUint())
    {
        return m_pValue->GetUint();
    }
    else if (true == m_pValue->IsUint64())
    {
        return m_pValue->GetUint64();
    }
    else if (true == m_pValue->IsDouble())
    {
        return m_pValue->GetDouble();
    }
    else if (true == m_pValue->IsBool())
    {
        return m_pValue->GetBool();
    }
    else
    {
        return tDefValue;
    }
}

rapidjson的基本操作

增加数据

C++
static void MyGroupRapidjsonAdd() {

        CString strFileName = CUtility::GetAppPath() + _T("config.json");
        CString strContent;
        string str;
        str = readfile(string(CW2A(strFileName)).c_str());
        strContent = str.c_str();
        CJsonUtilsW json;
        json.Parse(strContent);

        CJsonUtilsW cJsonUtils1;
        cJsonUtils1[_T("b")] = _T("123");
        cJsonUtils1[_T("c")] = _T("1234");
        json[_T("test")] = cJsonUtils1;
        CString strJsonText4 = json.GetJsonText(true).c_str();
        acutPrintf(_T("\n输出json文件内容:%s"), strJsonText4);
    }

读取数据

C++
    static void MyGroupRapidjsonRead() {

        CString strFileName = CUtility::GetAppPath() + _T("config.json");
        CString strContent;
        string str;
        str = readfile(string(CW2A(strFileName)).c_str());
        strContent = str.c_str();
        CJsonUtilsW json;
        json.Parse(strContent);
        CString strJsonText4 = json.GetJsonText(true).c_str();
        acutPrintf(_T("\n输出json文件内容:%s"), strJsonText4);
    }

编辑数据

C++
static void MyGroupRapidjsonEdit() {

        CString strFileName = CUtility::GetAppPath() + _T("config.json");
        CString strContent;
        string str;
        str = readfile(string(CW2A(strFileName)).c_str());
        strContent = str.c_str();
        CJsonUtilsW json;
        json.Parse(strContent);

        CJsonUtilsW cJsonUtils1;
        cJsonUtils1[_T("b")] = _T("123");
        cJsonUtils1[_T("c")] = _T("1234");
        json[_T("array")][0][_T("b")] = _T("hero");
        json[_T("array")][1][_T("d")] = cJsonUtils1;
        CString strJsonText4 = json.GetJsonText(true).c_str();


        CStdioFile File;
        if (!File.Open(strFileName, CFile::modeReadWrite | CFile::typeText | CFile::modeCreate))
        {
            return;
        }
        File.WriteString(strJsonText4);
        File.Close();
        acutPrintf(_T("\n输出json文件内容:%s"), strJsonText4);
    }

DWG转svg

安装软件

ezdxf不支持处理dwg文件,那么就需要使用oda_file_converter

安装python插件

Python
pip install pydantic ezdxf

代码

将dwg转成svg

Python
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, svg
from ezdxf.addons import odafc
# 通过修改win_exec_path的值为自定义安装路径
odafc.win_exec_path = r'C:\\Program Files\\ODA\\ODAFileConverter 25.5.0\\ODAFileConverter.exe'

def convert_dwg_to_svg(dxf_path, svg_path):
    doc = odafc.readfile(dxf_path)
    msp = doc.modelspace()
    # 1. create the render context
    context = RenderContext(doc)
    # 2. create the backend
    backend = svg.SVGBackend()
    # 3. create the frontend
    frontend = Frontend(context, backend)
    # 4. draw the modelspace
    frontend.draw_layout(msp)
    # 5. create an A4 page layout, not required for all backends
    page = layout.Page(64, 64, layout.Units.mm, margins=layout.Margins.all(20))
    # 6. get the SVG rendering as string - this step is backend dependent
    svg_string = backend.get_string(page)
    with open(svg_path, "wt", encoding="utf8") as fp:
        fp.write(svg_string)

if __name__ == '__main__':
    filePath = 'D:\\Test\\'
    dwg_path = filePath + '5000报废矩形立井.dwg'
    svg_path = filePath + '5000报废矩形立井11.svg'
    convert_dwg_to_svg(dwg_path, svg_path)

完整代码如下所示:

Python
from ezdxf.addons.drawing import Frontend, RenderContext, pymupdf, layout, svg, config
from ezdxf.addons import odafc
import configparser
import sys
import os
from PIL import Image

# 通过修改win_exec_path的值为自定义安装路径
odafc.win_exec_path = (
    r"C:\\Program Files\\ODA\\ODAFileConverter 25.5.0\\ODAFileConverter.exe"
)

# 自定义config解析
class myconf(configparser.ConfigParser):
    def __init__(self, defaults=None):
        """
        初始化ConfigParser类的实例。
        通过调用父类configparser.ConfigParser的构造方法,初始化配置解析器实例。
        该构造方法允许指定默认配置值,这些值将在读取配置文件之前提供基本的配置项。
        参数:
        - defaults: 可选参数,字典类型,提供基本的配置项和值。如果未提供,将使用父类的默认设置。
        """
        configparser.ConfigParser.__init__(self, defaults=None)

    def optionxform(self, optionstr):
        return optionstr

    def write(self, fp):
        """
        将配置数据写入指定的文件指针。
        参数:
        - fp: 文件指针,用于写入配置数据。
        该方法首先检查是否有默认配置,默认配置是 configparser 模块的特殊部分。
        如果有默认配置,它将写入一个包含默认值的部分。
        然后,它遍历所有部分,为每个部分写入对应的键值对。
        """
        # 检查是否有默认配置,如果有,则写入默认配置部分
        if self._defaults:
            fp.write("[%s]\n" % configparser.DEFAULTSECT)
        # 遍历默认配置,写入每个键值对
        for key, value in self._defaults.items():
            if key.strip():
                fp.write("%s=%s\n" % (key, str(value).replace("\n", "\n\t")))
                # fp.write("\n")
        # 遍历所有部分,写入每个部分及其键值对
        for section in self._sections:
            fp.write("[%s]\n" % section)
            for key, value in self._sections[section].items():
                if key == "__name__":
                    continue
                # 添加一行key为空的代码
                if (value is not None) or (self._optcre == self.OPTCRE):
                    if key.strip():
                        key = "=".join((key, str(value).replace("\n", "\n\t")))
                        fp.write("%s\n" % (key))
            fp.write("\n")


# 获取同一目录下的所有dwg文件的绝对路径
def getFileName(filedir):
    """
    获取指定目录下所有以"dwg"为后缀的文件的绝对路径列表。
    参数:
    filedir: str - 文件目录的路径。
    返回:
    List[str] - 包含所有符合条件的文件的绝对路径的列表,如果没有找到任何文件,则返回空列表。
    """
    # 使用列表推导式和os.walk遍历指定目录及其子目录,查找所有以"dwg"结尾的文件
    # os.path.join用于拼接文件的绝对路径
    file_list = [
        os.path.join(root, filespath)
        for root, dirs, files in os.walk(filedir)
        for filespath in files
        if str(filespath).endswith("dwg")
    ]
    # 如果file_list不为空,则返回file_list,否则返回空列表
    return file_list if file_list else []


# 获取当前脚本目录
def get_current_file_path():
    # 通过命令行参数获取当前脚本的绝对路径
    abs_file = sys.argv[0]
    # 将路径中的斜杠替换为反斜杠,以适应Windows系统
    windows_path = abs_file.replace("/", "\\")
    # 去除路径中的脚本文件名,仅保留目录部分
    windows_path = windows_path[: windows_path.rfind("\\")]
    # 返回脚本所在的目录路径
    return windows_path


# 用于将DXF格式的文件转换为指定格式的图像文件
def convert_dxf_to_image(
    dxf_path, output_file_name, width=64, height=64, backgroundtype=0, file_suffix="pdf"
):
    try:
        doc = odafc.readfile(dxf_path)
    except odafc.DXFStructureError as e:
        print(f"DXF Structure Error in file {dxf_path}: {e}")
        return
    except FileNotFoundError:
        print(f"File not found: {dxf_path}")
        return
    except PermissionError:
        print(f"Permission denied for file: {dxf_path}")
        return
    except Exception as e:
        print(f"Error reading file {dxf_path}: {e}")
        return
    msp = doc.modelspace()
    # 创建渲染上下文
    context = RenderContext(doc)
    # 创建后端
    backend = pymupdf.PyMuPdfBackend()
    # 创建前端
    # 定义一个字典来映射 backgroundtype 到对应的 BackgroundPolicy
    policy_map = {
        0: config.BackgroundPolicy.DEFAULT,
        1: config.BackgroundPolicy.BLACK,
        2: config.BackgroundPolicy.WHITE,
        3: config.BackgroundPolicy.CUSTOM,
        4: config.BackgroundPolicy.PAPERSPACE,
        5: config.BackgroundPolicy.MODELSPACE,
        6: config.BackgroundPolicy.OFF,
    }
    # 使用 try-except 来处理可能出现的 KeyError 异常
    try:
        background_policy = policy_map[backgroundtype]
    except KeyError:
        # 如果 backgroundtype 不在预定义的映射中,则使用默认策略
        background_policy = config.BackgroundPolicy.DEFAULT
        print("Warning: Invalid backgroundtype. Using default policy.")

    # 创建 Configuration 对象
    cfg = config.Configuration(background_policy=background_policy)
    # 初始化 Frontend 实例
    frontend = Frontend(context, backend, config=cfg)
    # 绘制模型空间
    frontend.draw_layout(msp)
    # 创建A4页面布局
    page = layout.Page(width, height, layout.Units.mm, margins=layout.Margins.all(20))
    # 获取PDF或PNG渲染结果作为字节流
    if file_suffix == "pdf":
        pdf_bytes = backend.get_pdf_bytes(page)
        try:
            with open(output_file_name, "wb") as fp:
                fp.write(pdf_bytes)
        except Exception as e:
            print(f"Error writing to file {output_file_name}: {e}")
            return
    else:
        png_bytes = backend.get_pixmap_bytes(page, fmt="png", dpi=96)
        try:
            with open(output_file_name, "wb") as fp:
                fp.write(png_bytes)
        except Exception as e:
            print(f"Error writing to file {output_file_name}: {e}")
            return

        if file_suffix == "bmp":
            img = Image.open(output_file_name)
            img = img.convert("RGB")
            bmp_out_file_name = output_file_name.replace(".png", ".bmp")
            img.save(bmp_out_file_name, "BMP")
            output_file_name = bmp_out_file_name

    print(output_file_name + "文件已经转换")


# 用于将DXF格式的文件转换为SVG格式的文件
def convert_dwg_to_svg(dxf_path, svg_path, width=64, height=64):
    try:
        doc = odafc.readfile(dxf_path)
    except odafc.DXFStructureError as e:
        print(f"DXF Structure Error in file {dxf_path}: {e}")
        return
    except FileNotFoundError:
        print(f"File not found: {dxf_path}")
        return
    except PermissionError:
        print(f"Permission denied for file: {dxf_path}")
        return
    except Exception as e:
        print(f"Error reading file {dxf_path}: {e}")
        return
    msp = doc.modelspace()
    # 1. create the render context
    context = RenderContext(doc)
    # 2. create the backend
    backend = svg.SVGBackend()
    # 3. create the frontend
    # 定义一个字典来映射 backgroundtype 到对应的 BackgroundPolicy
    policy_map = {
        0: config.BackgroundPolicy.DEFAULT,
        1: config.BackgroundPolicy.BLACK,
        2: config.BackgroundPolicy.WHITE,
        3: config.BackgroundPolicy.CUSTOM,
        4: config.BackgroundPolicy.PAPERSPACE,
        5: config.BackgroundPolicy.MODELSPACE,
        6: config.BackgroundPolicy.OFF,
    }

    # 使用 try-except 来处理可能出现的 KeyError 异常
    try:
        background_policy = policy_map[backgroundtype]
    except KeyError:
        # 如果 backgroundtype 不在预定义的映射中,则使用默认策略
        background_policy = config.BackgroundPolicy.DEFAULT
        print("Warning: Invalid backgroundtype. Using default policy.")

    # 创建 Configuration 对象
    cfg = config.Configuration(background_policy=background_policy)

    # 初始化 Frontend 实例
    frontend = Frontend(context, backend, config=cfg)
    # 4. draw the modelspace
    frontend.draw_layout(msp)
    # 5. create an A4 page layout, not required for all backends
    page = layout.Page(width, height, layout.Units.mm, margins=layout.Margins.all(20))
    # 6. get the SVG rendering as string - this step is backend dependent
    svg_string = backend.get_string(page)
    with open(svg_path, "wt", encoding="utf8") as fp:
        fp.write(svg_string)
    print(svg_path + "文件已经转换")


def is_float_zero(num, epsilon=1e-6):
    """
    判断一个浮点数是否接近零。
    由于浮点数的精度问题,直接比较数值与零相等通常是不推荐的。通过指定一个极小的误差范围(epsilon),
    判断数值是否在这个误差范围内,从而确定该数值是否接近零。
    参数:
    num: 待判断的浮点数。
    epsilon: 可接受的误差范围,默认值为1e-6。
    返回值:
    如果 num 的绝对值小于 epsilon,返回 True,表示 num 接近零。
    否则,返回 False,表示 num 不接近零。
    """
    return -epsilon < num < epsilon


def read_config_file(inifile):
    """
    读取配置文件并解析其中的设置。
    该函数尝试读取一个INI格式的配置文件,并从中获取特定的设置值,
    包括输入路径、宽度、高度和文件后缀。如果无法读取或解析配置文件,
    它将返回一组默认的空值。
    参数:
    inifile (str): 配置文件的路径。
    返回:
    tuple: 包含输入路径(str)、宽度(float)、高度(float)和文件后缀(str)的元组。
           如果发生错误,返回("", 0.0, 0.0, "")。
    """
    try:
        # 尝试读取配置文件
        iniconfig.read(inifile, encoding="utf-8")
        # 从配置文件的"settings"部分获取各个配置项的值
        inputpath = iniconfig.get("settings", "path")
        width = iniconfig.getfloat("settings", "width")
        height = iniconfig.getfloat("settings", "height")
        file_suffix = iniconfig.get("settings", "file_suffix")
        backgroundtype = iniconfig.getint("settings", "backgroundtype")
        # 返回解析的配置项值
        return inputpath, width, height, file_suffix, backgroundtype
    except Exception as e:
        # 如果发生异常,打印错误信息并返回一组默认的空值
        print(f"读取配置文件时发生错误: {e}")
        return "", 0.0, 0.0, "", 0


def process_files(width, height, file_suffix, backgroundtype, filelist):
    """
    根据提供的文件列表和参数,将指定的文件转换为指定格式的PDF或图片文件。
    参数:
    - width: 转换后文件的宽度,用于调整输出文件的尺寸。
    - height: 转换后文件的高度,用于调整输出文件的尺寸。
    - file_suffix: 输出文件的格式,如'pdf', 'png', 'svg'等。
    - filelist: 需要转换的文件列表,包含多个文件的路径。
    - backgroundtype: 背景颜色信息。
    返回值:
    无直接返回值,该函数的主要作用是转换文件并保存到指定路径。
    """
    for file in filelist:
        # 打印当前处理的文件名
        print(file)
        # 获取文件名,不包含扩展名
        file_name = os.path.basename(file).split(".")[0]
        # 获取文件的目录路径
        outpath = os.path.dirname(file)
        # 根据文件名和指定的文件格式构建输出文件的完整路径
        pdf_file_name = os.path.join(outpath, f"{file_name}.{file_suffix}")
        # 如果文件格式为bmp,则输出格式为png
        if file_suffix == "bmp":
            pdf_file_name = os.path.join(outpath, f"{file_name}.png")
        # 如果文件格式为svg,则调用特定的转换函数
        if file_suffix == "svg":
            convert_dwg_to_svg(file, pdf_file_name, width, height)
        # 对于其他格式,假设为dwg,调用转换为pdf或其他图片格式的函数
        else:
            convert_dxf_to_image(
                file, pdf_file_name, width, height, backgroundtype, file_suffix
            )

def ensure_non_empty_value(value, default):
    """
    Ensure the given value is non-empty. If the value is empty, return the default value.
    Parameters:
    - value: The value to check and return if it is non-empty.
    - default: The default value to return if the given value is empty.
    Returns:
    - The given value if it is non-empty; otherwise, the default value.
    """
    # Return the given value if it is non-empty, otherwise return the default value
    return value if value else default

if __name__ == "__main__":
    currentPath = get_current_file_path()
    inifile = os.path.join(currentPath, "dwg2svg.ini")
    print(f"开始转换,ini文件为{inifile}")
    print(
        """配置文件格式为
            {
                \033[34m[settings]
                path=
                width=64
                height=64
                file_suffix=svg
                backgroundtype=0\033[0m
            }
            \033[32mfile_suffix\033[0m为pdf、bmp、png、svg
            \033[32mbackgroundtype\033[0m默认为0
            \033[34m{
                0: config.BackgroundPolicy.DEFAULT,
                1: config.BackgroundPolicy.BLACK,
                2: config.BackgroundPolicy.WHITE,
                3: config.BackgroundPolicy.CUSTOM,
                4: config.BackgroundPolicy.PAPERSPACE,
                5: config.BackgroundPolicy.MODELSPACE,
                6: config.BackgroundPolicy.OFF,
            }\033[0m
        """
    )
    iniconfig = myconf()
    inputpath, width, height, file_suffix, backgroundtype = "", 0.0, 0.0, "", 0
    if os.path.exists(inifile):
        inputpath, width, height, file_suffix, backgroundtype = read_config_file(
            inifile
        )
    else:
        print(f"{inifile} 配置文件不存在,请检查配置文件路径是否正确")
    inputpath = ensure_non_empty_value(inputpath, currentPath)
    width = ensure_non_empty_value(width, 64)
    height = ensure_non_empty_value(height, 64)
    file_suffix = ensure_non_empty_value(file_suffix, "pdf")
    backgroundtype = ensure_non_empty_value(backgroundtype, 0)
    print(f"dwg文件夹为:{inputpath}")
    filelist = getFileName(inputpath)
    process_files(width, height, file_suffix, backgroundtype, filelist)
    print("结束转换")

dwg2svg.ini

INI
1
2
3
4
5
6
[settings]
path=
width=64
height=64
file_suffix=svg
backgroundtype=0

其它设置

如果要改成白底

Python
# 3. create the frontend
# 定义一个字典来映射 backgroundtype 到对应的 BackgroundPolicy
policy_map = {
    0: config.BackgroundPolicy.DEFAULT,
    1: config.BackgroundPolicy.BLACK,
    2: config.BackgroundPolicy.WHITE,
    3: config.BackgroundPolicy.CUSTOM,
    4: config.BackgroundPolicy.PAPERSPACE,
    5: config.BackgroundPolicy.MODELSPACE,
    6: config.BackgroundPolicy.OFF,
}

# 使用 try-except 来处理可能出现的 KeyError 异常
try:
    background_policy = policy_map[backgroundtype]
except KeyError:
    # 如果 backgroundtype 不在预定义的映射中,则使用默认策略
    background_policy = config.BackgroundPolicy.DEFAULT
    print("Warning: Invalid backgroundtype. Using default policy.")

    # 创建 Configuration 对象
    cfg = config.Configuration(background_policy=background_policy)

    # 初始化 Frontend 实例
    frontend = Frontend(context, backend, config=cfg)

pdf打印使用Monochrome.ctb不起作用

设置的plotstyle没起作用,手动打印没有问题

C++
//get the active layout
AcDbLayout* pLayout = pLayMan->findLayoutNamed(pLayMan->findActiveLayout(TRUE), TRUE);//获得当前布局
AcDbObjectId  m_layoutId = pLayout->objectId();//获得布局的Id
AcPlPlotInfo plotInfo;
AcDbPlotSettingsValidator* pPSV = acdbHostApplicationServices()->plotSettingsValidator();

plotInfo.setLayout(pLayout->objectId());//必须设置

AcDbPlotSettings* m_pSetting = new AcDbPlotSettings(pLayout->modelType());

m_pSetting->copyFrom(pLayout);
pPSV->refreshLists(m_pSetting);

m_pSetting->setShadePlot(AcDbPlotSettings::kAsDisplayed);
m_pSetting->setShadePlotResLevel(AcDbPlotSettings::kNormal);
m_pSetting->setScaleLineweights(false);
m_pSetting->setPrintLineweights(true);
m_pSetting->setPlotTransparency(false);
m_pSetting->setPlotPlotStyles(true);
m_pSetting->setDrawViewportsFirst(true);

缺少m_pSetting->setPlotPlotStyles(true);

某些图纸的layout里有数据,没有设置plotstyle信息,需要手动设置