• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            eryar

            PipeCAD - Plant Piping Design Software.
            RvmTranslator - Translate AVEVA RVM to OBJ, glTF, etc.
            posts - 603, comments - 590, trackbacks - 0, articles - 0

            QCAD Plugin 開發

            Posted on 2018-06-21 23:28 eryar 閱讀(2660) 評論(0)  編輯 收藏 引用 所屬分類: 6.Others

            QCAD Plugin 開發

            eryar@163.com

            Abstract. QCAD是基于GPL協議的開源CAD軟件,核心功能基于Qt使用C++開發,界面及其交互使用Javascript腳本進行開發。QCAD官方推薦開發其Plugin的方式為使用Javascript腳本的方式,因為QCAD的菜單及其對應的功能全部由Javascript實現。程序有時也需要和C++直接通信,如在QCAD中使用OpenCASCADE。本文主要介紹如何來開發QCAD的插件Plugin,從而能夠對QCAD進行擴展,做一些定制化的功能開發。

            Key Words. QCAD Plugin, Javascript, C++, CAD, 3D

            1.Introduction

            QCAD是GPL協議的開源CAD軟件,主要使用Javascript腳本進行開發,也可使用C++開發。與AutoCAD的多種開發方式一樣,支持AutoLisp腳本,也支持ObjectArx使用C++進行開發。不過開源的程序可以進行源碼Debug,遇到問題可以自己動手解決。而AutoCAD是閉源的,如果是正版用戶可以咨詢開發廠家,不能追根溯源。對于想學習CAD的人來說,建議可以多看這種開源軟件,學習CAD的開發原理。

            本文主要介紹開源軟件QCAD的插件Plugin的開發方法。

            2.Javascript

            由于QCAD的菜單、交互都提供了Javascript的封裝,所以QCAD的大部分功能都是用Javascript腳本實現。使Javascript腳本對QCAD進行開發也是QCAD作者推薦的方式。

            https://www.qcad.org/doc/qcad/latest/developer/_script_scope.html

            QCAD程序框架提供了一很完整的強大的ECMAScript接口,QCAD幾乎所有的功能都可以通過腳本JavaScript來訪問。ECMAScript(JavaScript)是很流行且易于學習的一種腳本語言。通過使用JavaScript腳本來擴展QCAD是一種簡單高效的方式,擴展的功能包括交互創建、修改工具等等。

            wps_clip_image-21599

            用戶甚至可以基于QCAD的應用框架開發出一個全新的程序。全新的程序可能是一個控制臺工具或包含用戶交互的CAD程序:

            wps_clip_image-12615

            如下圖所示為QCAD中主要模塊的功能。Qt主要涉及通用的功能,與CAD沒有直接關系。QCAD程序框架QCAD Application Framework提供CAD專用功能,如CAD Core, DXF導入導出、強大的圖形視圖powerful graphics view等等。腳本ECMAScript可以用來快速的擴展CAD專用功能。QCAD用戶接口及所有的交互功能、幾乎所有的窗口都是通過腳本實現的。

            QCAD包中的qcad.exe就是一個ECMAScript解釋器,并且封裝了Qt和QCAD的接口。當沒有任何ECMAScript腳本的時候,運行qcad.exe將會什么也不做。Qcad.exe默認會查找“scripts/autostart.js”并執行。在QCAD中,autostart.js腳本初始化了所有的ECMAScript工具和用戶交互的功能,并啟動主程序。

            QCAD中幾乎所有的窗口、菜單、工具欄都是通過ECMAScript腳本實現。這些腳本位于scripts文件夾中。

            wps_clip_image-10035

            用JavaScript腳本開發QCAD插件最好辦法就是先在QCAD中創建菜單和工具欄。下面就給出在QCAD中創建菜單和工具欄的步驟。首先要創建文件結構:

            l 對于新的頂層菜單,在QCAD目錄中的scripts文件夾中創建一個新的文件夾。例如:創建一個“MyScripts”的文件夾;

            l 在MyScripts文件夾中創建一個文本文件“MyScripts.js”;

            l 在MyScripts文件夾中創建另外一個文件夾來提供一個命令Action,如命名為“MyAction”;

            l 在MyAction文件夾中創建一個文本文件MyAction.js,文件名必須和文件夾的名字一致;

            文件組織結構如下所示:

            wps_clip_image-11506

            將如下JavaScript腳本復制到MyScripts.js文件中:

            /**
             * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved.
             * 
             * This file is part of the QCAD project.
             *
             * QCAD is free software: you can redistribute it and/or modify
             * it under the terms of the GNU General Public License as published by
             * the Free Software Foundation, either version 3 of the License, or
             * (at your option) any later version.
             *
             * QCAD is distributed in the hope that it will be useful,
             * but WITHOUT ANY WARRANTY; without even the implied warranty of
             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
             * GNU General Public License for more details.
             *
             * You should have received a copy of the GNU General Public License
             * along with QCAD.
             */
            // MyScripts.js
            // All actions are derived from class EAction, so we need to 
            // include this class definition here:
            include("../EAction.js");
            // Constructor calls base class constructor:
            function MyScripts(guiAction) {
                EAction.call(this, guiAction);
            }
            // Derive class MyScripts from class EAction:
            MyScripts.prototype = new EAction();
            // This static function returns a new or existing QMenu object.
            MyScripts.getMenu = function() {
                // EAction.getMenu is a helper function that returns an existing 
                // or new QMenu object with the given title and object name.
                // The object name (here "MyScriptMenu") must be unique. 
                return EAction.getMenu(MyScripts.getTitle(), "MyScriptsMenu");
            };
            // This static function returns a new or existing QToolBar object.
            MyScripts.getToolBar = function() {
                // EAction.getToolBar is a helper function that returns an existing 
                // or new QToolBar object with the given title and object name.
                // The object name (here "MyScriptToolBar") must be unique. 
                return EAction.getToolBar(MyScripts.getTitle(), "MyScriptToolBar");
            };
            // This static function defines and returns the title of the menu 
            // and toolbar.
            // The qsTr function marks the title as a translatable string.
            MyScripts.getTitle = function() {
                return qsTr("My Scripts");
            };
            // Init creates the menu and toolbar on start.
            MyScripts.init = function() {
                MyScripts.getMenu();
                MyScripts.getToolBar();
            };

             

            將如下腳本代碼復制到MyAction.js文件中:

            /**
             * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved.
             * 
             * This file is part of the QCAD project.
             *
             * QCAD is free software: you can redistribute it and/or modify
             * it under the terms of the GNU General Public License as published by
             * the Free Software Foundation, either version 3 of the License, or
             * (at your option) any later version.
             *
             * QCAD is distributed in the hope that it will be useful,
             * but WITHOUT ANY WARRANTY; without even the implied warranty of
             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
             * GNU General Public License for more details.
             *
             * You should have received a copy of the GNU General Public License
             * along with QCAD.
             */
            // MyAction.js
            // Include base class definition:
            include("../MyScripts.js");
            // Constructor calls base class constructor:
            function MyAction(guiAction) {
                MyScripts.call(this, guiAction);
            }
            // Derive class MyAction from class MyScripts:
            MyAction.prototype = new MyScripts();
            // This function is called immediately after the constructor when the user 
            // starts this action. For actions that don't require any user input (for
            // example auto zoom), beginEvent does everything and then terminates the
            // action.
            MyAction.prototype.beginEvent = function() {
                // call base class implementation of beginEvent:
                MyScripts.prototype.beginEvent.call(this);
                // get main application window:
                var appWin = EAction.getMainWindow();
                // print a message in the console of QCAD:
                appWin.handleUserMessage("MyAction() is running...");
                // terminate this action immediately:
                this.terminate();
            };
            // MyAction.init() is called by QCAD to initialize the action and create
            // the menu / toolbar for it.
            MyAction.init = function(basePath) {
                // Create a new RGuiAction (extended QAction):
                var action = new RGuiAction("&My Action", RMainWindowQt.getMainWindow());
                // This action requires a document to be open. If no document is
                // open, the menu and tool button are grayed out:
                action.setRequiresDocument(true);
                // Define the script file that is executed when this action is
                // launched:
                action.setScriptFile(basePath + "/MyAction.js");
                // Set the icon that is shown in the toolbar and on some platforms
                // also in the menu:
                action.setIcon(basePath + "/MyAction.svg");
                // Set the command(s) that can be used on the command line to 
                // launch this action:
                action.setDefaultCommands(["myaction"]);
                // Define the sort order of this action. Menus and tool buttons are
                // ordered by these values:
                action.setGroupSortOrder(80100);
                action.setSortOrder(200);
                // Set list of widgets this action is added to
                // (menus, tool bars, CAD tool bar panels):
                action.setWidgetNames(["MyScriptsMenu"]);
            };

             

            啟動QCAD可以發現在菜單上有了MyScripts,如下圖所示:

            wps_clip_image-31967

            點擊MyAction菜單,會在命令窗口中輸出測試文字。

            3.C++

            既然QCAD的是基于Qt開發的,理所當然地應該支持C++開發,只是C++開發方式需要與JavaScript相結合。因為QCAD中一些交互功能封裝到JavaScript腳本中了,所以只能通過在JavaScript中調用C++。這種方式QCAD也提供了一個例子,位于源碼的

            support\examples\exampleplugin中。主要是將C++的類暴露給JavaScript,使在JavaScript中可以調用C++的類及其方法。只將頭文件源碼列出如下:RExamplePlugin.h

            #include <QDebug>
            #include <QObject>
            #include <QScriptEngine>
            #include <QStringList>
            #include "RActionAdapter.h"
            #include "RDocumentInterface.h"
            #include "RGuiAction.h"
            #include "RMainWindow.h"
            #include "RPluginInterface.h"
            class MyAction : public RActionAdapter {
            public:
                MyAction(RGuiAction* guiAction) : RActionAdapter(guiAction) {}
                static void factory(RGuiAction* guiAction) {
                    qDebug() << "MyAction::factory";
                    if (guiAction==NULL) {
                        qDebug("guiAction is NULL");
                        return;
                    }
                    RDocumentInterface* di = RMainWindow::getDocumentInterfaceStatic();
                    if (di==NULL) {
                        qDebug("di is NULL");
                        return;
                    }
                    di->setCurrentAction(new MyAction(guiAction));
                }
                virtual void beginEvent() {
                    qDebug() << "MyAction::beginEvent";
                }
            };
            class MyClass : public QObject {
            Q_OBJECT
            public:
                MyClass() : QObject(), i(0), d(0.0) {}
                virtual int getInt() const {
                    return i;
                }
                virtual double getDouble() const {
                    return d;
                }
                virtual QString getString() const {
                    return s;
                }
                virtual void setInt(int v) {
                    i = v;
                }
                virtual void setDouble(int v) {
                    d = v;
                }
                virtual void setString(const QString& v) {
                    s = v;
                }
                void emitSignal() {
                    emit mySignal(i);
                }
            signals:
                void mySignal(int code);
            private:
                int i;
                double d;
                QString s;
            };
            Q_DECLARE_METATYPE(MyClass*)
            /**
             * Script binding for MyClass.
             */
            class EcmaMyClass {
            public:
                static void initEcma(QScriptEngine& engine);
                static QScriptValue createMyClass(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue myClassToString(QScriptContext *context, QScriptEngine *engine);
                static MyClass* getSelfMyClass(const QString& fName, QScriptContext* context);
                static QScriptValue getInt(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue getDouble(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue getString(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue setInt(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue setDouble(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue setString(QScriptContext* context, QScriptEngine* engine);
                static QScriptValue emitSignal(QScriptContext* context, QScriptEngine* engine);
            };
            class RExamplePlugin : public QObject, public RPluginInterface
            {
                Q_OBJECT
                Q_INTERFACES(RPluginInterface)
            #if QT_VERSION >= 0x050000
                Q_PLUGIN_METADATA(IID "org.qcad.exampleplugin")
            #endif
            public:
                virtual bool init();
                virtual void uninit(bool) {}
                virtual void postInit(InitStatus status);
                virtual void initScriptExtensions(QScriptEngine& engine);
                virtual RPluginInfo getPluginInfo();
            };

             

            從上述源碼可以看出,通過Qt的Plguin機制將C++的類暴露給JavaScript,從而在JavaScript中使用C++的功能。如下圖所示為在QCAD中通過JavaScript調用C++來顯示一個三維視圖的窗口。

            wps_clip_image-25228

            4.Conclusion

            綜上所述,QCAD二次開發的方式主要是以JavaScript為主。如果要在QCAD中使用C++,或者是使用C++的第三方庫,只能是將相關的C++類暴露給JavaScirpt,這樣開發才是最簡單的。如果純用C++開發,一些交互功能是封裝在JavaScript中,反而效率不高。

            通過在QCAD中使用OpenCASCADE之類的三維幾何內核,可以實現一些建模、出圖的功能。

            5.References

            1. https://www.qcad.org/doc/qcad/latest/developer/_menus_and_tool_bars.html

            2. https://www.qcad.org/doc/qcad/latest/developer/index.html#what_is

            3. https://www.qcad.org/rsforum/viewforum.php?f=30&sid=8621b8249232845e54252ef7fa6b34ae

            4. JavaScript 高級程序設計

            5. C++ GUI Programming with Qt


            為了方便大家在移動端也能看到我的博文和討論交流,現已注冊微信公眾號,歡迎大家掃描下方二維碼關注。
            Shing Liu(eryar@163.com)

             

            无码人妻精品一区二区三区久久久| 性欧美大战久久久久久久久| 亚洲国产精品久久| 久久93精品国产91久久综合| 亚洲精品WWW久久久久久| 久久人人爽人人爽人人av东京热| 久久久久久亚洲Av无码精品专口| 大香网伊人久久综合网2020| 久久成人小视频| 久久精品国产99国产电影网| 久久国产成人亚洲精品影院| 日本人妻丰满熟妇久久久久久| 久久福利青草精品资源站| 亚洲人成网站999久久久综合 | 日韩电影久久久被窝网| 久久久久女人精品毛片| 日产精品久久久久久久| 天天久久狠狠色综合| 午夜欧美精品久久久久久久| 九九热久久免费视频| 久久综合丁香激情久久| 国内精品久久久久影院亚洲| 久久一区二区三区99| 久久精品国产清自在天天线| 国产∨亚洲V天堂无码久久久| 日韩久久久久中文字幕人妻| 国产91久久综合| 婷婷综合久久狠狠色99h| 99久久国产综合精品女同图片| 久久中文字幕视频、最近更新| 热久久这里只有精品| 国产精品毛片久久久久久久| 欧洲成人午夜精品无码区久久| 性做久久久久久久久老女人| 香蕉99久久国产综合精品宅男自| 91精品婷婷国产综合久久| 欧美精品一区二区精品久久| 亚洲国产二区三区久久| 国产精品九九久久精品女同亚洲欧美日韩综合区 | 亚洲日本久久久午夜精品| 久久97久久97精品免视看|