鉴于介绍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;
}