You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QML:如何从Footer访问GridView所有Delegate实例的Stream功能?

The Problem

I've spent a lot of time searching Google/Stack Overflow for a solution to this, but haven't found anything that works. I understand that you can't directly access child element IDs/properties without special tricks. I tried using multiple alias properties, but couldn't build an alias chain since I can't define properties in the Component.

My goal is to display all videos via MainGrid.qml (a GridView component) and implement playback controls in Footer.qml. Here's my current code setup:

MainGrid.qml

GridView {
    x: videoWallWindow.x
    y: videoWallWindow.y
    width: videoWallWindow.width
    height: videoWallWindow.height
    cellWidth: 300
    cellHeight: 300
    property alias deleg : loader.item
    Loader {
        id: loader
        sourceComponent: videoDelegate
        visible: false
    }
    Component {
        id: videoDelegate
        Rectangle {
            id: container
            property alias streamVid : stream
            width: 256
            height: 240
            color: "#4f4f4f"
            border.color: "black"
            border.width: 3
            Stream {
                id: stream
            }
            Playbar {
                x: 0
                y: container.height - 20
                width: container.width
                height: 20
            }
            Text {
                id: textId
                text: name // defined in a ListModel
            }
        }
    }
    model: StreamList {}
    delegate: videoDelegate
    focus: true
}

Footer.qml

ToolBar {
    property MainGrid myGrid
    id: footer
    x: 0
    y: window.height - footer.height
    width: window.width
    background: Rectangle {
        implicitHeight: 45
        color: "#212121"
        Rectangle {
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
            color: "transparent"
            border.color: "#212121"
        }
    }
    Row {
        anchors.centerIn: parent
        PlaybarButton {
            id: pauseButton
            height: footer.height
            width: footer.height
            property bool currentState: true
            onClicked: {
                // This only accesses the Loader's single instance, not all delegates
                currentState ? myGrid.deleg.streamVid.pause() : myGrid.deleg.streamVid.play()
                currentState = !currentState
            }
            Image {
                id: pauseImage
                anchors.fill: parent
                source: parent.currentState ? ("pics/pause.png") : ("pics/play.png")
            }
        }
    }
}

Stream.qml

Video {
    id: streamVideo
    width: mainGrid.cellWidth
    height: mainGrid.cellHeight
    anchors.fill: parent
    source: portrait // defined as the path in a ListModel
    MouseArea {
        anchors.fill: parent
        onClicked: {
            // Note: Typo here - should reference streamVideo, not video
            streamVideo.playbackState == MediaPlayer.PlayingState ? streamVideo.pause() : streamVideo.play()
        }
    }
    autoPlay: true
    loops: MediaPlayer.Infinite
    focus: true
}

main.qml

ApplicationWindow {
    id: window
    visible: true
    width: Screen.desktopAvailableWidth
    height: Screen.desktopAvailableHeight
    ...
    MainGrid {
        id: mainGrid
    }
    Footer {
        id: footer
        myGrid: mainGrid
    }
}

I need to figure out how to properly access all Delegate video/stream instances in the GridView from Footer.qml. Do I need to completely refactor my existing code?


The Solution

You don't need a full refactor—your core issue is that the Loader + alias approach only gives you access to a single hidden delegate instance, not all the live ones created by the GridView for each model item. Here's a straightforward fix:

Step 1: Track All Active Delegates in MainGrid

Add a property to MainGrid to keep a list of all active delegate instances, then update the delegate to register/unregister itself when it's created/destroyed:

GridView {
    // ... existing properties ...
    property var activeDelegates: [] // New property to track live delegates

    Component {
        id: videoDelegate
        Rectangle {
            id: container
            property alias streamVid : stream
            // ... existing delegate code ...

            // Add these two handlers to manage the delegate list
            Component.onCompleted: mainGrid.activeDelegates.push(this)
            Component.onDestruction: mainGrid.activeDelegates.remove(mainGrid.activeDelegates.indexOf(this))
        }
    }

    // Optional: Add helper methods to control all streams (cleaner than accessing the list directly)
    function pauseAllStreams() {
        activeDelegates.forEach(delegate => {
            delegate.streamVid.pause()
        })
    }

    function playAllStreams() {
        activeDelegates.forEach(delegate => {
            delegate.streamVid.play()
        })
    }
}

Step 2: Update Footer to Control All Streams

Modify the Footer's button click handler to use the helper methods (or directly iterate the delegate list) to control every video:

PlaybarButton {
    id: pauseButton
    // ... existing button code ...
    onClicked: {
        // Use the helper methods for cleaner code
        currentState ? myGrid.pauseAllStreams() : myGrid.playAllStreams()
        currentState = !currentState
    }
}

Quick Fix for Stream.qml

Also, fix the typo in your Stream.qml MouseArea—you were referencing an undefined video ID instead of streamVideo:

MouseArea {
    anchors.fill: parent
    onClicked: {
        streamVideo.playbackState == MediaPlayer.PlayingState ? streamVideo.pause() : streamVideo.play()
    }
}

Why This Works

  • The Component.onCompleted and Component.onDestruction handlers ensure every delegate adds itself to the activeDelegates list when it's created, and removes itself when it's destroyed (e.g., when scrolling off-screen or the model changes).
  • The helper methods in MainGrid encapsulate the logic to control all streams, keeping your Footer code clean and decoupled from the GridView's internal structure.

You don't need to overhaul your entire setup—this small adjustment will let you control all video instances from the Footer.

内容的提问来源于stack exchange,提问作者NhatNienne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:50:08