如何存储QPropertyChangeHandler的实例?

huangapple go评论76阅读模式
英文:

How to store an instance of QPropertyChangeHandler?

问题

QProperty::onValueChange() 返回一个 QPropertyChangeHandler 对象,我认为应该将它存储为成员变量,以便它不会被销毁,从而取消注册 Functor。

由于 QPropertyChangeHandler 是一个接受 Functor 的模板类,我需要提供我要使用的 Functor 类型,但我不确定应该放什么类型。

如何存储返回的 QPropertyChangeHandler 对象?


以下是到目前为止我最好的尝试:

Proptest.h

#ifndef PROP_TEST
#define PROP_TEST

#include <QObject>
#include <QProperty>
#include <QString>
#include <QPropertyChangeHandler>
#include <functional>

class PropTest : public QObject {
    Q_OBJECT

public:
    QProperty<QString> m_property;

    PropTest();
    ~PropTest() = default;

    QPropertyChangeHandler<std::function<void()>> propertyChangeHandler;

    void TestFunction();
};

#endif

Proptest.cpp

#include <QObject>
#include <QString>
#include <QDebug>
#include <QApplication>

#include "prop_test.h"

PropTest::PropTest() { // &lt;- error occurs here
    this->propertyChangeHandler = this->m_property.onValueChanged(&PropTest::TestFunction);
}

void PropTest::TestFunction() {
    // further processing
}

int main(int argc, char* argv[]) {

    auto app = QApplication(argc, argv);

    auto obj = new PropTest{};

    obj->m_property = "String";
    obj->m_property = "New";

    app.exec();
}

但是我得到了这个陌生的错误:

[build] prop_test.cpp: In constructor &#39;PropTest::PropTest()&#39;:
[build] prop_test.cpp:11:20: error: no matching function for call to &#39;QPropertyChangeHandler&lt;std::function&lt;void()&gt; &gt;::QPropertyChangeHandler()&#39;
[build]    11 | PropTest::PropTest() {
[build]       |                    ^

我觉得错误出现的地方很奇怪。

英文:

QProperty::onValueChange() returns a QPropertyChangeHandler object which I believe should be stored as a member variable so it will not be destroyed and consequently de-registering the Functor.

Since QPropertyChangeHandler is a Template class that takes a Functor, I need to provide the type of Functor that I am going to use but I am not sure what type to place there.

How should I store the returned QPropertyChangeHandler object?


The following are my best attempt so far:

Proptest.h

#ifndef PROP_TEST
#define PROP_TEST

#include &lt;QObject&gt;
#include &lt;QProperty&gt;
#include &lt;QString&gt;
#include &lt;QPropertyChangeHandler&gt;
#include &lt;functional&gt;

class PropTest : public QObject {
    Q_OBJECT

public:
    QProperty&lt;QString&gt; m_property;

    PropTest();
    ~PropTest() = default;

    // QString m_property;

    QPropertyChangeHandler&lt; std::function&lt;void()&gt; &gt; propertyChangeHandler;

    void TestFunction();
};

#endif

Proptest.cpp

#include &lt;QObject&gt;
#include &lt;QString&gt;
#include &lt;QDebug&gt;
#include &lt;QApplication&gt;

#include &quot;prop_test.h&quot;

PropTest::PropTest() { // &lt;- error occurs here
    this-&gt;propertyChangeHandler = this-&gt;m_property.onValueChanged(&amp;PropTest::TestFunction);
}

void PropTest::TestFunction() {
    // further processing
}

int main(int arc, char* argv[]) {

    auto app = QApplication(arc, argv);

    auto ob = new PropTest{};

    ob-&gt;m_property = &quot;String&quot;;
    ob-&gt;m_property = &quot;New&quot;;

    app.exec();
}

But all I got was this unfamiliar error:

[build] prop_test.cpp: In constructor &#39;PropTest::PropTest()&#39;:
[build] prop_test.cpp:11:20: error: no matching function for call to &#39;QPropertyChangeHandler&lt;std::function&lt;void()&gt; &gt;::QPropertyChangeHandler()&#39;
[build]    11 | PropTest::PropTest() {
[build]       |                    ^

and I find the place where the error occurs bizarre.

答案1

得分: 1

让我们按顺序进行。<br/>免责声明:不幸的是,我犯了一个错误,下载了 Visual Studio 的非英语版本,从未改回来,因此我没有精确的错误消息。


你应该注意到的第一个错误是在 QPropertyChangeHandler&lt;[...]&gt; 的代码行中没有默认构造函数。

通过将

this-&gt;propertyChangeHandler = this-&gt;m_property.onValueChanged(&amp;PropTest::TestFunction);

从构造函数的主体中移出,并放到类的初始化列表中,可以轻松修复这个问题。


解决了这个错误后,现在是时候解决类型混乱的问题了。

PropTest::TestFunction 方法的确切类型是 void(PropTest::*)();这与 void() 是不同的类型,因为对于类的方法来说,指针 this 总是作为参数传递的。

因为将 this 视为参数,所以你不能这样做:

propertyChangeHandler(m_property.onValueChanged(&amp;PropTest::TestFunction))

如果尝试这样做,你会得到来自 Qt 的错误消息(来自 QProperty.h 中的静态断言):Functor callback must be callable without any parameters

假设你想在处理程序中连接的函数需要是对象方法(而不是单独的函数或静态方法),有几种解决方法:

  1. 第一个解决方案使用一个函数对象,其中包含你的对象作为其成员。<br/>头文件:
class PropTest;

struct TestFunctor {
public:
    TestFunctor(PropTest* propTestObject);
    void operator () () const;

private:
    PropTest* object;
};

和源文件:

TestFunctor::TestFunctor(PropTest* propTestObject)
    : object(propTestObject)
{
}

void TestFunctor::operator()() const {
    object-&gt;TestFunction();
}

有了这个解决方案(只有这个解决方案),propertyChangeHandler 的类型必须更改为 QPropertyChangeHandler&lt;TestFunctor&gt;,并使用以下方式构造:propertyChangeHandler( m_property.onValueChanged(TestFunctor(this)))

  1. 第二个解决方案是使用 lambda 表达式。例如:
PropTest::PropTest()
    : QObject(),
    propertyChangeHandler(m_property.onValueChanged(std::function&lt;void()&gt;([=]() { this-&gt;TestFunction(); })))
{
}

如果你决定采用这种方式(与你的问题相同),propertyChangeHandler 的类型是 QPropertyChangeHandler&lt; std::function&lt;void()&gt; &gt;

  1. 第三个解决方案是使用 bind 来绑定 TestFunction 方法。
PropTest::PropTest()
    : QObject(),
    propertyChangeHandler(m_property.onValueChanged(std::function&lt;void()&gt;(std::bind(&amp;PropTest::TestFunction, this)))
    {
    }
  1. 如果你可以将类方法 TestFunction() 转化为单独的函数或静态方法,问题就会变得简单很多。propertyChangeHandler 的类型分别需要是 QPropertyChangeHandler&lt;void()&gt;(用于单独函数)或 QPropertyChangeHandler&lt;void(*)()&gt;(用于静态方法)。

最后,代码可以编译通过!!

附注:如果函数不需要连接到对象实例,我会选择解决方案 4。否则,我会选择解决方案 2 或解决方案 3。

英文:

Let us proceed in order.<br/>Disclaimer: unfortunately, I made the mistake of downloading a non-English version of Visual studio and never changed it back so I do not have the exact error messages.


The first error you sould have notice is in the lines of QPropertyChangeHandler&lt;[...]&gt; has no default constructor.

This is easily corrected by moving

this-&gt;propertyChangeHandler = this-&gt;m_property.onValueChanged(&amp;PropTest::TestFunction);

out of the constructor's body and into the initialization list of your class.


With that error out of the way, it is time to solve the type mess.

The exact type of the PropTest::TestFunction method is void(PropTest::*)(); this is a different type from void() because inherently, for class' methods, the pointer this is always going to be an argument.

Because this is considered an argument, you cannot do:

propertyChangeHandler(m_property.onValueChanged(&amp;PropTest::TestFunction))

If you try, you get the error message from Qt (from a static assert in QProperty.h): Functor callback must be callable without any parameters.

Assuming the function you want to connect in the handler needs to be an object method (not a separate function, not a static method), there are several ways to solve this:

  1. First solution uses a functor, with your object as its member.<br/>Header:

    class PropTest;
    
    struct TestFunctor {
    public:
        TestFunctor(PropTest* propTestObject);
        void operator () () const;
    
    private:
        PropTest* object;
    
    };
    

    And source:

    TestFunctor::TestFunctor(PropTest* propTestObject)
        : object(propTestObject)
    {
    }
    void TestFunctor::operator()() const {
        object-&gt;TestFunction();
    }
    

    With that solution (and that solution only), the type of propertyChangeHandler must be changed to QPropertyChangeHandler&lt;TestFunctor&gt; and it is constructed with<br/>propertyChangeHandler( m_property.onValueChanged(TestFunctor(this))).

  2. Second solution is to use a lambda. For instance:

    PropTest::PropTest()
        : QObject(),
        propertyChangeHandler(m_property.onValueChanged(std::function&lt;void()&gt;([=]() { this-&gt;TestFunction(); })))
    {
    }
    

    The type of propertyChangeHandler is QPropertyChangeHandler&lt; std::function&lt;void()&gt; &gt; if you decide to proceed this way (i.e. same as your question).

  3. Third solution is to bind the TestFunction method.

    PropTest::PropTest()
        : QObject(),
        propertyChangeHandler(m_property.onValueChanged(std::function&lt;void()&gt;(std::bind(&amp;PropTest::TestFunction, this))))
    {
    }
    
  4. If you can turn the class method TestFunction() into a separate function or into a static method, it simplifies the issue quite a bit. The type of propertyChangeHandler needs to be, respectively QPropertyChangeHandler&lt;void()&gt; (for a separate function) or QPropertyChangeHandler&lt;void(*)()&gt; (for a static method).

And finally, it compiles!!

PS: If the function does not need to be attached to an object instance, I would use solution 4. Otherwise, I would go for either solution 2 or solution 3.

huangapple
  • 本文由 发表于 2023年2月24日 11:54:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75552470.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定