2014-09-09 12 views
5

Ich habe ein sehr spezifisches Problem bei der Verwendung eines QML ListView Elements in Kombination mit seinen Abschnitt Eigenschaften.Qt QML ListView contentHeight Verhalten

Ich verwende Qt 4.8.6, aber ich habe auch das gleiche Problem, wenn ich dies in Qt 5.3.1 versuche.

Der Code kann sie auch durch einfaches Ändern der Import-Anweisung zu

Import 1.0 in älteren Versionen von Qt ausgeführt werden (für < Qt 4.7.4)

oder

QtQuick

importieren QtQuick 1.1 (Für> = Qt 4.7.4)

Hier ist ein eigenständiger Anwendungsfall, mein Problem zu demonstrieren:

import QtQuick 2.2 

Rectangle { 
    width: 800 
    height: 800 
    color: "black" 

    property int pageNumber: 1 
    property int totalPages: Math.ceil(animalListView.contentHeight/animalListView.height) 

    Text { 
     x: 2 
     y: 90 
     color: "Orange" 
     text: "Expected height: " + (animalListView.count*70 + (50*10)) 
     font.pixelSize: 28 
    } 

    Text { 
     x: 2 
     y: 0 
     color: "Orange" 
     text: "Actual ContentHeight: " + animalListView.contentHeight 
     font.pixelSize: 28 
    } 

    Text { 
     x: 2 
     y: 30 
     color: "Orange" 
     text: "Actual ChildrenRectHeight: " + animalListView.childrenRect.height 
     font.pixelSize: 28 
    } 

    Text { 
     x: 2 
     y: 60 
     color: "Orange" 
     text: "Total model items (minus sections): " + animalListView.count 
     font.pixelSize: 28 
    } 

    Rectangle { 
     id: boundingRect 
     width: 640 
     height: 500 
     x: 20 
     y: 200 
     radius: 10 
     border.width: 1 
     border.color: "green" 
     color: "transparent" 

     // The delegate for each section header 
     Component { 
      id: sectionHeaderDelegate 
      Rectangle { 
       width: parent.width 
       height: 50 // this is the problem     
       color: "transparent"     

       Text { 
        anchors.left: parent.left 
        id: headerText 
        text: section 
        color: "red" 
       } 

       Rectangle { 
        anchors.fill: parent 
        border.color: "purple"      
        border.width: 1  
        color: "transparent" 
       } 
      } 
     } 

     ListModel { 
      id: animalsModel 
      ListElement { name: "1Parrot"; size: "Small" } 
      ListElement { name: "2Guinea pig"; size: "Small" } 
      ListElement { name: "3Dog"; size: "Medium" } 
      ListElement { name: "4Cat"; size: "Medium" } 
      ListElement { name: "5Elephant"; size: "Medium" } 
      ListElement { name: "6Parrot"; size: "Small" } 
      ListElement { name: "7Guinea pig"; size: "Small" } 
      ListElement { name: "8Dog"; size: "Medium" } 
      ListElement { name: "9Cat"; size: "Medium" } 
      ListElement { name: "10Elephant"; size: "Large" } 
      ListElement { name: "11Parrot"; size: "Large" } 
      ListElement { name: "12Guinea pig"; size: "Large" } 
      ListElement { name: "13Dog"; size: "Large" } 
      ListElement { name: "14Cat"; size: "Medium" } 
      ListElement { name: "15Elephant"; size: "Large" } 
      ListElement { name: "16Parrot"; size: "Small" } 
      ListElement { name: "17Guinea pig"; size: "Small" } 
      ListElement { name: "18Dog"; size: "Medium" } 
      ListElement { name: "19Cat"; size: "Medium" } 
      ListElement { name: "20Elephant"; size: "Large" } 
     } 

     ListView { 
      id: animalListView 
      anchors.fill: parent 
      anchors.margins: 10 
      clip: true 
      interactive: true 
      flickableDirection: Flickable.VerticalFlick 
      boundsBehavior: Flickable.StopAtBounds 
      model: animalsModel 

      delegate: Item { 
       width: parent.width 
       height: 70 
        Text { 
         text: name 
         color: "green" 
        } 

        Rectangle { 
         anchors.fill: parent 
         border.color: "yellow"      
         border.width: 1  
         color: "transparent" 
        } 
       } 

      section.property: "size" 
      section.criteria: ViewSection.FullString 
      section.delegate: sectionHeaderDelegate 
     } 
    } 

    Rectangle { 
     anchors.top: boundingRect.top 
     anchors.left: boundingRect.right 
     anchors.leftMargin: 20   
     width: 40 
     height: 40 
     color: "blue" 

     MouseArea { 
      anchors.fill: parent 
      onClicked: { 
       if (pageNumber > 1) { 
        animalListView.contentY -= animalListView.height; 
        animalListView.returnToBounds(); 
        --pageNumber; 
       }    
      } 
     } 

     enabled: (!animalListView.atYBeginning) 
     visible: !(animalListView.atYBeginning && animalListView.atYEnd) 

     Text { 
      anchors.centerIn: parent 
      font.family: "Wingdings 3" 
      font.pixelSize: 40 
      text: "Ç" // Up arrow 
     } 
    } 

    Text { 
     visible: totalPages > 1 
     anchors.left: boundingRect.right 
     anchors.verticalCenter: boundingRect.verticalCenter 
     width: 100 
     height: 20 
     font.pixelSize: 18 
     horizontalAlignment: Text.AlignHCenter 
     color: "red" 
     text: qsTr("%1 of %2").arg(pageNumber).arg(totalPages) 
    } 

    Rectangle { 
     anchors.bottom: boundingRect.bottom 
     anchors.left: boundingRect.right 
     anchors.leftMargin: 20 
     width: 40 
     height: 40 
     color: "orange" 

     MouseArea { 
      anchors.fill: parent 
      onClicked: { 
       if (pageNumber < totalPages) { 
        animalListView.contentY += animalListView.height; 
        ++pageNumber; 
       } 
      } 
     } 

     enabled: (!animalListView.atYEnd) 
     visible: !(animalListView.atYBeginning && animalListView.atYEnd) 

     Text { 
      anchors.centerIn: parent 
      font.family: "Wingdings 3" 
      font.pixelSize: 40 
      text: "È" // Down arrow 
     } 
    } 

} 

ich die Listview bin mit einer Liste von Tiermodellen angezeigt werden, die von ihrer Größe klassifizierte. Um diese Kategorisierung in der Ansicht zu erreichen, benutze ich die section.property, section.critiria und section.delegate Eigenschaften des ListView wie im oben angegebenen Code implementiert.

(Hinweis. Bitte ignorieren Sie die Tatsache, dass das Modell, das ich auf dem Listview liefern nicht sortiert ist, ich verstehe, dass dies zahlreiche doppelte Kategorie Einträge in der Listview schaffen Dies ist neben dem Punkt hier.)

Wenn die Anzahl der Modelle den sichtbaren Bereich der ListView überschreitet, verwende ich die Eigenschaft totalPages, um zu berechnen, wie viele volle ListView-Seiten für die Navigation vorhanden sind. Die Pfeil-nach-oben- und die Pfeil-nach-unten-Taste dekrementieren und inkrementieren den content.Y der ListView jeweils um die Höhe des ListView.

Das Problem ist, dass die content des Listview nicht statisch bleibt, dynamisch verändert und bewirkt, dass meine Totalpages Eigenschaft Berechnung falsch.

Es ist interessant zu beachten, dass dieses Verhalten auftritt, wenn und nur wenn ich eine Höhe für meine sectionHeaderDelegate Rechteck festlegen. Wenn ich die height-Anweisung (Höhe: 50) auskommentiere, bleibt die contentHeight der ListView wie erwartet statisch - mit dem Nachteil, dass die Abschnittsüberschriften/Kategorien jetzt über dem Modelltext stehen, was überhaupt nicht sinnvoll ist .

Also meine Frage ist, warum die contentHeight des QML ListView-Elements dynamisch ändert, wenn und nur wenn ich einen Abschnittsdelegaten benutze, dessen Höhe auf einen Wert ungleich Null gesetzt wurde?

Außerdem habe ich die folgenden Eigenschaften im Listview zu Testzwecken verlassen, sollte der Listview mit den Auf-/Ab-Pfeile verwendet werden:

  interactive: true 
      flickableDirection: Flickable.VerticalFlick 
      boundsBehavior: Flickable.StopAtBounds 

Antwort

3

Es ist, weil Listview schätzt seine contentHeight nach derzeit sichtbaren Elementen. Überprüfen Sie, was passiert, wenn Ihre Abschnitte nicht gruppiert werden können. ListView vermeidet es, jedes Objekt instanziieren, so dass es die richtige Größe nicht sichtbaren Inhalts nicht kennt. Look at this thread.

+0

Der Take-Away, den ich aus dem Thread erhalte, zu dem Sie verlinken, ist folgender: "Wenn Elemente in einem vertikalen ListView keine feste Höhe haben, wird contentHeight geschätzt." Ok, aber in meinem Fall haben alle Modellobjekte dieselbe implizite Höhe und der Sektionsdelegat hat auch eine feste Höhe. Ich verwende keine Variablenhöhen für eines meiner Modellelemente oder im Abschnitt delegate, aber ich habe immer noch das gleiche Problem, wenn sich contentHeight dynamisch ändert. – ManuelH

+0

Mein Problem stammt ausschließlich aus der Verwendung des Abschnittsdelegaten. Wenn die Höhe des Delegates auf einen anderen Wert als den impliziten Wert festgelegt wird, wird der Wert contentHeight seltsam berechnet/geschätzt, selbst wenn der Abschnittsdelegat eine feste Höhe hat! – ManuelH

+0

Ihre Abschnittsüberschrift hat eine dynamische Höhe, da sie mit einer Höhe von 50 Pixeln gezeichnet werden kann, wenn sie sich zuerst in der Abschnittsgruppe befindet oder nicht gezeichnet wird, wenn sie nicht das erste Element in der Gruppe ist. Wie gesagt, was passiert, wenn Ihre Sektionen nicht gruppiert werden können - jedes Element fester Größe hat seinen eigenen Kopfbereich fester Größe, so dass nichts dynamisch ist. –

2

Ich weiß, das ist alt, aber ich werde es hier trotzdem beantworten, weil ich nach einer Lösung suchte;

Wenn Sie eine feste Höhe für Ihre Produkte haben, können Sie die Höhe des Behälters dynamisch, indem Sie einfach den Wert durch die Formel festlegen:

MyContainerWithListItems { 
height: MyModel.items.length * height 
} 

Wenn Sie variable Höhe Elemente haben wird es schwieriger sein; Die Lösung besteht wahrscheinlich darin, dass ein onChange-Ereignis eine Funktion auslöst, die durch Ihre Elemente crawlt und die Höhen manuell addiert.

Verwandte Themen