如何在不从 QObject 派生的情况下使用 SIGNAL 和 SLOT?

发布于 2024-12-05 21:57:04 字数 1181 浏览 3 评论 0原文

或其他方式来表达我的问题(虽然它没有解决我的问题): 'QObject::QObject' 无法访问在类 'QObject' 中声明的私有成员

我需要类中的 SIGNAL 和 SLOTS 功能,但我认为如果不从其派生,这是不可能的QObject

class MyClass
{
signals:
   importantSignal();
public slots:
   importantSlot();
};

问题似乎是我需要从 QObject 派生来使用信号和插槽......但我需要 MyClass 的默认构造函数。但由于 QObject 的以下功能,我无法构造它们: 没有复制构造函数或赋值运算符

我尝试了很多......

所以我的应该类看起来像这样:

#include <QObject>
class MyClass: public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0); //autogenerated by qtcreator for QObject derived class
    MyClass(const MyClass * other);

signals:
    importantSignal();
public slots:
    importantSlot();
};

我需要 MyClass 的默认构造函数。

那么是否有可能避免“'QObject::QObject'无法访问类'QObject'中声明的私有成员”错误?

或者作为替代方案,是否有可能在没有 QObject 的情况下使用信号和槽?

我很高兴收到任何建议。

OR other way to formulate my question (though it didn't solve my problem): 'QObject::QObject' cannot access private member declared in class 'QObject'

I need SIGNALs and SLOTS functionality in my class, but I assume it is not possible without to derive from QObject?

class MyClass
{
signals:
   importantSignal();
public slots:
   importantSlot();
};

The Problem seems to be that I need to derive from QObject to use signals and slots ... but I need the default contructor of MyClass. But I can't construct them because of the following feature of QObject:
No Copy Constructor or Assignment Operator.

I tried a lot ...

So my shoul Class look like that:

#include <QObject>
class MyClass: public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0); //autogenerated by qtcreator for QObject derived class
    MyClass(const MyClass * other);

signals:
    importantSignal();
public slots:
    importantSlot();
};

I need the default contructor of MyClass.

So is there any possibility do avoid the "'QObject::QObject' cannot access private member declared in class 'QObject'" error?

Or as an alternative is there any possibility to use signals and slots without QObject?

I'm glad for any advice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

月棠 2024-12-12 21:57:04

如果您想要一个具有 QObject 功能的可复制对象,您需要成员资格(通过指针)而不是继承。

您可以从 QObject 派生类 Handler,其中 Handler 的插槽调用其父级上的 SomeInterface 虚拟函数。

struct NonQObjectHandler {
    virtual ~ NonQObjectHandler () {}
    virtual void receive (int, float) = 0;
};

class Handler : public NonQObjectHandler {
    struct Receiver;
    std :: unique_ptr <Receiver> m_receiver;
    void receive (int, float); // NonQObjectHandler
public:
    Handler ();
    Handler (const Handler &); // This is what you're really after
};

class Handler :: Receiver : public QObject {
Q_OBJECT
private:
    NonQObjectHandler * m_handler;
private slots:
    void receive (int, float); // Calls m_handler's receive
public:
    Receiver (NonQObjectHandler *);
};

Handler :: Handler ()
: m_receiver (new Receiver (this))
{
}

Handler :: Handler (const Handler & old)
: m_receiver (new Receiver (this))
{
    // Copy over any extra state variables also, but
    // Receiver is created anew.
}

Handler :: Receiver :: Receiver (NonQObjectHandler * h)
: m_handler (h)
{
    connect (foo, SIGNAL (bar (int, float)), this, SLOT (receive (int, float)));
}

void Handler :: Receiver :: receive (int i, float f)
{
    m_handler -> receive (i, f);
}

If you want a copyable object with QObject features you need membership (by pointer) rather than inheritence.

You can derive a class Handler from QObject where Handler's slots call SomeInterface virtual functions on its parent.

struct NonQObjectHandler {
    virtual ~ NonQObjectHandler () {}
    virtual void receive (int, float) = 0;
};

class Handler : public NonQObjectHandler {
    struct Receiver;
    std :: unique_ptr <Receiver> m_receiver;
    void receive (int, float); // NonQObjectHandler
public:
    Handler ();
    Handler (const Handler &); // This is what you're really after
};

class Handler :: Receiver : public QObject {
Q_OBJECT
private:
    NonQObjectHandler * m_handler;
private slots:
    void receive (int, float); // Calls m_handler's receive
public:
    Receiver (NonQObjectHandler *);
};

Handler :: Handler ()
: m_receiver (new Receiver (this))
{
}

Handler :: Handler (const Handler & old)
: m_receiver (new Receiver (this))
{
    // Copy over any extra state variables also, but
    // Receiver is created anew.
}

Handler :: Receiver :: Receiver (NonQObjectHandler * h)
: m_handler (h)
{
    connect (foo, SIGNAL (bar (int, float)), this, SLOT (receive (int, float)));
}

void Handler :: Receiver :: receive (int i, float f)
{
    m_handler -> receive (i, f);
}
画尸师 2024-12-12 21:57:04

如果您想使用信号/槽模式实现事件驱动功能,但不想在 Qt 的范围内工作(即您想在需要复制构造函数的 STL 容器等内部使用您的类),我建议使用 Boost::signal

否则,不,如果不从 QObject 派生,您就不可能做您想做的事情,因为该基类是处理 Qt 运行时信号/槽功能的。

If you want to implement event-driven functionality using a signals/slots pattern, but do not want to work inside the confines of Qt (i.e., you want to use your class inside of STL containers, etc. that require copy-constructors), I would suggest using Boost::signal.

Otherwise, no, you can't possibly do what you're wanting without deriving from QObject since that base class is what handles the Qt runtime signals/slots functionality.

美人迟暮 2024-12-12 21:57:04

如果不使用QObject/Q_OBJECT,则无法使用Qt 的信号/槽机制。

理论上,您可以创建一个虚拟 QObject 并将其组合到您的类中。然后,虚拟人会将插槽调用转发到您的班级。由于 Liz 在她的评论中描述的原因,您可能会遇到生命周期管理问题。

You cannot use Qt's signal/slot mechanisms without using QObject/Q_OBJECT.

You theoretically could create a dummy QObject and compose it into your class. The dummy would then forward the slot calls to your class. You will probably run in to issues with lifetime management, for the reasons that Liz has described in her comment.

为人所爱 2024-12-12 21:57:04

从 Qt5 开始你可以连接到任何函数

connect(&timer, &QTimer::finished,
        &instanceOfMyClass, &MyClass::fancyMemberFunction);

Since Qt5 you can just connect to any function

connect(&timer, &QTimer::finished,
        &instanceOfMyClass, &MyClass::fancyMemberFunction);
尐籹人 2024-12-12 21:57:04

在 Qt5 中,您使用 QObject::connectsignalslot 连接:

/*
   QMetaObject::Connection QObject::connect(
    const QObject *sender,
    const char *signal,
    const char *method,
    Qt::ConnectionType type = Qt::AutoConnection) const;
 */

#include <QApplication>
#include <QDebug>
#include <QLineEdit>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QLineEdit lnedit;

    // connect signal `QLineEdit::textChanged` with slot `lambda function`
    QObject::connect(&lnedit, &QLineEdit::textChanged, [&](){qDebug()<<lnedit.text()<<endl;});

    lnedit.show();
    return app.exec();
}

结果:

在此处输入图像描述

In Qt5, you use QObject::connect to connect signal with slot:

/*
   QMetaObject::Connection QObject::connect(
    const QObject *sender,
    const char *signal,
    const char *method,
    Qt::ConnectionType type = Qt::AutoConnection) const;
 */

#include <QApplication>
#include <QDebug>
#include <QLineEdit>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QLineEdit lnedit;

    // connect signal `QLineEdit::textChanged` with slot `lambda function`
    QObject::connect(&lnedit, &QLineEdit::textChanged, [&](){qDebug()<<lnedit.text()<<endl;});

    lnedit.show();
    return app.exec();
}

The result:

enter image description here

◇流星雨 2024-12-12 21:57:04

仅仅因为 QObject 不可复制并不意味着您在复制或分配类等时必须复制它。具体来说,您需要做的就是将您的类与 QObject 的副本隔离和赋值运算符(因为它们已被删除)。

通常,您会将“可复制的不可复制的 QObject”分解为一个单独的类:

// main.cpp
#include <QObject>
#include <QVariant>

class CopyableQObject : public QObject
{
protected:
   explicit CopyableQObject(QObject* parent = nullptr) : QObject(parent) {}
   CopyableQObject(const CopyableQObject& other) { initFrom(other); }
   CopyableQObject(CopyableQObject&& other)      { initFrom(other); }
   CopyableQObject& operator=(const CopyableQObject& other)
   {
      return initFrom(other), *this;
   }
   CopyableQObject& operator=(CopyableQObject&& other)
   {
      return initFrom(other), *this;
   }
private:
   void initFrom(const CopyableQObject& other)
   {
      setParent(other.parent());
      setObjectName(other.objectName());
   }
   void initFrom(CopyableQObject& other)
   {
      initFrom(const_cast<const CopyableQObject&>(other));
      for (QObject* child : other.children())
         child->setParent( this );
      for (auto& name : other.dynamicPropertyNames())
         setProperty(name, other.property(name));
   }
};

您可以在 QObject 实例之间复制所需的任何属性。上面复制了父对象名称和对象名称。此外,当从另一个对象移动时,其子对象将被重新设置父级,并且动态属性名称也会被传输。

现在,CopyableQObject 适配器实现了所有允许派生类进行复制构造、复制分配、移动构造和移动分配的构造函数。

您的类需要做的就是从上面的适配器类派生:

class MyClass : public CopyableQObject
{
   Q_OBJECT
public:
   Q_SIGNAL void signal1();
   Q_SIGNAL void signal2();
};

我们可以测试它是否有效:

int main()
{
   int counter = 0;

   MyClass obj1;
   MyClass obj2;
   Q_SET_OBJECT_NAME(obj1);

   QObject::connect(&obj1, &MyClass::signal1, [&]{ counter += 0x1; });
   QObject::connect(&obj1, &MyClass::signal2, [&]{ counter += 0x10; });
   QObject::connect(&obj2, &MyClass::signal1, [&]{ counter += 0x100; });
   QObject::connect(&obj2, &MyClass::signal2, [&]{ counter += 0x1000; });

   Q_ASSERT(counter == 0);
   emit obj1.signal1();
   emit obj1.signal2();
   Q_ASSERT(counter == 0x11);

   QObject obj3(&obj1);
   Q_ASSERT(obj3.parent() == &obj1);
   const auto name1 = obj1.objectName();

   obj2 = std::move(obj1);

   Q_ASSERT(obj3.parent() == &obj2);
   Q_ASSERT(obj2.objectName() == name1);

   emit obj2.signal1();
   emit obj2.signal2();
   Q_ASSERT(counter == 0x1111);
}

#include "main.moc"

这就是完整的、可编译的示例。

Just because QObject is not copyable doesn't mean that you have to copy it when your class is copied, or assigned to, etc. Specifically, all you need to do is to insulate your class from QObject's copy and assignment operators (because they are deleted).

Typically, you'd factor out the "copyable non-copyable QObject" into a separate class:

// main.cpp
#include <QObject>
#include <QVariant>

class CopyableQObject : public QObject
{
protected:
   explicit CopyableQObject(QObject* parent = nullptr) : QObject(parent) {}
   CopyableQObject(const CopyableQObject& other) { initFrom(other); }
   CopyableQObject(CopyableQObject&& other)      { initFrom(other); }
   CopyableQObject& operator=(const CopyableQObject& other)
   {
      return initFrom(other), *this;
   }
   CopyableQObject& operator=(CopyableQObject&& other)
   {
      return initFrom(other), *this;
   }
private:
   void initFrom(const CopyableQObject& other)
   {
      setParent(other.parent());
      setObjectName(other.objectName());
   }
   void initFrom(CopyableQObject& other)
   {
      initFrom(const_cast<const CopyableQObject&>(other));
      for (QObject* child : other.children())
         child->setParent( this );
      for (auto& name : other.dynamicPropertyNames())
         setProperty(name, other.property(name));
   }
};

You can copy whatever attributes you desire between the QObject instances. Above, the parent and object name are copied. Furthermore, when moving from another object, its children are reparented, and dynamic property names are transferred as well.

Now the CopyableQObject adapter implements all the constructors that will allow derived classes to be copy-constructible, copy-assignable, move-constructible and move-assignable.

All your class needs to do is derive from the adapter class above:

class MyClass : public CopyableQObject
{
   Q_OBJECT
public:
   Q_SIGNAL void signal1();
   Q_SIGNAL void signal2();
};

We can test that it works:

int main()
{
   int counter = 0;

   MyClass obj1;
   MyClass obj2;
   Q_SET_OBJECT_NAME(obj1);

   QObject::connect(&obj1, &MyClass::signal1, [&]{ counter += 0x1; });
   QObject::connect(&obj1, &MyClass::signal2, [&]{ counter += 0x10; });
   QObject::connect(&obj2, &MyClass::signal1, [&]{ counter += 0x100; });
   QObject::connect(&obj2, &MyClass::signal2, [&]{ counter += 0x1000; });

   Q_ASSERT(counter == 0);
   emit obj1.signal1();
   emit obj1.signal2();
   Q_ASSERT(counter == 0x11);

   QObject obj3(&obj1);
   Q_ASSERT(obj3.parent() == &obj1);
   const auto name1 = obj1.objectName();

   obj2 = std::move(obj1);

   Q_ASSERT(obj3.parent() == &obj2);
   Q_ASSERT(obj2.objectName() == name1);

   emit obj2.signal1();
   emit obj2.signal2();
   Q_ASSERT(counter == 0x1111);
}

#include "main.moc"

This concludes the complete, compileable example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文