如何在Qt中插件和主应用程序之间进行通信

How to communicate between plugin and main application in Qt?

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

我需要让我的绘图板应用程序及其几何图形插件(绘制矩形、圆形等)相互通信:当加载.so文件时,主应用程序将获得一个具体的工厂来实例化图形类和一个按钮(将在主应用程序中加载以表示此图形)。单击按钮时,应用程序可以绘制此图形。

我愚蠢地实现了这一点:

主应用程序具有识别客户端选择的图形的QString。 我在工厂中存储了一个指向此 QString 的QString *point,并编写如下代码:

QPushButton *CircleFactory::MyButton()
{
    QPushButton *drawCircleBut = new QPushButton;
    drawCircleBut->setIcon(QIcon(":/shape/circle"));
    connect(drawCircleBut, SIGNAL(clicked()), this, SLOT(changeShape()));
    return drawCircleBut;
}
void CircleFactory::changeShape()
{
    *point = ID_LABEL;
}

我相信一定有更好的方法来解决这个问题......请给我一些建议或建议。

最简单的解决方案是利用QObject的属性系统:

QPushButton * CircleFactory::MyButton()
{
  QScopedPointer<QPushButton> button(new QPushButton);
  button->setIcon(QIcon(":/shape/circle"));
  button->setProperty("identity", ID_LABEL);
  return button->take();
}

然后,无论您连接到这些按钮的哪个插槽,您都可以轻松检查它们的身份;

void Foo::buttonClicked() {
  qDebug() << "clicked on:" << sender()->property("identity");
}

这样就可以避免对全局变量的需求。

我质疑按钮是否需要以这种方式标识自己。我担心的是,您正在使用按钮的身份,然后以某种方式引用回圆形对象或正确的插件。

相反,圆形工厂应该提供一个已经连接到正确插槽的按钮。如果这是不可能的,你必须进一步解释你的"绘图板应用程序"的设计和预期功能。正如您可能想象的那样,这样的应用程序应该如何工作还远非显而易见 - 对您来说显而易见的东西对其他人来说并不明显。

另一种解决方案是扩展您的几何图形插件接口,以便只有插件知道它们的形状是如何调用的,以及如果将其表示为QIcon,它的外观。应用程序本身对圆形或矩形一无所知。

#include <QString>
class GeometricPluginInterface
{
public:
   GeometricPluginInterface() {}
   virtual ~GeometricPluginInterface() {}
   virtual QString name() const = 0;
   virtual QIcon icon() const = 0;
};

在应用程序启动时,您可以将所有加载的插件存储在一个QList中(例如 QList<GeometricPluginInterface*> m_plugins;)。如果您用按钮填充您的 UI,您可以迭代列表并使用从插件本身获得的图标为每个插件创建一个QPushButton。您可以通过 lambda(自 C++11 起)将按钮的clicked信号连接到插槽,就像代码中一样。

foreach (GeometricPluginInterface *plugin, m_plugins) {
   QPushButton *button = new QPushButton;
   button->setIcon(plugin->icon());
   connect(button, &QPushButton::clicked,
           [this, plugin] {
      geometryButtonClicked(plugin->name());
   });
   ui->buttonLayout->addWidget(button);
}
void GeometricPluginInterface::geometryButtonClicked(const QString &geometryName)
{
   qDebug() << "Geometry clicked: " << geometryName;
}