應用程序插件框架的內容包括:主程序App,插件Plugin。
1、實現一個應用程序插架框架關鍵點有:
一個插件的標准接口,在主程序中存在一個插件的集合。主程序通過循環讀取每個插件,將插件對象通過多態的機制轉換為插件接口,實現插件的裝載。
主程序對象或者主程序接口需要作為參數傳遞到插件對象中,以方便插件對象調用主程序的內容,如主視圖、工具欄、樹視圖、狀態欄等。
2、開源點雲處理軟件CloudCompare也是一個插件框架,因此也必然包括這些內容。
插件接口:ccPluginInterface,每個插件對象有在ccPluginInterface基礎上定義了一個新的接口類class ccStdPluginInterface : public ccPluginInterface
具體的插件則繼承自ccStdPluginInterface 累,比如這樣,class qMyPlugin : public QObject, public ccStdPluginInterface
主程序對象:class ccMainAppInterface,MainWindow主窗體類實現了ccMainAppInterface接口。
MainWindow::loadPlugins()方法負責插件的調用。(mainwindow.cpp文件中)
1 void MainWindow::loadPlugins() 2 { 3 menuPlugins->setEnabled(false); 4 menuShadersAndFilters->setEnabled(false); 5 toolBarPluginTools->setVisible(false); 6 toolBarGLFilters->setVisible(false); 7 8 //"static" plugins 9 foreach (QObject *plugin, QPluginLoader::staticInstances()) 10 dispatchPlugin(plugin); 11 12 ccConsole::Print(QString("Application path: ")+QCoreApplication::applicationDirPath()); 13 14 #if defined(Q_OS_MAC) 15 // plugins are in the bundle 16 QString path = QCoreApplication::applicationDirPath(); 17 path.remove( "MacOS" ); 18 m_pluginsPath = path + "Plugins/ccPlugins"; 19 #else 20 //plugins are in bin/plugins 21 m_pluginsPath = QCoreApplication::applicationDirPath()+QString("/plugins"); 22 #endif 23 24 ccConsole::Print(QString("Plugins lookup dir.: %1").arg(m_pluginsPath)); 25 26 QStringList filters; 27 #if defined(Q_OS_WIN) 28 filters << "*.dll"; 29 #elif defined(Q_OS_LINUX) 30 filters << "*.so"; 31 #elif defined(Q_OS_MAC) 32 filters << "*.dylib"; 33 #endif 34 QDir pluginsDir(m_pluginsPath); 35 pluginsDir.setNameFilters(filters); 36 foreach (QString filename, pluginsDir.entryList(filters)) 37 { 38 QPluginLoader loader(pluginsDir.absoluteFilePath(filename)); 39 QObject* plugin = loader.instance(); 40 if (plugin) 41 { 42 ccConsole::Print(QString("Found new plugin: '%1'").arg(filename)); 43 if (dispatchPlugin(plugin)) 44 { 45 m_pluginFileNames += filename; 46 } 47 else 48 { 49 delete plugin; 50 plugin = 0; 51 ccConsole::Warning("\tUnsupported or invalid plugin type"); 52 } 53 } 54 else 55 { 56 delete plugin; 57 plugin = 0; 58 ccConsole::Warning(QString("[Plugin] %1")/*.arg(pluginsDir.absoluteFilePath(filename))*/.arg(loader.errorString())); 59 } 60 } 61 62 if (menuPlugins) 63 { 64 menuPlugins->setEnabled(!m_stdPlugins.empty()); 65 } 66 67 if (toolBarPluginTools->isEnabled()) 68 { 69 actionDisplayPluginTools->setEnabled(true); 70 actionDisplayPluginTools->setChecked(true); 71 } 72 else 73 { 74 //DGM: doesn't work :( 75 //actionDisplayPluginTools->setChecked(false); 76 } 77 78 if (toolBarGLFilters->isEnabled()) 79 { 80 actionDisplayGLFiltersTools->setEnabled(true); 81 actionDisplayGLFiltersTools->setChecked(true); 82 } 83 else 84 { 85 //DGM: doesn't work :( 86 //actionDisplayGLFiltersTools->setChecked(false); 87 } 88 }
主程序在加載插件時會調用插件的setMainAppInterface方法,將主程序參數傳入,這樣插件就可以獲取主程序的內容了。
1 //! Sets application entry point 2 /** Called just after plugin creation by qCC 3 **/ 4 virtual void setMainAppInterface(ccMainAppInterface* app);
3、獲取主窗體中的點雲圖層
在doAction中的代碼:
1 const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); 2 size_t selNum = selectedEntities.size(); 3 if (selNum!=1) 4 { 5 m_app->dispToConsole("Select only one cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); 6 return; 7 } 8 9 ccHObject* ent = selectedEntities[0]; 10 assert(ent); 11 if (!ent || !ent->isA(CC_TYPES::POINT_CLOUD)) 12 { 13 m_app->dispToConsole("Select a real point cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); 14 return; 15 } 16 17 ccPointCloud* pc = static_cast<ccPointCloud*>(ent); 18 19 //input cloud 20 unsigned count = pc->size(); 21 bool hasNorms = pc->hasNormals(); 22 CCVector3 bbMin, bbMax; 23 pc->getBoundingBox(bbMin,bbMax); 24 const CCVector3d& globalShift = pc->getGlobalShift(); 25 double globalScale = pc->getGlobalScale();