2016-08-03 5 views
3

Я следующий this учебник (без flickable содержания в каждой записи) для Qt 4.8 при использовании Qt 5,7 с QtQuick 2.0. Образом ListView там работает следующим образом:QML ListView - изменить все, кроме текущего элемента

  1. Пользователь нажимает на элемент в списке
  2. Alternative (детальный) вид элемента отображается
  3. Пользователь должен нажать на Close кнопку в детализированном виде, чтобы сбросить состояние входа в компактный вид по умолчанию.

Это приводит к беспорядку, когда в какой-то момент, если пользователь нажимает на все предметы, в этом случае все будет отображаться в их полном представлении. Если пользователь нажимает кнопку Close каждый раз, когда он открывает подробный вид, это также (omho) не так удобно.

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

  1. пользователь щелкает по пункту в списке
  2. Альтернативный вид элемента отображается
  3. пользователь щелкает на детализированном виде, чтобы сбросить состояние входа в состояние по умолчанию компактный вид ИЛИ
  4. Пользователь нажимает на другую запись и все в настоящее время в подробных записях просмотра сбрасываются компактному зрения

В настоящее время я перебираю ListViewcontentItem.children[loop_index] и устанавливаю состояние на "" ("Details" = Показать детальный вид | "" = показать компактный вид). Из-за того, как работает ListView (загрузка/выгрузка делегатов по запросу), это довольно ненадежно, и я часто получаю неопределенную ссылку, когда пытаюсь получить доступ к состоянию других делегатов. Следующий MouseArea, который я использую, чтобы сделать все, что является частью каждого делегата:

// state is a QML `State` that is bound to the delegate (see below for the details on it) 
MouseArea { 
    anchors.fill: background 
    onClicked: { 
     // Iterate through all other entries and close them 
     for (var entry = 0; entry < listView.count; ++entry) { 
      if(listView.contentItem.children[entry] !== gestureEntry) { 
       console.log("Hide other element"); 
       listView.contentItem.children[entry].state = ""; // IT FAILS HERE (SOMETIMES) 
      } 
     } 

     // Change view of current entry 
     if(gestureEntry.state === "Details") { 
      gestureEntry.state = ""; 
      console.log("Hiding details") 
     } 
     else { 
      gestureEntry.state = "Details"; 
      console.log("Showing details"); 
     } 
    } 
} 

с state быть государством делегата:

states: State { 
    name: "Details" 

    PropertyChanges { target: background; color: "white" } 
    PropertyChanges { target: gestureImage; width: 130; height: 130 } // Make picture bigger 
    PropertyChanges { target: gestureEntry; detailsOpacity: 1; x: 0; y: 0 } // Make details visible 
    PropertyChanges { target: gestureEntry; height: listView.height } // Fill the entire list area with the detailed view 
} 

Я имею в виду, что state информация может храниться внутри самого ListModel, что позволяет выполнять итерацию содержимого модели (которая всегда присутствует в отличие от содержимого делегатов), однако я не знаю, как автоматически обновлять список (и в настоящее время видимых/невидимых делегатов), когда изменения записи в модели. Из того, что я нашел до сих пор, кажется невозможным сделать это, поскольку ListView не активно отслеживает его ListModel.

Действительно ли это так? Если да, то можно ли решить эту проблему по-другому?

ответ

1

Почему вы не используете свойство currentIndex своего ListView? Просто измените делегат, как это:

Item { 
    id: gestureEntry 
    ... 
    state: ListView.isCurrentItem?"Details":"" 
    ... 
    MouseArea { 
     anchors.fill: background 
     onClicked: { 
      if(listView.currentIndex == index) 
       listView.currentIndex = -1 
      else 
       listView.currentIndex = index 
     } 
    } 
} 

EDIT: Единственная проблема с выше решения заключается в том, что - при загрузке - запись в ListView уже выбран автоматически запускает подробный обзор этой записи. Для того, чтобы избежать этого следующие потребности быть добавлены к listView:

Component.onCompleted: { 
    listView.currentIndex = -1; 
} 

Это гарантирует, что запись не будет предварительно.

+0

Ах, подождите. Теперь закрытие при нажатии на запись не работает ... XD Мне действительно нужно 'if-else' внутри' onClicked'. Однако это нарушает ваше решение. : -/ – rbaleksandar

+0

Отредактировал свой ответ. Надеюсь, это сработает на этот раз :) – Yoann

+0

Остается только проблема, что при первом загрузке «ListView» первая запись (я думаю, тот, который предварительно выбран при загрузке списка) находится в подробном представлении. – rbaleksandar

2

Угадайте, это проблема, потому что вы сохранили состояние в своем делетете. Вы не должны делать это, как описано в delegate -property (Link), потому что делегаты получают повторное использование, когда они выходят из поля зрения.

По крайней мере, вы должны использовать when: ListView.isCurrentItem в состоянии и зависят от значения ListView. Таким образом, максимизируется только ваш текущий делегат. Затем в MouseArea устанавливается только «ListView.view.currentIndex = index». Не изменить состояние вручную в функции!

Я столкнулся с той же проблемой, полностью удалил штаты и просто использовал прикрепленное свойство ListView.isCurrentItem. Но привязка состояния к значению из ListView также должна работать, потому что он не хранится в делегате.

Минимальный пример:

import QtQuick 2.0 

Item { 
    width: 800 
    height: 600 

    ListView { 
     id: view 
     anchors.fill: parent 
     model: 3 
     spacing: 5 
     currentIndex: -1 
     delegate: Rectangle { 
      id: delegate 
      color: ListView.isCurrentItem ? "lightblue" : "green" // directly change properties depending on isCurrentItem 
      height: 100 
      width: 100 

      states: State { 
       name: "maximized" 
       when: delegate.ListView.isCurrentItem // bind to isCurrentItem to set the state 
       PropertyChanges { 
        target: delegate 
        height: 200 
       } 
      } 
      MouseArea { 
       anchors.fill: parent 
       //onClicked: delegate.ListView.view.currentIndex = model.index // if only selection is wanted 
       onClicked: { 
        //console.debug("click"); 
        if (delegate.ListView.isCurrentItem) 
        { 
         delegate.ListView.view.currentIndex = -1; 

        } 
        else 
        { 
         delegate.ListView.view.currentIndex = model.index; 
        } 
       } 
      } 
      Text { 
       anchors.centerIn: parent 
       text: index 
      } 
     } 
     Text { 
      text: "CurrentIndex: " + parent.currentIndex 
     } 
    } 
} 
+0

Я получаю 'TypeError' в' ListView.view.currentIndex = index; ' – rbaleksandar

+0

Я также попытался изменить его на' listView.view.currentIndex = index; '(поскольку мой' ListView' имеет этот ID, но проблема по-прежнему присутствует. – rbaleksandar

+0

ListView получает привязку к вашему элементу-элементу-делегату в качестве индекса. Возможно, вам нужно явно использовать 'delegateId.ListView.currentIndex = delegateId.index' или даже вызывать сигнал в делетете там должен работать. Я использовал его много, и он определенно работает здесь, используя Qt 5.5.1. –

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