2014-09-09 7 views
5

У меня возникает очень специфическая проблема при использовании элемента ListView QML в сочетании с его свойствами раздела.Qt QML ListView contentHeight поведение

Я использую Qt 4.8.6, но у меня также такая же проблема, когда я пытаюсь это сделать в Qt 5.3.1.

Следующий код также может работать в более ранних версиях Qt, просто изменив оператор импорта в

импорт QtQuick 1.0 (Для < Qt 4.7.4)

или

импорт QtQuick 1.1 (для> = Qt 4.7.4)

Вот автономный случай использования, чтобы продемонстрировать мою проблему:

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 
     } 
    } 

} 

Я использую ListView для отображения списка моделей животных, классифицированного по их размеру. Для достижения этой категоризации в представлении я использую раздел .property, section.critiria и раздел.delegate свойства ListView, реализованные в приведенном выше коде.

(Примечание:. Просьба игнорировать тот факт, что модель я поставляю в ListView не отсортирован, я понимаю, что это создаст многочисленные повторяющиеся записи категории в ListView Это рядом с точкой здесь.)

Когда число моделей превышает видимую область ListView, я использую свойство totalPages, чтобы рассчитать, сколько полных страниц ListView доступно для навигации. Стрелки вверх и стрелки вниз просто уменьшают и увеличивают содержимое .Y ListView по высоте ListView соответственно.

Проблема заключается в том, что contentHeight в ListView не остается статичным, она динамически меняется, и причина моего TOTALPAGES расчета свойства быть неправильными.

Интересно отметить, что такое поведение возникает тогда и только тогда, когда я устанавливаю высоту для моего прямоугольника sectionHeaderDelegate. Если я прокомментирую инструкцию высоты (высота: 50), то contentHeight ListView остается статичным, как и ожидалось - с недостатком, что заголовки/категории разделов теперь находятся поверх текста модели, что совсем не полезно ,

Итак, мой вопрос: почему элемент contentHeight элемента QML ListView динамически изменяется тогда и только тогда, когда я использую делегат раздела, высота которого была установлена ​​на ненулевое значение?

Кроме того, я оставил следующие свойства в ListView для целей тестирования, то ListView следует использовать с стрелками вверх/вниз:

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

ответ

3

Это происходит потому, что ListView оценивает его contentHeight по текущим видимым элементам. Проверьте, что происходит, когда ваши разделы не могут быть сгруппированы. ListView избегает создания экземпляра каждого элемента, поэтому он не знает правильного размера не видимого содержимого. Look at this thread.

+0

Вынос, который я получил из потока, на который вы ссылаетесь, заключается в том, что «когда элементы в вертикальном ListView не имеют фиксированной высоты, оценивается contentHeight». Хорошо, но в моем случае все элементы модели имеют одинаковую неявную высоту, а делегат раздела имеет фиксированную высоту. Я не использую переменную высоту для любого из моих элементов модели или делегата раздела, но у меня все еще есть такая же проблема с динамическим изменением contentHeight. – ManuelH

+0

Моя проблема объясняется исключительно использованием делегата раздела. Установка высоты делегата на что-либо, кроме его неявного значения, приводит к тому, что contentHeight вычисляется/оценивается странно, даже если делегат секции имеет фиксированную высоту! – ManuelH

+0

Заголовок вашего заголовка имеет динамическую высоту, потому что он может быть нарисован с высотой 50 пикселей, если он первый в группе разделов или не будет рисовать, когда он не является первым элементом в группе. Как я уже сказал, посмотрите, что происходит, когда ваши разделы не могут быть сгруппированы - каждый элемент фиксированного размера имеет свой собственный заголовок секции фиксированного размера, так что ничего не динамично. –

2

Я знаю, что это древний, но я все равно отвечу на него, потому что я искал решение;

Если у вас есть фиксированная высота для ваших деталей, вы можете установить высоту контейнера динамически, просто установив значение по формуле:

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

Если у вас есть переменные элементы высоты он будет более трудным; решение, вероятно, должно включать событие события onChange с функцией, которая сканирует ваши объекты и вручную добавляет высоты.

Смежные вопросы