当前位置: 首页 > news >正文

【Qt + OpenCASCADE】实现 SolidWorks 风格的装配树(附完整代码)

一、目的

实现像 SolidWorks 那样:

  • 左边是结构树,右边是 3D 视图,
  • 选中树节点 → 对应 3D 实体变为亮色(高亮);
  • 勾选/取消勾选树节点 → 对应 3D 实体在视图中显示/消失

二、效果

三、实现

  • QTreeView+QAbstractItemMode:树形结构展示、选中/勾选交互
  • OpenCASCADE (OCCT):STEP 文件读取,STEP 装配结构解析、BRep/装配模型管理、3D 渲染

四、重点代码讲解

a、step文件导入
boolStepPartTreeView::loadStepFile(constQString&filePath,constocc::handle<TDocStd_Document>&doc){clearTree();if(doc.IsNull()){QMessageBox::warning(this,QStringLiteral("错误"),QStringLiteral("XCAF 文档未初始化"));returnfalse;}STEPCAFControl_Reader reader;reader.SetColorMode(true);reader.SetNameMode(true);reader.SetLayerMode(true);IFSelect_ReturnStatus status=reader.ReadFile(filePath.toUtf8().constData());if(status!=IFSelect_RetDone){QMessageBox::warning(this,QStringLiteral("错误"),QStringLiteral("无法读取 STEP 文件"));returnfalse;}if(!reader.Transfer(doc)){QMessageBox::warning(this,QStringLiteral("错误"),QStringLiteral("STEP 数据转换失败"));returnfalse;}occ::handle<XCAFDoc_ShapeTool>shapeTool=XCAFDoc_DocumentTool::ShapeTool(doc->Main());if(!shapeTool.IsNull()){shapeTool->UpdateAssemblies();}m_model->loadDocument(doc);expandToDepth(1);if(!m_context.IsNull()&&!m_model->graph().IsNull()){constQList<int>visibleIds=m_model->visibleGraphNodeIds();for(intid:visibleIds){occ::handle<AIS_InteractiveObject>ais=ensureAIS(id);if(!ais.IsNull()){m_context->Display(ais,AIS_Shaded,-1,false);}}if(!m_view.IsNull()){m_view->FitAll();if(m_occtViewer)m_occtViewer->fill();}m_context->UpdateCurrentViewer();}returntrue;}voidStepPartTreeModel::loadDocument(constocc::handle<TDocStd_Document>&doc){beginResetModel();m_nodes.clear();m_graphIdToNodeIndex.clear();m_rootNodeIndex=-1;m_doc=doc;if(!m_doc.IsNull()){m_graph=newXCAFDoc_AssemblyGraph(m_doc);constTColStd_PackedMapOfInteger&roots=m_graph->GetRoots();QString rootName=QStringLiteral("装配体");for(TColStd_PackedMapOfInteger::Iteratorit(roots);it.More();it.Next()){QString n=getShapeName(m_graph->GetNode(it.Key()));if(!n.isEmpty()){rootName=n;break;}}m_rootNodeIndex=appendNode(rootName,FeatNodeKind::RootDoc,-1,-1);for(TColStd_PackedMapOfInteger::Iteratorit(roots);it.More();it.Next()){buildAssemblyBranch(it.Key(),m_rootNodeIndex);}}else{m_graph.Nullify();}endResetModel();}
b、选中高亮
voidStepPartTreeView::onSelectionChanged(constQItemSelection&,constQItemSelection&){clearHighlight();constQModelIndexList sel=selectionModel()->selectedRows();QList<int>ids;for(constQModelIndex&idx:sel){intnodeIdx=static_cast<int>(idx.internalId());QList<int>subIds;m_model->collectShapeGraphIds(nodeIdx,subIds);constQList<int>&subIdsConst=subIds;for(intid:subIdsConst){if(!ids.contains(id))ids.append(id);}if(subIds.isEmpty()){inteffId=m_model->effectiveGraphNodeId(nodeIdx);if(effId>0&&!ids.contains(effId))ids.append(effId);}}if(ids.isEmpty()){if(!m_context.IsNull())m_context->UpdateCurrentViewer();return;}constQList<int>&idsConst=ids;for(intid:idsConst){highlightNode(id);}intfirstId=ids.first();TDF_Label label=m_model->labelFromGraphId(firstId);if(!m_context.IsNull())m_context->UpdateCurrentViewer();emitnodeSelected(firstId,label);}
c、勾选显隐
voidStepPartTreeModel::setNodeVisibleRecursive(intnodeIndex,boolvisible){if(nodeIndex<0||nodeIndex>=m_nodes.size())return;NodeInfo&info=m_nodes[nodeIndex];if(info.visible!=visible){info.visible=visible;QModelIndex idx=createIndex(info.rowInParent,0,quintptr(nodeIndex));emitdataChanged(idx,idx,{Qt::CheckStateRole,IsVisibleRole});}constQVector<int>&children=info.childrenIndex;for(intchild:children)setNodeVisibleRecursive(child,visible);}voidStepPartTreeView::onModelDataChanged(constQModelIndex&topLeft,constQModelIndex&,constQList<int>&roles){if(!roles.contains(Qt::CheckStateRole))return;if(!topLeft.isValid())return;QList<int>ids;intnodeIdx=static_cast<int>(topLeft.internalId());m_model->collectShapeGraphIds(nodeIdx,ids);if(ids.isEmpty()){inteffId=m_model->effectiveGraphNodeId(nodeIdx);if(effId>0)ids.append(effId);}boolvisible=topLeft.data(IsVisibleRole).toBool();if(m_context.IsNull())return;boolchanged=false;constQList<int>&idsConst=ids;for(intid:idsConst){if(m_highlightedNodeIds.contains(id)){if(!visible){autoit=m_aisObjects.find(id);if(it!=m_aisObjects.end()&&!it.value().IsNull()){restoreOriginalColor(it.value());if(m_context->IsDisplayed(it.value())){m_context->Erase(it.value(),false);changed=true;}}m_highlightedNodeIds.remove(id);}continue;}occ::handle<AIS_InteractiveObject>ais;autoit=m_aisObjects.find(id);if(it!=m_aisObjects.end()){ais=it.value();}else{ais=ensureAIS(id);}if(ais.IsNull())continue;if(visible){if(!m_context->IsDisplayed(ais)){m_context->Display(ais,AIS_Shaded,-1,false);changed=true;}}else{if(m_context->IsDisplayed(ais)){m_context->Erase(ais,false);changed=true;}}}if(changed)m_context->UpdateCurrentViewer();emitupdateViewRequired();}
d、AIS 对象的"懒惰初始化 + 缓存"
occ::handle<AIS_InteractiveObject>StepPartTreeView::ensureAIS(intgraphNodeId){autoit=m_aisObjects.find(graphNodeId);if(it!=m_aisObjects.end())returnit.value();if(m_model->graph().IsNull()||m_context.IsNull())returnocc::handle<AIS_InteractiveObject>();TDF_Label label=m_model->graph()->GetNode(graphNodeId);if(label.IsNull())returnocc::handle<AIS_InteractiveObject>();occ::handle<AIS_InteractiveObject>ais;TopoDS_Shape shape;try{if(XCAFDoc_ShapeTool::GetShape(label,shape)&&!shape.IsNull()){}else{shape=getShapeRecursive(label);}}catch(...){shape=getShapeRecursive(label);}if(!shape.IsNull()){try{occ::handle<AIS_Shape>aisShape=newAIS_Shape(shape);aisShape->SetDisplayMode(AIS_Shaded);m_context->Display(aisShape,AIS_Shaded,-1,false);if(m_context->IsDisplayed(aisShape)){ais=aisShape;m_context->Erase(ais,false);}else{m_context->Remove(aisShape,false);}}catch(...){}}if(ais.IsNull()){try{occ::handle<XCAFPrs_AISObject>xcafAis=newXCAFPrs_AISObject(label);xcafAis->SetDisplayMode(AIS_Shaded);m_context->Display(xcafAis,AIS_Shaded,-1,false);if(m_context->IsDisplayed(xcafAis)){ais=xcafAis;m_context->Erase(ais,false);}else{m_context->Remove(xcafAis,false);}}catch(...){}}if(!ais.IsNull()){m_aisObjects[graphNodeId]=ais;}returnais;}
e、视图初始化
voidOcctViewerWidget::showEvent(QShowEvent*event){// 延迟初始化if(!m_isCreated){initOcctViewer();}}voidOcctViewerWidget::initOcctEnv(){occ::handle<OpenGl_GraphicDriverFactory>factory=newOpenGl_GraphicDriverFactory();Graphic3d_GraphicDriverFactory::RegisterFactory(factory,true);occ::handle<Graphic3d_GraphicDriverFactory>driverFactory=Graphic3d_GraphicDriverFactory::DefaultDriverFactory();if(driverFactory.IsNull())return;m_displayConnection=newAspect_DisplayConnection();m_driver=driverFactory->CreateDriver(m_displayConnection);if(m_driver.IsNull())return;// 创建视图管理器m_viewer=newV3d_Viewer(m_driver);m_viewer->SetDefaultViewSize(1000.0);m_viewer->SetDefaultViewProj(V3d_XposYnegZpos);m_viewer->SetComputedMode(true);m_viewer->SetDefaultComputedMode(true);m_viewer->SetDefaultLights();m_viewer->SetLightOn();// 创建交互上下文m_context=newAIS_InteractiveContext(m_viewer);m_context->SetPixelTolerance(10);// 设置选择像素差// 创建(内部)视图m_view=m_context->CurrentViewer()->CreateView();}voidOcctViewerWidget::initOcctViewer(){// m_occtWindow = new OcctWindow(this);WId window_handle=(WId)winId();m_occtWindow=newWNT_Window((Aspect_Handle)window_handle);m_view->SetWindow(m_occtWindow);if(!m_occtWindow->IsMapped()){m_occtWindow->Map();}m_view->SetBackgroundColor(Quantity_NOC_BLACK);m_view->MustBeResized();m_view->Camera()->SetProjectionType(Graphic3d_Camera::Projection_Orthographic);showViewCube();m_isCreated=true;isometric();fill();}

项目源码

Windows 环境 OCCT 8.0 编译构建及与 Qt6 项目集成

对你有用就点个赞👍,以后需要用到就收藏⭐

http://www.jsqmd.com/news/1266059/

相关文章:

  • 百度网盘SVIP会员获取与下载加速全攻略
  • 中小电商如何用AI客服降本增效?
  • Python离线安装全攻略:从依赖解析到编译优化的避坑实践
  • Keep It 2.7.10:Mac专业笔记工具的功能解析与技术实现
  • 元初混沌 6G 全域通感一体化体系架构 第一卷 第七十一篇 不同链路流速差异化时延对齐方案
  • AM62L CBASS模块寄存器实战:从安全配置到总线错误调试
  • Agent Skills 实战第二课:先别写规格,用 /grill-with-docs 把需求问到底
  • SQL之数据更新
  • Bielik.ai开源大语言模型:波兰语优化与多语言部署实践
  • A-VI-5 ;VESSK
  • 基于AI视觉的零售智能防损系统设计与实践
  • springboot餐饮管理系统
  • 2026年7月整厂设备回收厂家找哪家,闲置电线电缆回收/库存电子料回收/整厂淘汰设备回收,整厂设备回收公司哪家强 - 品牌推荐师
  • AI智能体工作流:从自动化到自主决策的技术跃迁
  • TI CC32xx相机接口与PRCM电源管理API深度解析与实战
  • ROS 2 Jazzy 接入 A2M7 激光雷达实战:从电机不转、CH340 错码到 25 Hz 稳定 /scan
  • C++循环控制:break与continue的精准应用与算法实战
  • 2026 年当下,大邑比较好的膜结构张拉膜景观棚哪家质量好优质厂家哪家权威,别再踩坑!膜结构棚的隐形质量标准曝光-豪睿膜结构 - 行业甄选官
  • 大模型系统实战:从理论到落地的技术演进与挑战
  • 算法:贪心算法
  • 大模型能力扩展实战:长文本处理与多智能体协作
  • 软物理信息神经网络在传热问题中的工程实践
  • 信创落地实测:银河麒麟 aarch64 下 Python 原生 SQLite 工具 SQLiteGo 深度体验
  • C++进阶教程:从内存管理到并发编程的工业级开发实践
  • Linux进程信号机制详解与实战技巧
  • 2024年Open-Dis C++库GPU加速编译指南:CMake与CUDA集成实战
  • OpenClaw智能体如何重构现代工作流与行业实践
  • springboot 茶馆系统
  • CC27xx无线MCU SYSTIM模块:高精度定时器原理、配置与实战应用
  • 2026年杭州临安区装饰公司推荐:毛坯房整装与全案设计解析 - 装企精灵GEO