在AutoCAD绘图工作中,经常用到特性面板,它可以方便地查询、修改CAD对象的详细信息,如颜色、线型等,它是一个非常实用且便捷的工具。如果能为自定义对象添加一个特性面板(OPM),这无疑是众多初学者极感兴趣的事情。笔者也是一名ObjectARX的初学者和爱好者,为了给自定义对象添加OPM,笔者查阅了无数的网上和书籍资料,但大多寥寥数语,含糊其辞。功夫不负有心人,在经历了千百次的“测试-失败-改进”后,终于摸索出了自定义对象OPM编程的部分细节,现将之分享。由于笔者水平有限,文中的错误和疏漏还望各位大侠指点。

本文以具有6个顶点的折线及一行格式化文字组成一个自定义对象(MyObject),拟在特性面板中实现折线顶点的显示与编辑、格式化文本的选择以及位置编辑等功能。笔者所用版本为ObjectARX 2020,编程语言为C++。本例功能虽简单,但特性表中的一般项、下拉列表控件、数值调节控件、三维坐标分解等均有涉及,基本可以涵盖特性表的全部常用功能。

  1. 添加新建项,双击“ArxAtlWizComWrapper”;
  2. Shot Name填写“MyObjectOPM”,其他默认,点击下一步;
  3. DBX classname填写自定义对象的类名“MyObject”,并选中“Entity Interfafe support(versus just Object)”、“Use IOPMPropertyExtensionImpl”、“Implement IOPMPropertyExpander”选项,点击完成;
  4. 打开“MyObjectOPM.h”文件,将#include "***.h"(DBX类的头文件)修改为#include "***_i.h",并添加包含#include "MyObject.h";
  5. 重新生成一次。
  6. 为自定义对象类添加函数:virtual Acad::ErrorStatus subGetClassID(CLSID* pClsid) const(protected属性),其实现代码如下:
//获取OPM的ID,以建立COM方式的通讯
Acad::ErrorStatus MyObject::subGetClassID(CLSID* pClsid) const
{assertReadEnabled();*pClsid = CLSID_MyObjectOPM;return Acad::eOk;
}

7. 变量CLSID_MyObjectOPM会报错,添加4中的包含文件:#include "***_i.h"

8. 为自定义对象类添加私有变量:

private:AcGePoint3d          mTxPt;  //格式化文本插入点AcGePoint3dArray  mPts;   //折线的顶点坐标集合AcString         mTx;    //格式化文本

9. 为自定义对象类添加公有函数:

//-----------------------------------------------------------------------------
Acad::ErrorStatus MyObject::GetVertex(int index, AcGePoint3d &pt) const
{assertReadEnabled();pt = mPts[index];return Acad::eOk;
}//-----------------------------------------------------------------------------
Acad::ErrorStatus MyObject::SetVertex(int index, AcGePoint3d newVal)
{assertWriteEnabled();mPts[index] = newVal;return Acad::eOk;
}//-----------------------------------------------------------------------------
AcString MyObject::GetText() const
{assertReadEnabled();return mTx;
}//-----------------------------------------------------------------------------
Acad::ErrorStatus MyObject::SetText(AcString newVal)
{assertWriteEnabled();mTx = newVal;return Acad::eOk;
}//-----------------------------------------------------------------------------
Acad::ErrorStatus MyObject::GetIns(AcGePoint3d &pt) const
{assertReadEnabled();pt = mTxPt;return Acad::eOk;
}//-----------------------------------------------------------------------------
Acad::ErrorStatus MyObject::SetIns(AcGePoint3d newVal)
{assertWriteEnabled();mTxPt = newVal;return Acad::eOk;
}

10. 打开DBX项目的.idl文件,在interface IMyObjectOPM : IAcadEntity   { };段中添加如下代码,以初始化特性表:

[propget, id(1), helpstring("折线顶点坐标集合")] HRESULT Vertex([in] SHORT index, [out, retval] VARIANT *pVal);
[propput, id(1), helpstring("折线顶点坐标集合")] HRESULT Vertex([in] SHORT index, [in] VARIANT newVal);
[propget, id(2), helpstring("格式化的文本")] HRESULT Explain([out, retval] BSTR *pVal);
[propput, id(2), helpstring("格式化的文本")] HRESULT Explain([in] BSTR *newVal);
[propget, id(3), helpstring("文本插入点")] HRESULT InsertPt([out, retval] VARIANT *pVal);
[propput, id(3), helpstring("文本插入点")] HRESULT InsertPt([in] VARIANT newVal);
[propget, id(4), helpstring("说明")] HRESULT Note([out, retval] BSTR *pVal);
//注意:id值从1开始自定义编号,既是在“特性”列表中的显示顺序(dispID),但此值在所有代码中须始终一一对应。

11. 打开“MyObjectOPM.h”文件,定义2个常量:#define WjcCategoryID1 86  #define WjcCategoryID2 87//用于特性表的分类号,在BEGIN_OPMPROP_MAP() END_OPMPROP_MAP()段间插入如下语句,以进行属性分类及编辑模式等的声明,这些语句须和10中的语句对应:

//IOPMPropertyExtension
BEGIN_OPMPROP_MAP()OPMPROP_ENTRY(0, 0x001, WjcCategoryID1, 0, 0, 0, _T(""), 0, 1, IID_NULL, IID_NULL, "")OPMPROP_ENTRY(0, 0x002, WjcCategoryID2, 0, 0, 0, _T(""), 0, 1, IID_NULL, IID_NULL, "")OPMPROP_ENTRY(0, 0x003, WjcCategoryID2, 0, 0, 0, _T(""), 0, 1, IID_NULL, IID_NULL, "")OPMPROP_ENTRY(0, 0x004, WjcCategoryID1, 0, 0, 0, _T(""), 0, 0, IID_NULL, IID_NULL, "")
END_OPMPROP_MAP()
/*⑴DescriptionID:默认0
⑵dispID:见10条的注意
⑶catagoryID:分组的ID
⑷catagoryNameID:默认0
⑸elements string list ID (semi-colon separator) :默认0
⑹predefined strings ID (semi-colon separator) :默认0
⑺predefined values:默认_T("")
⑻grouping:默认0
⑼editable:是否可编辑:1-可编辑;0-不能编辑
⑽property:默认 IID_NULL
⑾other:默认 IID_NULL
⑿proppage:默认 ""*/

12. 声明如下函数,这些函数须和10中的语句一一对应,且函数名称、参数都是一一对应的,这些函数是OPM和自定义对象进行数据交换的唯一通道:

public://IMyObjectOPMSTDMETHOD(get_Vertex)(/*[in]*/ SHORT index, /*[out, retval]*/VARIANT *pVal);STDMETHOD(put_Vertex)(/*[in]*/ SHORT index, /*[in]*/ VARIANT newVal);STDMETHOD(get_Explain)(BSTR *pVal);STDMETHOD(put_Explain)(BSTR *newVal);STDMETHOD(get_InsertPt)(/*[out, retval]*/VARIANT *pVal);STDMETHOD(put_InsertPt)(/*[in]*/ VARIANT newVal);STDMETHOD(get_Note)(BSTR *pVal);//在MyObject类中须有与这些函数对应的函数

13. 实现上述函数:

//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::get_Vertex(/*[in]*/ SHORT index, /*[out, retval]*/VARIANT *pVal)
{try{AcDbObjectPointer <MyObject>pC(m_objRef.objectId(), AcDb::kForRead);if (pC.openStatus() != Acad::eOk)return E_ACCESSDENIED;AcAxPoint3d pt;pC->GetVertex(index, pt);pt.setVariant(*pVal);}catch (const HRESULT hf)//{Error("请检查输入的参数!");return hf;}return S_OK;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::put_Vertex(/*[in]*/ SHORT index, /*[in]*/ VARIANT newVal)
{try{AcAxDocLock docLock(m_objRef.objectId(), AcAxDocLock::kNormal);if (docLock.lockStatus() != Acad::eOk && docLock.lockStatus() != Acad::eNoDatabase)return E_ACCESSDENIED;AcDbObjectPointer <MyObject>pC(m_objRef.objectId(), AcDb::kForWrite);if (pC.openStatus() != Acad::eOk){return E_ACCESSDENIED;}AcAxPoint3d pt(newVal);pC->SetVertex(index, pt);}catch (const HRESULT hf){Error("请检查输入的参数!");return hf;}return S_OK;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::get_Explain(BSTR *pVal)
{try{AcDbObjectPointer <MyObject>pC(m_objRef.objectId(), AcDb::kForRead);if (pC.openStatus() != Acad::eOk){return E_ACCESSDENIED;}*pVal = ::SysAllocString(pC->GetText());}catch (const HRESULT hf){Error("请检查输入的参数!");return hf;}return S_OK;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::put_Explain(BSTR *newVal)
{try{AcString ts;ts.format(_T("%s"), *newVal);::SysFreeString(*newVal);AcAxDocLock docLock(m_objRef.objectId(), AcAxDocLock::kNormal);if (docLock.lockStatus() != Acad::eOk && docLock.lockStatus() != Acad::eNoDatabase)return E_ACCESSDENIED;AcDbObjectPointer <MyObject>pC(m_objRef.objectId(), AcDb::kForWrite);if (pC.openStatus() != Acad::eOk){return E_ACCESSDENIED;}pC->SetText(ts);}catch (const HRESULT hf){Error("请检查输入的参数!");return hf;}return S_OK;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::get_InsertPt(/*[out, retval]*/VARIANT *pVal)
{try{AcDbObjectPointer <MyObject>pC(m_objRef.objectId(), AcDb::kForRead);if (pC.openStatus() != Acad::eOk)return E_ACCESSDENIED;AcAxPoint3d pt;pC->GetIns(pt);pt.setVariant(*pVal);}catch (const HRESULT hf)//{Error("请检查输入的参数!");return hf;}return S_OK;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::put_InsertPt(/*[in]*/ VARIANT newVal)
{try{AcAxDocLock docLock(m_objRef.objectId(), AcAxDocLock::kNormal);if (docLock.lockStatus() != Acad::eOk && docLock.lockStatus() != Acad::eNoDatabase)return E_ACCESSDENIED;AcDbObjectPointer <MyObject>pC(m_objRef.objectId(), AcDb::kForWrite);if (pC.openStatus() != Acad::eOk){return E_ACCESSDENIED;}AcAxPoint3d pt(newVal);pC->SetIns(pt);}catch (const HRESULT hf){Error("请检查输入的参数!");return hf;}return S_OK;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::get_Note(BSTR *pVal)
{*pVal = ::SysAllocString(_T("成功展示"));return S_OK;
}

14. 在“MyObjectOPM.h”中声明如下重载函数(public):

    //IOPMPropertyExpander//分解复杂的属性(如三维坐标值包含x、y、z属性)STDMETHOD(GetElementStrings)(/*[in]*/DISPID dispID, /*[out]*/OPMLPOLESTR __RPC_FAR *pCaStringsOut, /*[out]*/OPMDWORD __RPC_FAR *pCaCookiesOut);//设置复杂属性的当前值STDMETHOD(GetElementValue)(/*[in]*/DISPID dispID, /*[in]*/DWORD dwCookie, /*[out]*/VARIANT *pVarOut);//读取复杂属性的当前值,并返回给关联的实体STDMETHOD(SetElementValue)(/*[in]*/DISPID dispID, /*[in]*/DWORD dwCookie, /*[in]*/VARIANT VarIn);//设置数值调节钮控件每组数据的数据个数,如三维坐标的每组数据个数为3,即x、y、zSTDMETHOD(GetElementGrouping)(/*[in]*/DISPID dispID, /*[out]*/short *groupingNumber);//设置数值调节钮控件的最大值,其值从1开始,步长为1STDMETHOD(GetGroupCount)(/*[in]*/DISPID dispID, /*[out]*/long *nGroupCnt);//设置下拉列表控件中的预定义字符串(或true/false)STDMETHOD(GetPredefinedStrings)(/*[in]*/DISPID dispID, /*[out]*/CALPOLESTR *pCaStringsOut, /*[out]*/CADWORD *pCaCookiesOut);//设置下拉列表控件的当前显示字符串(或true/false)STDMETHOD(GetPredefinedValue)(/*[in]*/DISPID dispID, /*[in]*/DWORD dwCookie, /*[out]*/VARIANT *pVarOut);//设置列表分类/分组的名称STDMETHOD(GetCategoryName)(/* [in] */ PROPCAT propcat,/* [in] */ LCID lcid,/* [out] */ BSTR* pbstrName);//重置/覆盖列表中简单属性(单行显示)的名称STDMETHOD(GetDisplayName)(/*[in]*/DISPID dispID, /*[out]*/BSTR *pBstr);

15. 实现上述函数:

//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetElementValue (DISPID dispID, DWORD dwCookie, VARIANT *pVarOut) {if (pVarOut == NULL) return (E_POINTER);if (dispID == 1){int index;index = int(dwCookie / 3);/*dwCookie是一个计数器,是用于获取和设置每个属性项的值的唯一标识符,编号从0开始,依次递增1.本例中一个三维坐标对应3个连续的dwCookie值*/CComVariant var;get_Vertex(index, &var);AcAxPoint3d pt(var);pVarOut->vt = VT_R8;pVarOut->dblVal = pt[dwCookie % 3];return (S_OK);}else if (dispID == 3){CComVariant var;get_InsertPt(&var);AcAxPoint3d pt(var);pVarOut->vt = VT_R8;pVarOut->dblVal = pt[dwCookie];return (S_OK);}return (E_NOTIMPL) ;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::SetElementValue (DISPID dispID, DWORD dwCookie, VARIANT VarIn) {if (dispID == 1){int index;index = int(dwCookie / 3);CComVariant var;get_Vertex(index, &var);AcAxPoint3d pt(var);pt[dwCookie % 3] = VarIn.dblVal;pt.setVariant(var);put_Vertex(index, var);return (S_OK);}else if (dispID == 3){CComVariant var;get_InsertPt(&var);AcAxPoint3d pt(var);pt[dwCookie] = VarIn.dblVal;pt.setVariant(var);put_InsertPt(var);return (S_OK);}return (E_NOTIMPL) ;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetElementStrings (DISPID dispID, OPMLPOLESTR __RPC_FAR *pCaStringsOut, OPMDWORD __RPC_FAR *pCaCookiesOut) {if (pCaStringsOut == NULL || pCaCookiesOut == NULL)  return (E_POINTER);if (dispID == 1){pCaStringsOut->cElems = 3;pCaStringsOut->pElems = (LPOLESTR*)CoTaskMemAlloc(sizeof(LPOLESTR) * 3);pCaStringsOut->pElems[0] = SysAllocString(L"  顶点 x 坐标");pCaStringsOut->pElems[1] = SysAllocString(L"  顶点 y 坐标");pCaStringsOut->pElems[2] = SysAllocString(L"  顶点 z 坐标");pCaCookiesOut->cElems = 3;pCaCookiesOut->pElems = (DWORD*)CoTaskMemAlloc(sizeof(DWORD) * 3);pCaCookiesOut->pElems[0] = 0;pCaCookiesOut->pElems[1] = 1;pCaCookiesOut->pElems[2] = 2;return (S_OK);}else if (dispID == 3){pCaStringsOut->cElems = 3;pCaStringsOut->pElems = (LPOLESTR*)CoTaskMemAlloc(sizeof(LPOLESTR) * 3);pCaStringsOut->pElems[0] = SysAllocString(L"文本 x 坐标");pCaStringsOut->pElems[1] = SysAllocString(L"文本 y 坐标");pCaStringsOut->pElems[2] = SysAllocString(L"文本 z 坐标");pCaCookiesOut->cElems = 3;pCaCookiesOut->pElems = (DWORD*)CoTaskMemAlloc(sizeof(DWORD) * 3);pCaCookiesOut->pElems[0] = 0;pCaCookiesOut->pElems[1] = 1;pCaCookiesOut->pElems[2] = 2;return (S_OK);}return (E_NOTIMPL) ;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetElementGrouping (DISPID dispID, short *groupingNumber) {if (groupingNumber == NULL) return (E_POINTER);if (dispID == 1){*groupingNumber = 3;//每组三个数据,及x、y、zreturn (S_OK);}return (E_NOTIMPL) ;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetGroupCount (DISPID dispID, long *nGroupCnt) {if (nGroupCnt == NULL)return (E_POINTER);if (dispID == 1){*nGroupCnt = 6; // 顶点数return S_OK;}return (E_NOTIMPL) ;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetPredefinedStrings(/*[in]*/DISPID dispID, /*[out]*/CALPOLESTR *pCaStringsOut, /*[out]*/CADWORD *pCaCookiesOut)
{if (dispID != 2)return  IOPMPropertyExtensionImpl<CMyObjectOPM>::GetPredefinedStrings(dispID, pCaStringsOut, pCaCookiesOut);USES_CONVERSION;if (dispID == 2){long size = 4;pCaStringsOut->pElems = (LPOLESTR *)::CoTaskMemAlloc(sizeof(LPOLESTR) * size);pCaCookiesOut->pElems = (DWORD *)::CoTaskMemAlloc(sizeof(DWORD) * size);pCaStringsOut->cElems = (ULONG)size;pCaCookiesOut->cElems = (ULONG)size;pCaStringsOut->pElems[0] = ::SysAllocString(_T("我们"));pCaCookiesOut->pElems[0] = 0;pCaStringsOut->pElems[1] = ::SysAllocString(_T("一起"));pCaCookiesOut->pElems[1] = 1;pCaStringsOut->pElems[2] = ::SysAllocString(_T("学习")); pCaCookiesOut->pElems[2] = 2;pCaStringsOut->pElems[3] = ::SysAllocString(_T("ObjectARX")); pCaCookiesOut->pElems[3] = 3;return S_OK;}return E_NOTIMPL;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetPredefinedValue(/*[in]*/DISPID dispID, /*[in]*/DWORD dwCookie, /*[out]*/VARIANT *pVarOut)
{if (dispID != 2)return  IOPMPropertyExtensionImpl<CMyObjectOPM>::GetPredefinedValue(dispID, dwCookie, pVarOut);USES_CONVERSION;const TCHAR* pName = NULL;if (dispID == 2){switch (dwCookie){case 0:pName = _T("我们");break;case 1:pName = _T("一起");break;case 2:pName = _T("学习");break;case 3:pName = _T("ObjectARX");break;default:return E_NOTIMPL;}::VariantCopy(pVarOut, &CComVariant(CT2W(pName)));return S_OK;}return E_NOTIMPL;
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetCategoryName(/* [in] */ PROPCAT propcat,/* [in] */ LCID lcid,/* [out] */ BSTR* pbstrName)
{if (propcat == WjcCategoryID1){*pbstrName = ::SysAllocString(_T("分类1 测试"));return S_OK;}else if (propcat == WjcCategoryID2){*pbstrName = ::SysAllocString(_T("分类2 测试")); return S_OK;}else{return S_FALSE;}
}//-----------------------------------------------------------------------------
STDMETHODIMP CMyObjectOPM::GetDisplayName(/*[in]*/DISPID dispID, /*[out]*/BSTR *pBstr)
{if (pBstr == NULL) return (E_POINTER);switch (dispID){case (0x401):*pBstr = ::SysAllocString(_T("对象特性表-乱石作品"));break;case (0x516):*pBstr = ::SysAllocString(_T("颜色"));break;case (0x501):*pBstr = ::SysAllocString(_T("图层"));break;case (0x502):*pBstr = ::SysAllocString(_T("线型"));break;case (0x503):*pBstr = ::SysAllocString(_T("线型比例"));break;case (0x513):*pBstr = ::SysAllocString(_T("打印样式"));break;case (0x514):*pBstr = ::SysAllocString(_T("线宽"));break;case (0x515):*pBstr = ::SysAllocString(_T("超链接"));break;case (0x577):*pBstr = ::SysAllocString(_T("材质"));break;case (0x579):*pBstr = ::SysAllocString(_T("实体透明度"));break;case (0x01):*pBstr = ::SysAllocString(_T("当前顶点"));break;case (0x02):*pBstr = ::SysAllocString(_T("格式文本"));break;case (0x04):*pBstr = ::SysAllocString(_T("说明"));break;default:break;}return (S_OK);
}

16. 重新编译后,在AutoCAD中的测试结果如图,此时选中自定义对象,特性表中已能显示出所需参数,且更改特性表中的参数,自定义对象亦能随之变化。成功!!!

ObjectARX自定义对象的OPM相关推荐

  1. java查询结果自定义显示_JPA自定义对象接收查询结果集操作

    最近使用JPA的时候,碰到需要自定义查询结果集的场景,网上搜了一下,都是需要自定义方法写一大串代码实现的,太繁琐了,有那时间还不如用mybaits. 用JPA就是要尽量通过声明接口解决持久层问题,要不 ...

  2. YOLOv5实现自定义对象训练与OpenVINO部署全解析

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 大家好,前面写了一个OpenVINO部 ...

  3. Object-C代码练习【自定义对象的归档】

    2019独角兽企业重金招聘Python工程师标准>>> // // main.m // 自定义对象的归档 // // Created by on 14-11-9. // Copyri ...

  4. HashMap存自定义对象为什么要重写 hashcode 和 equals 方法?

    HashMap的k放过自定义对象么? 当我们把自定义对象存入HashMap中时,如果不重写hashcode和equals这两个方法,会得不到预期的结果. class Key{private Integ ...

  5. 按属性对自定义对象的ArrayList进行排序

    我读过有关使用Comparator对ArrayList进行排序的信息,但在所有示例中,人们都使用了compareTo ,根据一些研究,它是String的一种方法. 我想按自定义对象的属性之一对Arra ...

  6. store 存取数据数组对象_ios – 如何在数组中保存自定义对象并将其存储在NSUserDefaults – iPhone中...

    要在用户默认值上存储和检索具有自定义对象的数组,您可以使用以下方法: -(void)writeArrayWithCustomObjToUserDefaults:(NSString *)keyName ...

  7. java 集合自定义元素_java集合 collection-list-ArrayList 将自定义对象作为元素存到ArrayList集合中,并去除重复元素。...

    import java.util.*;/*将自定义对象作为元素存到ArrayList集合中,并去除重复元素. 比如:存人对象.同姓名同年龄,视为同一个人.为重复元素. 思路: 1,对人描述,将数据封装 ...

  8. [置顶] 深入浅出Javascript(三)创建自定义对象以及属性、方法

    怎么样创建一个对象? 利用Object创建自定义对象 JavaScript能够自定义对象来扩展程序的功能,不仅如此,它还能扩展JavaScript提供的内置对象,新增内置对象的属性或方法 例如下面代码 ...

  9. JavaScript 自定义对象

    原文:JavaScript 自定义对象 在Js中,除了Array.Date.Number等内置对象外,开发者可以通过Js代码创建自己的对象. 目录 1. 对象特性:描述对象的特性 2. 创建对象方式: ...

最新文章

  1. 405 not allowed_无偿献血走进山东科技大学 405名爱心师生献血14万毫升
  2. 炫酷大屏demo_可视化大屏动态效果
  3. GhostNet 测试
  4. 图文详解安装NetBackup 6.5备份恢复Oracle 10g rac 数据库(修订)
  5. 坑爹的属性,android:descendantFocusability用法简析
  6. win10可用空间变成未分配_教你两种方法有效利用Win10未分配的空间 - 易我科技...
  7. netflix的准实验面临的主要挑战
  8. 四、Vue组件化开发学习笔记——父子组件通信,父级向子级传值(props),子级向父级传值(自定义事件),slot插槽
  9. linux /dev/null,Shell中 /dev/null和 /dev/null 21
  10. java案例代码20--斗地主V2
  11. SD-Host 控制器设计
  12. maya python 游戏与影视编程指南pdf_《Maya Python游戏与影视编程指南》.( [美]Adam Mechtley).[PDF]...
  13. 06-JavaWEB_Git
  14. 2021年2月程序员工资统计,平均15144元
  15. nvidia-smi 在 MIG M. 出现 Disabled
  16. MultiWarhead 球缺罩界面设计
  17. 移动端vConsole查看控制台信息
  18. 虚幻4和Unity3D应该学哪个? 1
  19. HTML/JS/浏览器与串口通信(一)
  20. 利用命令行工具pdftk对PDF进行合并分割

热门文章

  1. 配电室综合监控系统的设计与应用
  2. Linux控制GPIO
  3. java中 try用法,Java里try catch的简单用法
  4. 2023新版花粥商城PHP源码+附知识付费模版
  5. FilterDispatcher
  6. Delphi中的TStream类
  7. matlab 等高线颜色,MATLAB等高线图 - osc_ygiycxyf的个人空间 - OSCHINA - 中文开源技术交流社区...
  8. matlab 非线性差分方程,用牛顿法求解非线性差分方程组
  9. python字符串常量_常用的Python字符串常量
  10. 关于如何选择Bloger托管商