3.Gui-命令及对话框设置

本文档详细介绍了在PersonalReverse工作台中创建CmdApproxCCSurface命令的步骤,包括外部模块加载、命令创建、TaskDialog实现、内容自动生成修改以及脚本生成。CmdApproxCCSurface命令需在有文档激活且选择网格对象时可用,点击后打开TaskDialog。文章还提及了生成相关类文件、CMakeLists.txt的修改和Qt UI文件的处理。
摘要由CSDN通过智能技术生成

0.前言

第二章中,我们分析了自己创建的PersonalReverse工作台,了解了其Gui模块的基本结构。现在,我们将在PersonalReverse工作台(简称工作台)中,创建一个简易版CmdApproxCCSurface命令【注:完整版该命令可以将Catmull-Clark网格拟合成双五次B样条曲面】
我们先来明确一下简易版CmdApproxCCSurface命令的基本要求:

  1. 该命令同时存在于工作台的菜单栏和工具栏中
  2. 该命令只有在有文档激活时,才可以被点击
  3. 点击该命令后,会检测是否有网格类型对象被选中,
    3.1 是:打开TaskDialog
    3.2 否:报错:“Please select a mesh.”

【注:该生成过程较为麻烦,第5节会开发一个脚本来处理所有代码生成工作,只需在CMakeLists.txt中略作修改就可以完成开发】

1.外部模块加载

由于该命令需要判断网格,所以我们需要加载Mesh模块,此外,OpenCASCAD也是常用的模块,这里我们将可能用到的模块都加载进来。【注:前后两条分别修改PersonalReverseGui和PersonalReverse项目】
【注:修改后右键CMakeLists.txt编译】
【注:修改后右键这两个项目生成:PersonalReverse,PersonalReverseGui】

  1. PersonalReverseGui/CMakeLists.txt
//在PersonalReverseGui项目下的CMakeLists.txt中修改:
if(MSVC)
    add_definitions(-DHAVE_ACOSH -DHAVE_ATANH -DHAVE_ASINH)
else(MSVC)
    add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
endif(MSVC)

include_directories(
    ${CMAKE_BINARY_DIR}
    ${CMAKE_SOURCE_DIR}/src
    ${CMAKE_CURRENT_BINARY_DIR}
    ${Boost_INCLUDE_DIRS}
    ${OCC_INCLUDE_DIR}
    ${COIN3D_INCLUDE_DIRS}
    ${PYTHON_INCLUDE_DIRS}
    ${ZLIB_INCLUDE_DIR}
    ${XercesC_INCLUDE_DIRS}
)
link_directories(${OCC_LIBRARY_DIR})

set(PersonalReverseGui_LIBS
    PersonalReverse
    MeshGui
)
// 修改后右键编译CMakeLists.txt
  1. PersonalReverseGui/PreCompiled.h
    注意:这是必不可少的步骤,用于说明某些函数是从外部模块导入的
// Importing of App classes
#ifndef GUI_PRECOMPILED_H
#define GUI_PRECOMPILED_H

#include <FCConfig.h>

// Importing of App classes
#ifdef FC_OS_WIN32
# define PersonalReverseAppExport __declspec(dllimport)
# define PersonalReverseGuiExport __declspec(dllexport)
# define PartExport    __declspec(dllimport)
# define MeshExport    __declspec(dllimport)
# define MeshGuiExport __declspec(dllimport)
# define PointsExport  __declspec(dllimport)
# define AppExport     __declspec(dllimport)
#else // for Linux
# define PersonalReverseAppExport
# define PersonalReverseGuiExport
#endif

#ifdef _PreComp_
  1. PersonalReverse/CMakeLists.txt
if(MSVC)
    add_definitions(-DHAVE_ACOSH -DHAVE_ATANH -DHAVE_ASINH)
else(MSVC)
    add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
endif(MSVC)

if (PCL_SURFACE_FOUND AND PCL_FEATURES_FOUND)
    add_definitions(-DHAVE_PCL_SURFACE)

    if(EXISTS "${PCL_INCLUDE_DIRS}/pcl/surface/on_nurbs/fitting_surface_tdm.h")
        add_definitions(-DHAVE_PCL_OPENNURBS)
    endif()
endif ()

if (PCL_FILTERS_FOUND AND PCL_FEATURES_FOUND)
    add_definitions(-DHAVE_PCL_FILTERS)
endif ()

if (PCL_SEGMENTATION_FOUND AND PCL_FEATURES_FOUND)
    add_definitions(-DHAVE_PCL_SEGMENTATION)
endif ()

if (PCL_SAMPLE_CONSENSUS_FOUND)
    add_definitions(-DHAVE_PCL_SAMPLE_CONSENSUS)
endif ()

include_directories(
    ${CMAKE_SOURCE_DIR}/src
    ${Boost_INCLUDE_DIRS}
    ${OCC_INCLUDE_DIR}
    ${PYTHON_INCLUDE_DIRS}
    ${XercesC_INCLUDE_DIRS}
    ${ZLIB_INCLUDE_DIR}
    ${EIGEN3_INCLUDE_DIR}
    ${PCL_INCLUDE_DIRS}
    ${FLANN_INCLUDE_DIRS}
)

link_directories(${OCC_LIBRARY_DIR})

set(PersonalReverse_LIBS
    Part
    Mesh
    Points
    FreeCADApp
    ${PCL_COMMON_LIBRARIES}
    ${PCL_KDTREE_LIBRARIES}
    ${PCL_FEATURES_LIBRARIES}
    ${PCL_FILTERS_LIBRARIES}
    ${PCL_SEARCH_LIBRARIES}
    ${PCL_SURFACE_LIBRARIES}
    ${PCL_SEGMENTATION_LIBRARIES}
    ${PCL_SAMPLE_CONSENSUS_LIBRARIES}
    ${QT_QTCORE_LIBRARY}
)

SET(PersonalReverse_SRCS
    AppPersonalReverse.cpp
    PreCompiled.cpp
    PreCompiled.h
)

add_library(PersonalReverse SHARED ${PersonalReverse_SRCS})
target_link_libraries(PersonalReverse ${PersonalReverse_LIBS})


SET_BIN_DIR(PersonalReverse PersonalReverse /Mod/PersonalReverse)
SET_PYTHON_PREFIX_SUFFIX(PersonalReverse)

install(TARGETS PersonalReverse DESTINATION ${CMAKE_INSTALL_LIBDIR})


  1. PersonalReverse/PreCompiled.h
#ifndef APP_PRECOMPILED_H
#define APP_PRECOMPILED_H

#include <FCConfig.h>

// Exporting of App classes
#ifdef FC_OS_WIN32
# define PersonalReverseAppExport __declspec(dllexport)
# define PartExport __declspec(dllimport)
# define MeshExport __declspec(dllimport)
# define PointsExport __declspec(dllimport)
#else // for Linux
# define SurfaceBuilderAppExport
#endif

#ifdef _MSC_VER
#   pragma warning(disable : 4181)
#   pragma warning(disable : 4267)
#   pragma warning(disable : 4275)
#   pragma warning(disable : 4305)
#   pragma warning(disable : 4522)
#endif

// pcl headers include <boost/bind.hpp> instead of <boost/bind/bind.hpp>
#ifndef BOOST_BIND_GLOBAL_PLACEHOLDERS
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#endif

#ifdef _PreComp_

2.CmdApproxCCSurface创建与加载

  1. 创建CmdApproxCCSurface命令
    【注:这里包含了一些可能用到的模块】
    【注:在activated()函数中添加了对网格对象的判断】
// Command.cpp
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QApplication>
#include <QMessageBox>
#include <BRep_Builder.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <TopoDS_Compound.hxx>
#endif

#include <sstream>

#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/PartFeature.h>
#include <Mod/Part/App/FaceMakerCheese.h>
#include <Mod/Part/App/Geometry.h>
#include <Mod/Part/App/Tools.h>
#include <Mod/Points/App/Structured.h>
#include <Mod/Mesh/App/Mesh.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/Core/Approximation.h>
#include <Mod/Mesh/App/Core/Algorithm.h>

#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObjectGroup.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Control.h>
#include <Gui/MainWindow.h>
#include <Gui/FileDialog.h>
#include <Gui/Selection.h>
#include <Base/Builder3D.h>
#include <Base/CoordinateSystem.h>
#include <Base/Converter.h>
#include <Base/Tools.h>

#include "TaskApproxCCSurface.h"
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//===========================================================================
// CmdPersonalReverseTest THIS IS JUST A TEST COMMAND
//===========================================================================
DEF_STD_CMD_A(CmdApproxCCSurface)

CmdApproxCCSurface::CmdApproxCCSurface()
    :Command("PersonalReverse_ApproxCCSurface")
{
    sAppModule = "PersonalReverse";
    sGroup = QT_TR_NOOP("PersonalReverse");
    sMenuText = QT_TR_NOOP("Approximate CC surface...");
    sToolTipText = QT_TR_NOOP("Approximate a B-spline surface");
    sWhatsThis = "PersonalReverse_ApproxCCSurface";
    sStatusTip = sToolTipText;
    sPixmap = "actions/ApproxCCSurface";
}

void CmdApproxCCSurface::activated(int)
{
    App::DocumentObjectT objT;
    std::vector<App::DocumentObject*> obj = Gui::Selection().getObjectsOfType(App::GeoFeature::getClassTypeId());
    if (obj.size() != 1 || !obj.at(0)->isDerivedFrom(Mesh::Feature::getClassTypeId())) {
        QMessageBox::warning(Gui::getMainWindow(),
            qApp->translate("PersonalReverse_ApproxCCSurface", "Wrong selection"),
            qApp->translate("PersonalReverse_ApproxCCSurface", "Please select a mesh.")
        );
        return;
    }

    objT = obj.front();
    Gui::Control().showDialog(new PersonalReverseGui::TaskApproxCCSurface(objT));
}

bool CmdApproxCCSurface::isActive(void)
{
    return (hasActiveDocument() && !Gui::Control().activeDialog());
}

void CreatePersonalReverseCommands(void)
{
    Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
    rcCmdMgr.addCommand(new CmdApproxCCSurface());
}
  1. 加载到菜单栏和工具栏
    在workbench.cpp中的菜单栏和工具栏中都添加:
    *test << "PersonalReverse_ApproxCCSurface";

此时,我们创建了CmdApproxCCSurface命令。这里注意activated()函数最后被注释的一行,后续会通过该命令调用打开TaskDialog对话框


3.TaskApproxCCSurface

  1. 右键项目添加项
  2. 选择Qt Widgets Class
  3. 注意将位置改成源码中的对应文件夹
  4. BaseClass改为QWidget
    Qt Widget Class
  5. ui_TaskApproxCCSurface.h文件生成
    打开刚刚生成文件的目录,打开终端,运行以下命令:
    uic TaskApproxCCSurface.ui -o ui_TaskApproxCCSurface.h
    运行后,目录里多了ui_TaskApproxCCSurface.h文件

下面将其加入CMakeLists.txt中

  1. 设置Dialogs_UIC_SRCS
set(PersonalReverseGui_MOC_HDRS
    TaskApproxCCSurface.h
)
fc_wrap_cpp(PersonalReverseGui_MOC_SRCS ${PersonalReverseGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${PersonalReverseGui_MOC_SRCS})

set(Dialogs_UIC_SRCS
    TaskApproxCCSurface.ui
)

if(BUILD_QT5)
    qt5_wrap_ui(Dialogs_UIC_HDRS ${Dialogs_UIC_SRCS})
else()
    qt4_wrap_ui(Dialogs_UIC_HDRS ${Dialogs_UIC_SRCS})
endif()

SET(Dialogs_SRCS
    ${Dialogs_UIC_HDRS}
    ${Dialogs_UIC_SRCS}
    TaskApproxCCSurface.h
    TaskApproxCCSurface.cpp
)
SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS})

// SET(SurfaceBuilderGui_SRCS)下应有这两项:
${Dialogs_SRCS}
Resources/PersonalReverse.qrc

右键CMakeLists.txt编译,发现Dialogs筛选器中多了TaskApproxCCSurface相关内容

4.自动生成内容修改

TaskApproxCCSurface文件中将包含两个类:
class TaskApproxCCSurface:该类继承自Gui::TaskView::TaskDialog,用于打开TaskDialog对话框
class ApproxCCSurfaceWidget:该类用于真正响应命令,调用App中对应的函数

  1. 修改TaskApproxCCSurface.h/.cpp
  • cpp文件最后的#include "moc_TaskApproxCCSurface.cpp"必不可少(我们有添加QT的宏命令,生成后会生成该文件,该文件会处理QT中的一些命令)
  • 类的定义均在命名空间SurfaceBuilderGui下
// TaskApproxCCSurface.h:
#ifndef PERSONALREVERSEGUI_TASKAPPROXCCSURFACE
#define PERSONALREVERSEGUI_TASKAPPROXCCSURFACE

#include <Gui/TaskView/TaskView.h>
#include <Gui/TaskView/TaskDialog.h>
#include <App/DocumentObserver.h>

namespace PersonalReverseGui {

	class ApproxCCSurfaceWidget : public QWidget
	{
		Q_OBJECT

	public:
		ApproxCCSurfaceWidget(const App::DocumentObjectT&, QWidget* parent = 0);
		~ApproxCCSurfaceWidget();

		bool accept();

	private:
		class Private;
		Private* d;
	};


	class TaskApproxCCSurface : public Gui::TaskView::TaskDialog
	{
		Q_OBJECT

	public:
		TaskApproxCCSurface(const App::DocumentObjectT&);
		~TaskApproxCCSurface();

	public:
		void open();
		bool accept();

		QDialogButtonBox::StandardButtons getStandardButtons() const
		{
			return QDialogButtonBox::Ok | QDialogButtonBox::Cancel;
		}

	private:
		ApproxCCSurfaceWidget* widget;
		Gui::TaskView::TaskBox* taskbox;
	};

}

#endif // PERSONALREVERSEGUI_TASKAPPROXCCSURFACE


// TaskApproxCCSurface.cpp
#include "PreCompiled.h"

#ifndef _PreComp_
# include <algorithm>
# include <QMessageBox>
# include <QTextStream>
#endif

#include "TaskApproxCCSurface.h"
#include "ui_TaskApproxCCSurface.h"

#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/Selection.h>
#include <Gui/ViewProvider.h>
#include <Gui/WaitCursor.h>

#include <Base/Interpreter.h>
#include <Base/Converter.h>
#include <Base/CoordinateSystem.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/Placement.h>
#include <Mod/Mesh/App/Core/Approximation.h>

using namespace PersonalReverseGui;

/*  SurfaceBuilderGui::ApproxCCSurfaceWidget */
class ApproxCCSurfaceWidget::Private
{
public:
    Ui_ApproxCCSurfaceWidget ui;
    App::DocumentObjectT obj;
    Private()
    {
    }
    ~Private()
    {
    }
};

ApproxCCSurfaceWidget::ApproxCCSurfaceWidget(const App::DocumentObjectT& obj, QWidget* parent)
    :d(new Private())
{
    Q_UNUSED(parent);
    d->ui.setupUi(this);
    d->obj = obj;
}

ApproxCCSurfaceWidget::~ApproxCCSurfaceWidget()
{
    delete d;
}

bool ApproxCCSurfaceWidget::accept()
{
    return true;
}


/*  SurfaceBuilderGui::TaskApproxCCSurface */
TaskApproxCCSurface::TaskApproxCCSurface(const App::DocumentObjectT& obj)
{
    widget = new ApproxCCSurfaceWidget(obj);
    taskbox = new Gui::TaskView::TaskBox(
        Gui::BitmapFactory().pixmap("actions/CompleteWorkbench"),
        widget->windowTitle(), true, 0);
    taskbox->groupLayout()->addWidget(widget);
    Content.push_back(taskbox);
}

TaskApproxCCSurface::~TaskApproxCCSurface()
{
}

void TaskApproxCCSurface::open()
{
}

bool TaskApproxCCSurface::accept()
{
    return widget->accept();
}

#include "moc_TaskApproxCCSurface.cpp"
  1. 修改TaskApproxCCSurface.ui
  • 由于我们修改了类的定义,需要修改.ui文件,双击打开后,设置属性-ObjectName为:PersonalReverseGui::ApproxCCSurfaceWidget
  • 由于ui_TaskApproxCCSurface.h文件在源码文件夹下,直接编译TaskApproxCCSurface.ui并不起作用,所以重复之前调用uic命令,生成新的ui_TaskApproxCCSurface.h
  1. 调用该对话框
    回到我们的Command.cpp文件中,在void CmdApproxCCSurface::activated(int)中调用我们的对话框

至此,我们完成了简易版CmdApproxCCSurface的开发,如下:
PersonalReverse工作台


5. 脚本生成

c++脚本:GenFreeCADTaskClass

该脚本的输入参数为:NameSpace(这里是PersonalReverseGui)和DefaultClassName(这里是ApproxSingleSurface),调用该脚本后会生成以下三个文件:
TaskApproxSingleSurface.h
TaskApproxSingleSurface.cpp
TaskApproxSingleSurface.ui
你仍需要做的事情:
1.将文件拷贝到正确的目录
2.调用uic命令生成ui_TaskApproxSingleSurface.h文件
3.在CMakeLists.txt中添加该类


6.总结

完成简易版CmdApproxCCSurface的开发后,我们将初步探索App模块。App模块和Gui模块使得程序的算法实现和现实分离,那么你可能会好奇:这两块是怎么联系起来的呢?
你可能会注意到,在第1小节的外部模块加载中,我们不仅修改了Gui项目(PersonalReverseGui)下面的文件,还对App项目(PersonalReverse)下的文件进行了修改,这是因为,Gui模块会调用相应App模块中的算法,我们在Gui中导入了Mesh等外部模块,也要相应的在App中进行修改,这样才能完整的加载某一模块。
下一章节,我们将会开发进阶版CmdApproxCCSurface,该命令将会调用PersonalReverse中的命令,并进行参数的传递:从Gui传参给App模块,并接受App模块的返回值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骨骼建模师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值