Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Use repeater inside chartview



  • Hi, can anyone help me on the following?

    In a qml file trying to dynamically create AreaSeries objects. Try to get this working but the only result is an empty window, without any significant application output or debugging error information what is going wrong. No chartobject or graphics are shown.

    The data in the ListModel defined is a first step. Second step (after this concept appears to be working) will be removing the ListModel out of the qml, and placing it in the C++ environment. Code:

    ChartView {
    id: chartid
    antialiasing: true

        //Valueaxis
        ValueAxis{ id:xAxis; min:    0; max: 40000; tickCount:  9 }
        ValueAxis{ id:yAxis; min: -200; max:  1400; tickCount: 17 }
    
        //Listmodel only for testing AreaSeries/Repeater concept
        ListModel{
            id: listModel
            ListElement { x1: 18000; x2: 18200   ; y1: -100; y2:  400 }
            ListElement { x1: 25000; x2: 25200   ; y1: -100; y2: 1000 }
            ListElement { x1: 31000; x2: 31200   ; y1: -100; y2: 1200 }
            ListElement { x1: 39500; x2: 39700   ; y1: -100; y2: 1250 }
        }
    
        Repeater{
            id: areaSeriesRepeater
            model: listModel
            delegate:
                Item{
                AreaSeries {
                    axisX: xAxis
                    axisY: yAxis
                    color: "grey"
                    borderColor: "black"
                    borderWidth: 2
    
                    upperSeries: LineSeries {
                        XYPoint { x: model.x1 ; y: model.y2 }
                        XYPoint { x: model.x2 ; y: model.y2 }
                    }
                    lowerSeries: LineSeries {
                        XYPoint { x: model.x1 ; y: model.y1 }
                        XYPoint { x: model.x2 ; y: model.y1 }
                    }
                }
            }
        }
    }


  • Hereby a solution that works for me. Instead of using a repeater, this codesample works with the ChartView's onCompleted signal handler. In the onCompleted handler first three LineSeries are dynamically created, then an AreaSeries is created.

    ChartView {
    id: chartid
    anchors.fill: parent
    antialiasing: true
    
        //Valueaxis
        ValueAxis{ id:xAxis; min:    0; max: 40000; tickCount:  9 }
        ValueAxis{ id:yAxis; min: -200; max:  1400; tickCount: 17 }
    
        //Listmodel only for testing Area- and LineSeries concept
        ListModel{
            id: listModel
            ListElement { x1: 18000; y1: -100; x2: 18000 ; y2:  400 }
            ListElement { x1: 25000; y1: -100; x2: 25000 ; y2: 1000 }
            ListElement { x1: 31000; y1: -100; x2: 31000 ; y2: 1200 }
            ListElement { x1: 36500; y1: -100; x2: 39700 ; y2: 1250 }
        }
    
        Component.onCompleted: {
            var count = listModel.count;
    
            for(var i = 0;i < count;i ++)
            {
                if (i < count - 1) // add LineSeries
                {
                    var lineTypeSeries = chartid.createSeries(ChartView.SeriesTypeLine, "line" + i, xAxis, yAxis);
                    lineTypeSeries.color = "black";
                    lineTypeSeries.width = 2;
                    lineTypeSeries.borderWidth = 0;
    
                    lineTypeSeries.append(listModel.get(i).x1, listModel.get(i).y1);
                    lineTypeSeries.append(listModel.get(i).x2, listModel.get(i).y2);
                }
                else
                {
                    var areaTypeSeries = chartid.createSeries(ChartView.SeriesTypeArea, "area" + i, xAxis, yAxis);
                    areaTypeSeries.pointsVisible = true;
                    areaTypeSeries.color = "lightgrey";
                    areaTypeSeries.borderColor = "black";
                    areaTypeSeries.borderWidth = 2;
    
                    areaTypeSeries.lowerSeries = chartid.createSeries(ChartView.SeriesTypeLine, "lowerSerie");
                    areaTypeSeries.lowerSeries.width = 0;
                    areaTypeSeries.lowerSeries.borderWidth = 0;
                    areaTypeSeries.lowerSeries.color = areaTypeSeries.borderColor;
                    areaTypeSeries.lowerSeries.capStyle = 0x00;
    
                    areaTypeSeries.lowerSeries.append(listModel.get(i).x1, listModel.get(i).y1);
                    areaTypeSeries.lowerSeries.append(listModel.get(i).x2, listModel.get(i).y1);
    
                    areaTypeSeries.upperSeries.append(listModel.get(i).x1, listModel.get(i).y2);
                    areaTypeSeries.upperSeries.append(listModel.get(i).x2, listModel.get(i).y2);
                }
            }
        }
    }


  • Why is AreaSeries inside an Item?



  • If you don't place it inside an item object you get run time error: popup messagebox reporting a "Read access violation" and the application output windows says "QML Component: Delegate must be of Item type".

    When using the Item object, no errors are reported, looks good, but application window (chartview) stays completely empty.



  • I think you will have to find another way to do this.

    I tried this:

    ChartView {
                    id: chartid
                    antialiasing: true
    
                    width: parent.width
                    height: 500
    
                    //Valueaxis
                    ValueAxis{ id:xAxis; min:    0; max: 40000; tickCount:  9 }
                    ValueAxis{ id:yAxis; min: -200; max:  1400; tickCount: 17 }
    
                    //Listmodel only for testing AreaSeries/Repeater concept
                    ListModel{
                        id: listModel
                        ListElement { x1: 18000; x2: 18200   ; y1: -100; y2:  400 }
                        ListElement { x1: 25000; x2: 25200   ; y1: -100; y2: 1000 }
                        ListElement { x1: 31000; x2: 31200   ; y1: -100; y2: 1200 }
                        ListElement { x1: 39500; x2: 39700   ; y1: -100; y2: 1250 }
                    }
    
                    Repeater{
                        id: areaSeriesRepeater
                        model: listModel
                        delegate:
                            Item{
                            AreaSeries {
                                id: areaseries
    
                                axisX: xAxis
                                axisY: yAxis
                                color: "grey"
                                borderColor: "black"
                                borderWidth: 2
    
                                upperSeries: LineSeries {
                                    XYPoint { x: model.x1 ; y: model.y2 }
                                    XYPoint { x: model.x2 ; y: model.y2 }
                                }
                                lowerSeries: LineSeries {
                                    XYPoint { x: model.x1 ; y: model.y1 }
                                    XYPoint { x: model.x2 ; y: model.y1 }
                                }
    
                                Component.onCompleted: {
                                    chartid.children.push(areaseries)
                                }
                            }
                        }
                    }
                }
    

    But this causes a segfault. I think the problem is that AreaSeries is not a direct child of ChartView.



  • Thnx for your idea's. I'm also working on a solution via the onCompleted signal handler. First result looks promising. I'll work it out some further, and when usefull I'll post it here. In the meantime if anyone has any idea's how handle this in a proper way, please share it.



  • Hereby a solution that works for me. Instead of using a repeater, this codesample works with the ChartView's onCompleted signal handler. In the onCompleted handler first three LineSeries are dynamically created, then an AreaSeries is created.

    ChartView {
    id: chartid
    anchors.fill: parent
    antialiasing: true
    
        //Valueaxis
        ValueAxis{ id:xAxis; min:    0; max: 40000; tickCount:  9 }
        ValueAxis{ id:yAxis; min: -200; max:  1400; tickCount: 17 }
    
        //Listmodel only for testing Area- and LineSeries concept
        ListModel{
            id: listModel
            ListElement { x1: 18000; y1: -100; x2: 18000 ; y2:  400 }
            ListElement { x1: 25000; y1: -100; x2: 25000 ; y2: 1000 }
            ListElement { x1: 31000; y1: -100; x2: 31000 ; y2: 1200 }
            ListElement { x1: 36500; y1: -100; x2: 39700 ; y2: 1250 }
        }
    
        Component.onCompleted: {
            var count = listModel.count;
    
            for(var i = 0;i < count;i ++)
            {
                if (i < count - 1) // add LineSeries
                {
                    var lineTypeSeries = chartid.createSeries(ChartView.SeriesTypeLine, "line" + i, xAxis, yAxis);
                    lineTypeSeries.color = "black";
                    lineTypeSeries.width = 2;
                    lineTypeSeries.borderWidth = 0;
    
                    lineTypeSeries.append(listModel.get(i).x1, listModel.get(i).y1);
                    lineTypeSeries.append(listModel.get(i).x2, listModel.get(i).y2);
                }
                else
                {
                    var areaTypeSeries = chartid.createSeries(ChartView.SeriesTypeArea, "area" + i, xAxis, yAxis);
                    areaTypeSeries.pointsVisible = true;
                    areaTypeSeries.color = "lightgrey";
                    areaTypeSeries.borderColor = "black";
                    areaTypeSeries.borderWidth = 2;
    
                    areaTypeSeries.lowerSeries = chartid.createSeries(ChartView.SeriesTypeLine, "lowerSerie");
                    areaTypeSeries.lowerSeries.width = 0;
                    areaTypeSeries.lowerSeries.borderWidth = 0;
                    areaTypeSeries.lowerSeries.color = areaTypeSeries.borderColor;
                    areaTypeSeries.lowerSeries.capStyle = 0x00;
    
                    areaTypeSeries.lowerSeries.append(listModel.get(i).x1, listModel.get(i).y1);
                    areaTypeSeries.lowerSeries.append(listModel.get(i).x2, listModel.get(i).y1);
    
                    areaTypeSeries.upperSeries.append(listModel.get(i).x1, listModel.get(i).y2);
                    areaTypeSeries.upperSeries.append(listModel.get(i).x2, listModel.get(i).y2);
                }
            }
        }
    }