QML listview delegate item as QQuickItem



  • I have list view with delegate items with two component Text and Image

    The listview

    ListView {
        id: table_list_view
        anchors.fill: parent
        model: appModel
        highlight:  Rectangle { color: "#BB333333"; radius: 3 }
        delegate: appDelegate
    }
    

    And the delegate is like,

     Component {
            id: appDelegate;
    
            Item {
                width:parent.width;
                height:50;
               Row{
                   id:table_row
    
                Rectangle {
                     id:title_cln
                     width:200;
                     height:50;
                     color: "#88FF3333"
                     border.width: 1;
                     border.color: "white"
    
                     Text{
                         id: title_txt
                         anchors.centerIn: parent
                         text: title;
                         color: "white"
                     }
                     MouseArea{
                         anchors.fill: parent
                         onClicked: {
                             table_list_view.currentIndex=index;
                         }
                     }
                   }
    
    
                Rectangle {
                     id:img_cln
                     width:200;
                     height:50;
                     color: "#88333333"
                     border.width: 1;
                     border.color: "white"
    
                     Image {
                         id: myIcon;
                         width:200;
                         height:50;
                         anchors.horizontalCenter: parent.horizontalCenter;
                         source: icon;
                         fillMode: Image.PreserveAspectFit
                         cache : true;
                         asynchronous: true;
                     }
    
                     MouseArea{
                         anchors.fill: parent
                         onClicked: {
                             table_list_view.currentIndex=index;
                         }
                     }
                   }
        }
        }
        }
    

    And the list model

    ListModel {
            id: appModel
    
        }
    

    I am filling like

     Component.onCompleted: {
           appModel.append({ title:"Image1",icon: "http://www.gstatic.com/webp/gallery/4.jpg" })
           appModel.append({ title:"Image2",icon: "http://www.gstatic.com/webp/gallery/2.jpg" })
           appModel.append({ title:"Image3",icon: "http://www.gstatic.com/webp/gallery/3.jpg" })
    
      }
    

    Now what I need to implement is get each delegate image item as QQuickItem and then pass to c++ for further processing,

    I can get text from the model like,

    for(var i=0;i<appModel.count;i++)
               var text =appModel.get(i).title;
    

    Using the same way how can I get Image component with the id myIcon


  • Moderators

    @haris123 You can apply one of the following technique as explained here
    http://forum.qt.io/topic/67493/solved-saving-qml-image-from-c



  • I that case only one item can pass, but my case is I have to pass selected item from a listview.


  • Moderators

    @haris123 @haris123 You can do in following ways:

    • Inside Image you can monitor the Status using its corresponding handler onStatusChanged and when Image.Ready is triggered you call the C++ function passing it the image which I had explained in the earlier post.
    • From C++ use findChild to find the ListView and then access its contentItem property which gives a list of delegates(these are children of content item). Then you can iterate over the children(list of QQuickItems) and call the grabToImage on each. For eg. to get list of items
    QQuickItem *itm =  qvariant_cast<QQuickItem*>(view.rootObject()->findChild<QQuickItem*>("mylist")->property("contentItem"));
    QList<QQuickItem*> list = itm->childItems();
    //Then iterate over this list and call the function. 
    //May be you will need to go in further i.e access children of children
    


  • Hi Thanks for the answer,

    So is there any why to iterate delegate item from QML?


  • Moderators

    @haris123 Yes it is possible too. The delegates are children of contentItem. Similar to C++ here too you can iterate over its children. A typical code to do this Rectangle as delegate is as follows:

    for(var i=0; i<list.contentItem.children.length; i++) {
        console.log(list.contentItem.children[i])
    }
    

    This will list all the Rectangle's.



  • I manged to get it work using the above code with below modification, but the issue is the image saved is small as table cell.

      for(var i=0; i<table_list_view.contentItem.children.length; i++) {
                     for(var j=0; j<table_list_view.contentItem.children[i].children.length; j++){
    
                        for(var k=0; k<table_list_view.contentItem.children[i].children[j].children.length; k++){
                            for(var l=0; l<table_list_view.contentItem.children[i].children[j].children[k].children.length; l++){
                                console.log(i+" "+j+" "+k+" "+l+" "+table_list_view.contentItem.children[i].children[j].children[k].children[l])
                                if(k===1&&l===0) //filter image component only
                                    login.save(table_list_view.contentItem.children[i].children[j].children[k].children[l]);
                             }
                        }
                     }
                 }
    

    c++ code,

     void Login::save( QQuickItem *item)
      {
        auto grabResult = item->grabToImage();
        connect(grabResult.data(), &QQuickItemGrabResult::ready, [=]() {
        static int c=0;
        c++;
        QString fileName =  "C:/Users/vapplica/Desktop/"+QString::number(c)+".png";
        qDebug()<<"Saving image.."+fileName;
        grabResult->saveToFile(fileName);
        QImage img = grabResult->image();// gives the QImage associated if you want to use it directly in the program
        int p=0;
      });
    

    }

    My ultimate purpose is, load network image in qml asynchronously and save it to disk. But I think it wont work like, save image with original resolution by extracting it from listview delegate. Do you have any suggestion.


  • Moderators

    @haris123 What if you specify targetSize as explained here ?



  • I tried that, but when I give targetSize to it's orginal image resolution it's giving the output png with expected resolution where as the image portion is scaled to different.

    Another thing I have tried is

      item->resetHeight();
       item->resetWidth();
    

    inside the function

        void Login::save( QQuickItem *item), 
    

    where as this changes the image object showing in qml list view, as both uses same object. And I coud'nt find a way to deep copy of QQuickItem .


  • Moderators

    @haris123 Can you confirm if its the same behavior as above with the following example code ?

    import QtQuick 2.6
    import QtQuick.Controls 1.4
    
    Rectangle {
        id: rect
        width: 200
        height: 200
    
        Image {
            id: img
            anchors.fill: parent
            source: "http://r0k.us/graphics/kodak/kodak/kodim03.png"
        }
    
        Button {
            anchors.bottom: parent.bottom
            text: "Grab"
            onClicked: {
                img.grabToImage(function(result) {
                    result.saveToFile("myimage.png");
                }, Qt.size(768, 512));
            }
        }
    }
    
    


  • Thanks for the replay,

    The above code works fine here also, but when I used the same in list view gave scaled output.

         import QtQuick 2.3
         import QtQuick.Window 2.2
         import QtQuick.Controls 1.4
    
       Window {
         property int count: 0
         visible: true
        width : 900
        height: 900
    
        Rectangle{
         width: parent.width
         height:parent.height
         color: "#000000"
    
    Component {
        id: appDelegate;
    
        Item {
            width:parent.width;
            height:50;
           Row{
               id:table_row
    
            Rectangle {
                 id:cam_cln
                 width:200;
                 height:50;
                 color: "#88FF3333"
                 border.width: 1;
                 border.color: "white"
    
                 Text{
                     id: cam_txt
                     anchors.centerIn: parent
                     text: cam;
                     //font.bold : true
                     //font.pointSize: 9
                     color: "white"
                 }
                 MouseArea{
                     anchors.fill: parent
                     onClicked: {
                         table_list_view.currentIndex=index;
                     }
                 }
               }
    
    
            Rectangle {
                 id:img_cln
                 width:200;
                 height:50;
                 color: "#88333333"
                 border.width: 1;
                 border.color: "white"
    
                 Image {
                     id: myIcon;
                     width:200;
                     height:50;
                     anchors.horizontalCenter: parent.horizontalCenter;
                     source: icon;
                     fillMode: Image.PreserveAspectFit
                     cache : true;
                     asynchronous: true;
                 }
    
                 MouseArea{
                     anchors.fill: parent
                     onClicked: {
                         table_list_view.currentIndex=index;
    
                     }
                 }
               }
    
    
    
    
    }
    }
    }
    
    ListView {
        id: table_list_view
        highlightMoveVelocity :1000
       // objectName: "gridObject"
        anchors.fill: parent
        cacheBuffer:50
        clip: true;
        focus: true
        model: appModel
        highlight:  Rectangle { color: "#BB333333"; radius: 3 }
        delegate: appDelegate
        flickableDirection: Flickable.VerticalFlick
    
        flickableChildren: MouseArea {
               anchors.fill: parent
               onClicked:{
                   }
    
         }
    
    
    }
    
    ListModel {
        id: appModel
    
    }
    
    Component.onCompleted: {
       appModel.append({ cam:"Image1",icon: "http://www.gstatic.com/webp/gallery/4.jpg" })
       appModel.append({ cam:"Image2",icon: "http://www.gstatic.com/webp/gallery/2.jpg" })
       appModel.append({ cam:"Image3",icon: "http://www.gstatic.com/webp/gallery/3.jpg" })
       appModel.append({ cam:"Image3",icon: "http://r0k.us/graphics/kodak/kodak/kodim03.png" })
    
     }
    }
    
     Button {
       anchors.bottom: parent.bottom
       text: "Grab"
       onClicked: {
    
           for(var i=0; i<table_list_view.contentItem.children.length; i++) {
               for(var j=0; j<table_list_view.contentItem.children[i].children.length; j++){
                   for(var k=0; k<table_list_view.contentItem.children[i].children[j].children.length; k++){
                       for(var l=0; l<table_list_view.contentItem.children[i].children[j].children[k].children.length; l++){
                           console.log(i+" "+j+" "+k+" "+l+" "+table_list_view.contentItem.children[i].children[j].children[k].children[l])
                           if(k===1&&l===0){
                            table_list_view.contentItem.children[i].children[j].children[k].children[l].grabToImage(function(result) {
    
    
                                var fielName = "C:/Users/haris/Desktop/"+count+".png"
                                result.saveToFile(fielName);
                                count++;
                            }, Qt.size(768, 512));
                           }
                        }
                    }
             }
          }
       }
    

    }

    }


  • Moderators

    @haris123 Scaling it seems is because of fillMode: Image.PreserveAspectFit



  • You are right, now it's working as expected. The main issue solved, I can avoid the aspect fit, let the table in filled mode, but did you noticed that the last image wont saved, is that behavior there?.


  • Moderators

    @haris123 No. All 4 were saved. But I noticed you have mistakenly added same role values for last 2 items.
    cam:"Image3"



  • Thanks for noticing, I have rebuild and run again, now it's works fine, thanks once again, I really appreciate your help.


  • Moderators

    @haris123 You're Welcome,
    Btw. if your aim is to capture all the images at once you can avoid the cumbersome task of iterating children. You can use signal and slots mechanim here too.
    For eg.

    //Inside the Window declare a signal
    Window {
       id: win
       ...
       signal capture;
       ...
    
    //Inside the Image delegate use Connections to connect to the signal
    ...
    Image {
       id: myIcon;
       ...
       Connections {
        target: win
        onCapture: {
            myIcon.grabToImage(function(result) {
                result.saveToFile("C:/Users/vapplica/Desktop/"+index+".png");
            }, Qt.size(768, 512));
        }
      }
    }
    
    //Fire the signal
    Button {
        ...
        text: "Grab"
        onClicked: {
            win.capture()
        }
    }
    

    Also you can directly access Image source size which will be helpful for saving the images. So you can replace Qt.size(768, 512) with Qt.size(myIcon.sourceSize.width, myIcon.sourceSize.height)

    Here is the doc for Connections.



  • Not all the image, only selected image by the user, actually in my original application there is third delegate item tickbox using it user can select the image to download. Any way thanks for informing me the new method.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.