如何从Qt插件中使用宿主应用程序的类

How to use the classes of the host application from a Qt plugin?

本文关键字:宿主 应用程序 Qt 插件      更新时间:2023-10-16

我通过创建Qt c++插件来扩展我的应用程序的功能来链接问题。代码编译和一切工作,但只有当我使用Qt库类,如QString为例。当我从宿主应用程序中定义的类中给插件类一个对象的引用时,项目不再链接。创建插件时,我遵循Qt文档中的步骤,并考虑到给出的示例——echo和plug&paint。但是,这里没有涉及这种情况。


更新

错误如下:

并且。obj:-1:错误:LNK2019:未解析的外部符号"public: class QString __cdecl myClass::answer(void)const " (?answer@myClass@@QEBA?AVQString@@XZ)在函数中引用"public: virtual class QString __cdecl myPlugin::echo(class myClass *)"(? echo@myPlugin@@UEAA ? AVQString@@PEAVmyClass@@@Z)

这是导致它的项目:

plugtest.pro

TEMPLATE = subdirs
SUBDIRS += 
    host 
    plugin

host.pro

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = host
TEMPLATE = app

SOURCES += main.cpp
        MainWindow.cpp 
    myClass.cpp
HEADERS  += MainWindow.h 
    myClass.h 
    plugInterface.h
FORMS    += MainWindow.ui

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMessageBox>
#include <QPluginLoader>
#include <QDir>
#include "myClass.h"
#include "plugInterface.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void on_button_clicked();
private:
    bool loadPlugin();
    Ui::MainWindow *ui;
    plugInterface *m_interface;
    myClass *m_class;
};
#endif // MAINWINDOW_H

myClass.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
class myClass : public QObject
{
    Q_OBJECT
public:
    explicit myClass(QObject *parent = 0);
    QString answer() const;
    void setAnswer(const QString &str);
private:
    QString m_answer;
};
#endif // MYCLASS_H

plugInterface.h

#ifndef PLUGINTERFACE_H
#define PLUGINTERFACE_H
#include <QString>
#include "myClass.h"
class plugInterface
{
public:
    virtual ~plugInterface() {}
    virtual QString echo(myClass *value) = 0;
};
#define PlugInterface_iid "example.suite.app.PluginInterface"
Q_DECLARE_INTERFACE(plugInterface, PlugInterface_iid)
#endif // PLUGINTERFACE_H

MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    if (!loadPlugin())
    {
        QMessageBox::information(this, "Error", "Could not load the plugin");
    }
    m_class = new myClass(this);
    m_class->setAnswer("Good!");
}
MainWindow::~MainWindow()
{
    delete ui;
}
bool MainWindow::loadPlugin()
  {
      QDir pluginsDir(qApp->applicationDirPath());
      if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
      pluginsDir.cd("plugins");
      foreach (QString fileName, pluginsDir.entryList(QDir::Files))
      {
          QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
          QObject *plugin = pluginLoader.instance();
          if (plugin) {
              m_interface = qobject_cast<plugInterface *>(plugin);
              if (m_interface)
                  return true;
          }
      }
      return false;
  }
void MainWindow::on_button_clicked()
{
    ui->lineResult->setText(m_interface->echo(m_class));
}

myClass.cpp

#include "myClass.h"
myClass::myClass(QObject *parent) : QObject(parent)
{
}
QString myClass::answer() const
{
    return m_answer;
}
void myClass::setAnswer(const QString &str)
{
    m_answer = str;
}

plugin.pro

  TEMPLATE        = lib
  CONFIG         += plugin
  QT             += widgets
  INCLUDEPATH    += ../host
  HEADERS         = myPlugin.h
  SOURCES         = myPlugin.cpp
  TARGET          = $$qtLibraryTarget(myPlugin)
  DESTDIR         = ../plugins

myPlugin.h

#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include <QObject>
#include "plugInterface.h"
class myPlugin : public QObject, plugInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "example.suite.app.PluginInterface")
    Q_INTERFACES(plugInterface)
public:
    QString echo(myClass *value) Q_DECL_OVERRIDE;
};
#endif // MYPLUGIN_H

myPlugin.cpp

#include "myPlugin.h"
QString myPlugin::echo(myClass *value)
{
    return value->answer();
}

对我来说有效的解决方案是使myClass成为库的一部分,并将其动态地包含在插件和主机中。但是,我很好奇这是否可以在不创建库的情况下完成。