ctk框架搭建(五) 插件自动加载与插件依赖

     前面几章实现了一个很简单的项目结构:控制台生成主窗体,窗体点击弹出一个用户界面。姑且厚着脸皮谈一下框架优化,假设这个项目有N个用户,假设N接近无穷,每次增加用户都要对主窗体进行改动是不友好的;假设我们还要对某些用户进行删除,从代码里,逐一排查插件代码容易发生遗漏。架构中经常使用的方法就是自动加载,本章介绍怎么将原来的项目用自动化方式加载插件。

插件自动加载

    本项目所有生成插件都在plugins目录下,因此启用的自动化加载是简单的遍历插件,在main函数中添加函数 :main.cpp

void loadPlugins(QString path, ctkPluginContext* context, QList<QSharedPointer<ctkPlugin> >* list)
{
   QDir dir(path);
   if(!dir.exists())
        return;
 
    QStringList filters;
    filters << "*.dylib";
    QDirIterator dir_iterator(path, filters,  QDir::Files | QDir::Writable,
                              QDirIterator::Subdirectories);
 
    while (dir_iterator.hasNext()) {
        dir_iterator.next();
        QFileInfo file = dir_iterator.fileInfo();
 
        QString file_path = file.absoluteFilePath();
        if(file_path.contains(".1"))//排除多余连接文件
            continue;
 
        qDebug() << file_path;
 
        QUrl url = QUrl::fromLocalFile(file_path);
 
        QSharedPointer<ctkPlugin> plugin;
        try
        {
            plugin = context->installPlugin(url);
        }catch(ctkPluginException e){
            qDebug() << e.message() << e.getType();
            return;
        }
        list->append(plugin);
    }
 
 
}
 

     插件间启用逻辑应该改为:主界面启动时,生成用户接口及界面元素。代码层实现应该是:界面插件生成->用户插件生成并向界面注册接口->界面插件生成接口并弹出。于是在MainWindow中注册监听事件:mainwindowplugin.h

class MainWindowPlugin : public QObject, public iMainWindow, public ctkEventHandler
{
    Q_OBJECT
    Q_INTERFACES(iMainWindow ctkEventHandler)
public:
    MainWindowPlugin(ctkPluginContext *context);
    virtual void popMainWindow();
protected:
    virtual void handleEvent(const ctkEvent& event);
……
};

mainwindowplugin.cpp

MainWindowPlugin::MainWindowPlugin(ctkPluginContext *context)
    :m_context(context)
{
    m_windowDlg = new MainWindowDlg(context);
    ctkDictionary dic;
    dic.insert(ctkEventConstants::EVENT_TOPIC, "event/registAction");
    context->registerService<ctkEventHandler>(this, dic);
}
 

这样它既向外提供了接口调用,又在监听事件,一个插件可注册多种服务。

用户插件在生成时,就向MainWindow发起注册,包括接口信息和约定好的触发事件等参数信息:client1plugin.cpp

void Client1Plugin::registToMainWindow()
{
    ctkServiceReference ref;
    ctkEventAdmin* eventAdmin;
    ref = m_context->getServiceReference<ctkEventAdmin>();
    if(ref)
    {
        eventAdmin = m_context->getService<ctkEventAdmin>(ref);
        m_context->ungetService(ref);
    }
    ctkDictionary message;
    message.insert("id", "00");
    message.insert("name", "用户1");
    message.insert("topic","zhimakaimen");
    if(eventAdmin)
        eventAdmin->postEvent(ctkEvent("event/registAction", message));
}


MainWindow中响应函数如下:mainwindowplugin.cpp

void MainWindowPlugin::onRegistAction(const ctkEvent& event)
{
    QString name, id, topic;
    name = event.getProperty("name").toString();
    id = event.getProperty("id").toString();
    topic = event.getProperty("topic").toString();
    m_windowDlg->registAction(id, name, topic);
}

mainwindowdlg.cpp

void MainWindowDlg::registAction(QString id, QString name, QString topic)
{
    QAction* action = new QAction(name);
    action->setObjectName(id);
    action->setStatusTip(topic);
    ui->menubar->addAction(action);
    connect(action, SIGNAL(triggered(bool)), this, SLOT(action_clicked()));
}

当界面点击接口点击时,自动生成事件并发送:mainwindowdlg.cpp

void MainWindowDlg::action_clicked()
{
    if(QAction* action = dynamic_cast<QAction*>(sender()))
    {
        //获取事件服务接口
        ctkServiceReference ref;
        ctkEventAdmin* eventAdmin;
        QString topic = action->statusTip();
        ref = m_context->getServiceReference<ctkEventAdmin>();
        if(ref)
        {
            eventAdmin = m_context->getService<ctkEventAdmin>(ref);
            m_context->ungetService(ref);
        }
        //发送事件
        ctkDictionary message;
        if(eventAdmin)
            eventAdmin->postEvent(ctkEvent(topic, message));
    }
}

以上我们不用指定是那个插件需要加载,又是哪个事件需要触发,只要插件在plugins下成功生成,后面的逻辑由代码子自动完成

插件依赖

插件加载时一般根据首字母大小自动加载,所以在Client1启用时,MainWindow还没有被调用,所以发送的"event/registAction"事件没有接收方,这样就要考虑到插件依赖关系,在MANIFEST.MF中添加依赖:

Plugin-SymbolicName:Client1
Plugin-Version:1.0.0
Require-Plugin:MainWindow

这样就向框架申明了,该插件加载时需要先加载MainWindow插件,所有用户插件都应该有这样一份申明

 小结

    ctk框架搭建系列现在告一段落,所有代码已上传至https://github.com/Iyme/ctkExample。博主内心几乎是崩溃的,因为折腾了一番功夫,似乎也没有看到切实的架构应用场景,所以框架套用应该考虑自身项目是否有这个需求,如果代码量较少强行套框架显得有点得不偿失。

    欢迎留言交流,感谢每一个为文章增加点击量的人,也感谢一开始给我很大鼓励的小爬虫。

    PS:有朋友说文章排版有问题,我在Safari上没发现问题,最近用Chrome重新登录了下,排版吓哭我。难怪后面几章点击这么少,乱的跟盗版一样能看下去的都是真爱。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值