Qt项目开发遇到的问题4:在主程序中加载dll并显示出来,以及一些布局问题

先说一下布局的方式,一般来说不可能只添加一个dll,所以我们想办法将dll都显示出来的同时还可以美观方便;这里我的思路是用stackwidget将每个

dll都放在一个page中,添加一个dll创建相应的按钮,并将按钮绑定到相应的page中:

//初始显示第0页
    ui->stackedWidget->setCurrentIndex(0);

//这样可以让每次点击的时候都显示在第一页上

然后我们创建一个按钮:

先说明一下,mdlg是上一篇提到的,创建的一个  modulesmanager   class

/模块加载配置对话框初始化
    mdlg = NULL;
    //读取配置文件,需要加载哪些模块,已经模块的存放路径都存储于该文件中
    LoadModulesFromCfg();
    //信号槽匿名函数:创建并显示模块加载配置对话框
    connect(ui->toolButton,&QToolButton::clicked,[=](){

        if(mdlg == NULL)//当模块加载配置对话框未创建时,创建并建立信号槽机制
        {
            mdlg = new ModulesManager(this);
            void(ModulesManager::*sig)(QString) = &ModulesManager::sigReLoadModule;
            void(MainWindow::*slot)(QString) = &MainWindow::slotReloadModule;
            connect(mdlg,sig,this,slot);//信号槽:当模块加载配置对话框发送重载信号时,主界面重载所有模块组件
            //信号槽:当主界面发送刷新列表信号时,模块加载配置对话框刷新模块列表
            connect(this,&MainWindow::sigRefreshTable,mdlg,&ModulesManager::slotRefressTableWidget);
        }
        mdlg->show();
    });

来了来了他来了,添加删除的内容来了:

//模块加载
void MainWindow::slotReloadModule(QString path)
{
    //加载模块
    LoadModule(path);
    //发送刷新信号
    emit sigRefreshTable();
}

//卸载模块
void MainWindow::UnloadModule(QString &path)
{
    if(m_mapModules.find(path) != m_mapModules.end())
    {
        QMap<QString,QWidget*>::iterator itr = m_mapModulesWidget.find(path);
        if(itr != m_mapModulesWidget.end())
        {
            itr.value()->setAttribute(Qt::WA_DeleteOnClose);
            itr.value()->close();

            m_mapModulesWidget.remove(path);

        }
        QMap<QString,QAction*>::iterator itr2 = m_mapModulesActions.find(path);
        if(itr2 != m_mapModulesActions.end())
        {
            ui->toolButton_5->removeAction(itr2.value());
            m_mapModulesActions.remove(path);

        }

        if(m_mapModules[path]->unload())
        {
            m_mapModules.remove(path);

        }

    }

}

//添加模块
int btnar = 1;
QString MainWindow::LoadModule(QString &path)
{
    QIcon* icon = NULL;
    QString* text = NULL;
    //若该模块已加载,则先卸载
    UnloadModule(path);

    //动态加载共享库模块
    QLibrary *lib = new QLibrary(path);
    if(lib->load())
    {
        //将该模块储于模块列表
        m_mapModules[path]= lib;

        // 解析符号
        typedef QWidget* (*CreateFunc)(QWidget*);
        CreateFunc createDog = (CreateFunc)lib->resolve("CreateWidget");

        int a1=btnar;
        QWidget *pa;
        switch (a1)
        {
        case 1:
            pa=ui->page;
            break;
        case 2:
            pa=ui->page_2;
            break;
        case 3:
            pa=ui->page_3;
            break;
        case 4:
            pa=ui->page_4;
            break;
        case 5:
            pa=ui->page_5;
            break;
        case 6:
            pa=ui->page_6;
            break;
        case 7:
            pa=ui->page_7;
            break;
        case 8:
            pa=ui->page_8;
            break;
        case 9:
            pa=ui->page_9;
            break;
        case 10:
            pa=ui->page_10;
            break;
        case 11:
            pa=ui->page_11;
            break;
        default:
            pa=ui->page_12;
            break;
        }

        if(createDog != NULL)
        {

            IModules* module = dynamic_cast<IModules*>(createDog(pa));

            if (module)
            {
                icon = module->GetModuleIcon();
                text = module->GetModuleText();
                UDPSocket *udp = new UDPSocket();
                module->setSysCtrl(udp);
            }
        }
    }
    else
    {
        qDebug() << lib->errorString();
        return "";
    }


    //添加启动按钮*icon,*text,this
    QToolButton *btn = new QToolButton(this);
    btn->setText(*text);
    btn->setIcon(*icon);
    btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    btn->resize(150,80);//按钮大小
    btn->setIconSize(QSize(100,50));

    //  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    if(btnar<=6)
    {
        btn->move(btnar*150,80);//位置
    }
    else
    {
        btn->move((btnar-6)*200,160);//位置
    }
    btn->setStyleSheet("QToolButton{font-family:'幼圆';font-size:20px;color:rgb(115,45,0);}");
    btn->setAutoRaise(true);//透明


    //链接到每个page中。
    int a=btnar;
    ui->stackedWidget->setCurrentIndex(0);//指定index0为初始界面
    connect(btn,&QPushButton::clicked,[=](){
        ui->stackedWidget->setCurrentIndex(a-1);
    });

    btnar++;


    //信号槽:点击主界面启动按钮时,创建该模块的显示界面
    connect(btn,&QPushButton::clicked,[=](){
        //m_mapModulesWidget  该map用于存储已经创建了界面的“模块路径-模块显示界面”
        QMap<QString,QWidget*>::iterator itr = m_mapModulesWidget.find(path);//查找该模块显示界面是否被创建
        if(itr != m_mapModulesWidget.end())//若该模块已经被创建,则无需创建,直接显示
        {
            itr.value()->show();
        }
        else    //若该模块未创建,则需要创建该显示界面
        {
            if(m_mapModules[path]!=NULL)
            {
                QLibrary* lib = m_mapModules[path];//在模块共享库map中取出该共享库调用实例
                typedef QWidget* (*CreateFunc)(QWidget*);
                CreateFunc createDog = (CreateFunc)lib->resolve("CreateWidget");
                if (createDog) {//创建并记录该共享库的“模块路径-模块显示界面”
                    //pa指针指向page,以此将库内容显示到page上
                    QWidget *pa;
                    switch (a)
                    {
                    case 1:
                        pa=ui->page;
                        break;
                    case 2:
                        pa=ui->page_2;
                        break;
                    case 3:
                        pa=ui->page_3;
                        break;
                    case 4:
                        pa=ui->page_4;
                        break;
                    case 5:
                        pa=ui->page_5;
                        break;
                    case 6:
                        pa=ui->page_6;
                        break;
                    case 7:
                        pa=ui->page_7;
                        break;
                    case 8:
                        pa=ui->page_8;
                        break;
                    case 9:
                        pa=ui->page_9;
                        break;
                    case 10:
                        pa=ui->page_10;
                        break;
                    case 11:
                        pa=ui->page_11;
                        break;
                    default:
                        pa=ui->page_12;
                        break;
                    }
                    mWidget = createDog(pa);

                    mWidget->show();

                    m_mapModulesWidget[path]= mWidget;

                } else {//若未实现该接口,则卸载该共享库模块
                    lib->unload();
                }

            }
            else
            {
                qDebug() << lib->errorString();
            }
        }
    });
    //释放资源图片、文字资源
    if(icon != NULL)
    {
        delete icon;
    }
    if(text != NULL)
    {
        delete text;

    }

    //返回模块的名称
    return btn->text();
}




void MainWindow::LoadModulesFromCfg()
{
    //配置文件存放位置为运行目录跟目录下
    QString pathFile =  QCoreApplication::applicationDirPath() + "/Config.ini";
    QSettings *configIniRead = new QSettings(pathFile, QSettings::IniFormat);
    //将读取到的ini文件保存在QString中,先取值,然后通过toString()函数转换成QString类型
    configIniRead->setIniCodec("UTF8");
    int count = configIniRead->value("num/count").toInt();//读取num下count的值,表示总共需要加载的模块数量
    for (int i = 0; i < count ; i++) {
        //读取模块i共享库的存放路径
        QString str = QString("module%1/path").arg(i+1);
        QString modulePath = configIniRead->value(str).toString();
        //按照存放路径加载共享库
        QString moduleName = LoadModule(modulePath);

        //如果共享库是新添加的,记录该模块的模块名称
        if(moduleName!= "")
        {
            QSettings *configIniWrite = new QSettings(pathFile,QSettings::IniFormat);
            configIniWrite->setIniCodec("UTF8");
            QString str = QString("module%1/name").arg(i+1);
            configIniWrite->setValue(str,moduleName);
            if(configIniWrite != NULL)
                delete configIniWrite;
        }
    }

    //读入入完成后删除指针
    delete configIniRead;
}

其中几个注意点,添加用到了dll中的函数,通过接口调用相关功能,加载dll的图标、路径、名字。

分配dll到相应的page中,这里没有动态创建page,而是采用了先创建12个page,如果有更好的方法欢迎补充。

 

这一篇先到这里吧,之后再介绍相关dll的功能和方法。

posted @ 2020-08-15 15:46  邱丑丑  阅读(432)  评论(0)    收藏  举报