QML 的 Repeater 和 Loader 组合使用问题

Repeater,在对于需要生成多个 Item,但又不适合 ListView 的情况是很适用的。对于 Repeater 需要嵌套不同种类的 Delegate 的情况,有一些不同的解决方案。

例如,你针对不同的数据需要生成不同的 Item A 或者 Item B,那么一种选择就是把他们都作为子 Item 放到 Delegate 里面,然后选择性的进行 visible 的设置,来达到只现实一个的目的。这样带来的缺点也是显而易见的:

  • 需要真的实际创建多个并不使用的 Item
  • 对不同的 Item 设置值的时候,可能并不一定会有适合当前不显示的这个 Item 的值。例如,某项属性并不见于 Type B中,在实现的时候却不得不放进一个 dummy value 来避免程序错误。

而另一种选择就是,会选择 Repeater 嵌套一个 Loader ,用 loader 来动态的选择加载某个源文件,或者 Component,通过使用 Loader 的 source / setSource / sourceComponent 来实现。

但是如果你要进行多层次的嵌套,也即在 Loader 里面再套一个 Repeater,就会出现一个奇妙的现象。

举两个例子。

import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.10

GridLayout {
    columns: 2

    Repeater {
        model: [[1], [2], [3, 4, 5], [4], [5, 6]]
        delegate: Component {
            id: comp
            Repeater {
                model: modelData
                Label {
                    text: modelData
                }
            }
        }
    }
}

上面是一个不使用 Loader 的嵌套 Repeater,下面则是一个使用 Loader 的嵌套 Repeater。

import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.10

GridLayout {
    columns: 2

    Repeater {
        model: [[1], [2], [3, 4, 5], [4], [5, 6]]
        delegate: Loader {
            id: loader
            sourceComponent: comp
            Component {
                id: comp
                Repeater {
                    model: modelData
                    Label {
                        text: modelData
                    }
                }
           }
       }
    }
}

这两个代码最终的显示效果,是不一样的。前者可以正常显示表格,就仿佛内层的Repeater 的元素就是在 GridLayout 里一样。

而后者所有的元素都挤在了一起。

原因大概是因为使用了 Loader 的情形下,Loader 本身在层次关系中占有了一层,就像 一个普通的 Item。Loader 内部的 Repeater 并不能跨越 Loader 本身把内部的 Item 添加给 GridLayout。事实上,如果你在代码中把 Loader 直接改成 Item 就可以获得后图一样的效果,可以印证这一点。

只能说并没有一个好办法能够解决这样的问题,最好的解决办法,还是直接把 Model 扁平化只使用一层 Repeater 和 Loader 的组合。

This entry was posted in Qt and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.