QCad原始碼分析 第一章
阿新 • • 發佈:2018-12-07
鑑於介紹Qcad相關的文章很少,決定寫此部落格,一來便於日後查詢,二來要有分享精神。本文章基於Qcad3 .21.3.4的開源版本進行分析,分過程中難免有疏漏,如果有新的發現會及時更改,不足之處望高手指正,十分感謝。
QCad是一款2維的cad軟體,基於Qt類庫開發,邏輯處理方面夾雜著QtScript,所以首先要熟悉javascript,js相關文章不在贅述,其次QtScript的使用方面,詳細閱讀Qt官方文件Qt Script。
首先講一下QCad軟體中的簡單啟動過程,也就是程式碼中的main函式,QCad是一款跨平臺的軟體,暫時之講解window平臺的原始碼。
int main(int argc, char *argv[]) { qDebug() << "QCAD version " << R_QCAD_VERSION_STRING; // For correct Unicode translation, apply the current system locale: setlocale(LC_ALL, ""); // But use usual conversion for scanf()/sprintf(): setlocale(LC_NUMERIC, "C"); // Finetuning Japanese encoding for correct DXF/DWG import. // see http://qt-project.org/doc/qt-4.8/codecs-jis.html #ifdef Q_OS_WIN _putenv_s("UNICODEMAP_JP", "cp932"); #else setenv("UNICODEMAP_JP", "cp932", 1); #endif #ifdef Q_OS_WIN #if QT_VERSION >= 0x050200 // enable OpenGL logging under Windows // this info can then be shown in the about dialog QLoggingCategory::setFilterRules(QStringLiteral("qt.qpa.gl=true")); #endif #endif // Auto scale up user interface for high res displays under Windows: #ifdef Q_OS_WIN #if QT_VERSION >= 0x050600 //_putenv_s("QT_SCALE_FACTOR", "auto"); _putenv_s("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); #else _putenv_s("QT_DEVICE_PIXEL_RATIO", "auto"); #endif #endif #ifdef Q_OS_MAC // TODO: fix linking with objective c removeMacMenus(); #endif // these are defaults: //新增組織、公司、版本資訊 qApp->setOrganizationName("QCAD"); qApp->setOrganizationDomain("QCAD.org"); qApp->setApplicationName("QCAD"); qApp->setApplicationVersion(RSettings::getVersionString()); //除錯輸出重定義 RMainWindow::installMessageHandler(); #if QT_VERSION >= 0x050000 //高畫素比 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif #ifdef Q_OS_MAC // TODO: make available as script function: QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus); if (QSysInfo::MacintoshVersion>=0x000B) { // system font change bug fix on OS X 10.9 (Mavericks): QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); } #endif //產生隨機數 QTime time = QTime::currentTime(); qsrand((uint)time.msec()); //設定原始引數到RSettings當中 QStringList originalArguments; for (int i=0; i<argc; i++) { QString a = argv[i]; originalArguments.append(a); } RSettings::setOriginalArguments(originalArguments); //得到應用程式的id,用於一個終端只能啟用一個QCad程式 QString appId = "QCAD"; for (int i=0; i<argc; i++) { QString a = argv[i]; if (a=="-app-id" && i+1<argc) { appId = argv[i+1]; } } //是否啟用幫助介面 bool guiEnabled = true; for (int i=1; i<argc; i++) { if (!strcmp(argv[i], "-no-gui") || !strcmp(argv[i], "-help")) { //如果設定-no-gui或者-help引數,則不啟用介面 guiEnabled = false; } } //應用程式的派生類,派生主要用於一個終端只能啟用一個QCad程式中的本地服務通訊 RSingleApplication* app = new RSingleApplication(appId, argc, argv, guiEnabled); #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) // note that SIGPIPE is only ignored in release mode, gdb catches SIGPIPE // by default. To disable that behavior in gdb, use: // handle SIGPIPE nostop noprint pass signal(SIGPIPE,catchSigPipe); #endif #ifdef Q_OS_MAC // activate Mac OS X dock icon if desired: if (!app->arguments().contains("-no-dock-icon") && !app->arguments().contains("-help") && !app->arguments().contains("-h") && !app->arguments().contains("-version") && !app->arguments().contains("-v")) { ProcessSerialNumber psn; if (GetCurrentProcess(&psn) == noErr) { TransformProcessType(&psn, kProcessTransformToForegroundApplication); } } #endif if (!app->arguments().contains("-allow-multiple-instances")) { //如果程序不允許多例項 // send arguments to running instance for further processing: if (app->sendMessage(app->arguments().join("\n"), 30000)) { qWarning("Application already running. Aborting..."); return 0; } } #ifdef Q_OS_WIN // SVG icons are only rendered if this line is present under windows: QImageReader::supportedImageFormats(); // the SQLite plugin can only be loaded if this line is present under windows: QSqlDatabase::drivers(); #endif //註冊RColor型別到元物件系統 qRegisterMetaType<RColor>(); //將RColor註冊到流操縱當中去,RColor支援<<操作 qRegisterMetaTypeStreamOperators<RColor>("RColor"); //註冊RVector型別到元物件系統 qRegisterMetaType<RVector>(); //將RColor註冊到流操縱當中去,RVector支援<<操作 qRegisterMetaTypeStreamOperators<RVector>("RVector"); //獲取當前路徑 QString cwd = QDir::currentPath(); //設定釋出路徑 RSettings::setLaunchPath(cwd); // set current working directory: //將應用程式所在的目錄設為當前目錄 QDir::setCurrent(RSettings::getApplicationPath()); // disable Qt library paths to avoid plugins for Qt designer from being found: QStringList pluginPaths = RSettings::getPluginPaths(); if (pluginPaths.isEmpty()) { qWarning() << "No plugin paths found"; return -1; } //設定庫路徑,查詢dll時將在此目錄下查詢 app->setLibraryPaths(pluginPaths); //數學庫 RMath::init(); //載入字型 RFontList::init(); //載入填充圖形 RPatternListMetric::init(); RPatternListImperial::init(); // init object properties: //初始化物件屬性id RObject::init(); REntity::init(); RDocumentVariables::init(); RArcEntity::init(); RBlockReferenceEntity::init(); RCircleEntity::init(); RDimensionEntity::init(); RDimLinearEntity::init(); RDimAlignedEntity::init(); RDimAngularEntity::init(); RDimAngular2LEntity::init(); RDimAngular3PEntity::init(); RDimArcLengthEntity::init(); RDimDiametricEntity::init(); RDimOrdinateEntity::init(); RDimRadialEntity::init(); RDimRotatedEntity::init(); REllipseEntity::init(); RImageEntity::init(); RHatchEntity::init(); RLeaderEntity::init(); RLineEntity::init(); RPointEntity::init(); RPolylineEntity::init(); RSolidEntity::init(); RTraceEntity::init(); RFaceEntity::init(); RSplineEntity::init(); RXLineEntity::init(); RRayEntity::init(); RViewportEntity::init(); RTextBasedEntity::init(); RTextEntity::init(); RAttributeDefinitionEntity::init(); RAttributeEntity::init(); RUcs::init(); RLayer::init(); RLayout::init(); RLinetype::init(); RBlock::init(); RView::init(); // make sure plugins can find plugin related settings: // these are always stored in "QCAD3.ini/conf": //過載應用程式名稱【】 RSettings::setApplicationNameOverride("QCAD3"); //外掛管理類 RPluginLoader::loadPlugins(true); //初始化線型檔案 RLinetypeListMetric::init(); RLinetypeListImperial::init(); // check for autostart option: //檢查自動指令碼選項 QString autostartFile; //獲取引數列表,並從引數列表中查詢是否有啟動的指令碼檔案 QStringList arguments = app->arguments(); int i = arguments.indexOf("-autostart"); if (i!=-1 && arguments.count()>i+1) { autostartFile = arguments.at(i+1); } //將指令碼的工廠函式和指令碼型別註冊到系統當中,【jsfactory--js, pytonfactory--python】 RScriptHandlerRegistry::registerScriptHandler(RScriptHandlerEcma::factory, RScriptHandlerEcma::getSupportedFileExtensionsStatic()); //通過指令碼工廠【jsfactory】建立具體的指令碼類 RScriptHandler* handler = RScriptHandlerRegistry::getGlobalScriptHandler("js"); Q_ASSERT(handler!=NULL); //初始化自動指令碼程式【初始化過程中會建立主介面】 handler->init(autostartFile, arguments.mid(i+1)); //如果指令碼初始化過程中出現異常,則返回 int ret = 0; if (handler->hasUncaughtExceptions()) { ret = 1; } // delete script handler and print uncaught exceptions: //刪除指令碼控制代碼,列印異常 delete handler; RPluginLoader::unloadPlugins(); RSettings::uninit(); RFontList::uninit(); RPatternListMetric::uninit(); RPatternListImperial::uninit(); RSingleton::cleanUp(); RMath::uninit(); RDocumentInterface::deleteClipboard(); //RDebug::printCounters(); return ret; }