【问题标题】:How to find out when the QQuickItem-derived class object is initialized?如何找出 QQuickItem 派生类对象何时初始化?
【发布时间】:2018-03-01 21:23:16
【问题描述】:

我有一个继承自 QQuickItem 的类,在里面我正在操作它的 width height 属性。我也暴露了我自己的属性。

class MyQQuickItem : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QUrl source MEMBER m_source NOTIFY sourceChanged)

    public:
    explicit MyQQuickItem(QQuickItem *a_parent = Q_NULLPTR);
     ~PDFPage();

    signals:
    void sourceChanged(const QUrl a_source);

    private:
    QUrl m_source;
};

在qml中:

...
MyQQuickItem
{
    width: parent.width / 2
    height: parent.height
    source: "someSource"
    Component.onCompleted
    {
        console.log("component onCompleted");
    }
}

sourceChanged 发出时,我正在处理width height 属性,但在第一次发出时,它们尚未初始化,并且在我的NOTIFY 信号之后调用Component.onCompleted

我可以通过调用isComponentComplete 在获取widthheight 之前检查组件是否准备就绪,并在准备就绪时执行我的代码,但我无法找出它何时发生以及source 的初始值不是时跳过。

当然我可以创建插槽'itemReady' 并从Component.onCompleted 调用它,但是我有很多 QML 使用我的类,我将来会创建更多,所以我不想做复制粘贴工作。

我也不想在Component.onCompleted 中设置源。

连接到widthChangedheightChanged 信号也不是一个好主意,因为我经常调整我的项目大小,并且我不想执行我的代码。

有没有办法从 C++ 中获取completed 信号?

编辑:

我按照@Mitch 所说的做了-覆盖了componentComplete 方法和内部,称它为等效的基类。 isComponentComplete() 返回 true,但我仍然从 width()height() 方法中得到 0:

void MyQQuickItem::componentComplete()
{
    QQuickItem::componentComplete();
    if(isComponentComplete())
    {
        qDebug() << "c++: oncompleted, width,height: " << width() << height(); //gives 0,0
    }

}

实际上我发现 QML 中的 Component.onCompleted 也打印 0:

...
MyQQuickItem
{
    width: parent.width / 2
    height: parent.height
    source: "someSource"
    Component.onCompleted
    {
        console.log("component onCompleted width, height: ", width, height); //it gives 0 too
    }
}

@derM Component.onCompleted 不直接被QQuickItem::componentComplete() emmited,因为它在上面c++ 中的qDebug 之后打印了它的日志。

因此,虽然它已准备就绪,但属性并未初始化。

EDIT2:

终于解决了。 Window 是有罪的,因为它使用 contentItem 作为他孩子的父母,而在 MyQQuickItem 中 Component.onCompleted widthheightcontentItem(他的父母)是 0。

当我这样做时:

Window
{
    id: wnd
    width: 640
    height: 480
    Component.onCompleted:
    {
        console.log("Window completed: ", this, width, height);
        console.log("windowContentItem: ", contentItem, width, height);
    }

    MyQQuickItem
    {
        width: parent.width
        height: parent.height
        Component.onCompleted:
        {
            console.log("MyQQuickItem completed: ", this, width, height);
            console.log("MyQQuickItem parent: ", parent, parent.width, parent.height);
        }
    }
}

打印出来:

qml: Window completed:  QQuickWindowQmlImpl(0x345b5eb4d0) 640 480
qml: windowContentItem:  QQuickRootItem(0x345e2cdec0) 640 480
qml: MyQQuickItem completed:  MyQQuickItem(0x345b5b99e0) 0 0
qml: MyQQuickItem parent:  QQuickRootItem(0x345e2cdec0) 0 0

所以MyQQuickItem parentWindowcontentItem。当我更换

width: parent.width
height: parent.height

到:

width: wnd.width
height: wnd.height

它运行良好,在我的 void MyQQuickItem::componentComplete() 中,widthheight 按预期初始化。

我不明白的一件事是为什么在WindowonCompletedcontentItem 大小是正确的,但在MyQQuickItem onCompleted 中,大小是 0,0。如果有人能给我解释一下,我将不胜感激:P

【问题讨论】:

  • MCVE 仍然丢失。它将包含一个完整的 QML 文件,以便整个设置实际重现问题。
  • @derM 检查 EDIT2

标签: c++ qt qml qtquick2


【解决方案1】:

Qt code 像这样使用componentComplete()

void QQuickControl::componentComplete()
{
    Q_D(QQuickControl);
    QQuickItem::componentComplete();
    d->resizeContent();
    // ...
}

您可以执行类似的操作,将 resizeContent() 替换为适用于 widthheight 的函数。假设每当source 更改时也会调用该函数,则您需要isComponentComplete() 检查。使用这种方法,您应该不会有任何问题。

【讨论】:

  • 对不起,我说得太早了。 isComponentComplete() 在调用 QQuickItem::componentComplete() 之后实际上返回 true,但 widthheight 仍然为 0
  • 也许Component.onCompleted 可能会在QQuickItem::componentComplete() 中发出?因此,如果您遵循文档并首先调用基类方法,则信号将在您获得尺寸之前发出。尽管文档告诉您,尝试将QQuickItem::componentComplete() 移动到函数的末尾,看看是否没有崩溃:S
  • @Macias:一个最小的完整示例将有助于回答您的问题。
  • @Mitch 我已经编辑了我的问题,实际上你给出了正确的答案,但这并不是我的意思:f
【解决方案2】:

你可以继承QQmlParserStatus并实现componentComplete()。

class MyQQuickItem : public QQuickItem, public QQmlParserStatus
{
    Q_OBJECT
    Q_PROPERTY(QUrl source MEMBER m_source NOTIFY sourceChanged)

public:
    explicit MyQQuickItem(QQuickItem *a_parent = Q_NULLPTR);
    ~PDFPage();

    void classBegin();
    void componentComplete();

signals:
    void sourceChanged(const QUrl a_source);

private:
    QUrl m_source;
};

componentComplete() 将由 QML 引擎自动调用。

【讨论】:

  • 你不能同时继承 QQuickItem 和 QQmlParserStatus,因为 QQuickItem 本身继承自 QQmlParserStatus
  • 是的,没错!但是然后跳过inheter QQmlParserStatus 并覆盖classBegin() 和componentComplete()。
猜你喜欢
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
  • 2012-11-27
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
相关资源
最近更新 更多