2015-12-04 3 views
1

Я пытаюсь создать модель списка на основе асинхронной базы данных api. Вот QML пример того, как я хочу, чтобы иметь возможность использовать его:QAbstractListModel: имена ролей обновлений

ListView { 
    id: view; 

    anchors.fill: parent; 

    model: DatabaseModel { 
     id: dmodel 

     query: "SELECT id FROM test" 
     database: "toto.sqlite" 
    } 

    delegate: Label { 
     anchors.horizontalCenter: parent.horizontalCenter; 
     width: view.width/2; 
     height: 30; 
     text: id; 

     color: "teal"; 
    } 
} 

явно в какой-то момент мне нужно больше, чем идентификатор в моей базе данных и более этикетки для отображения этого элемента.

Чтобы иметь возможность использовать «ID» в определении моего ярлыка Я использую имена ролей, как, что:

QHash<int, QByteArray> DatabaseListModel::roleNames() const 
{ 
    QHash<int, QByteArray> b = this->QAbstractItemModel::roleNames(); 

    if (m_query != "" && m_database) { 
     QStringList l = m_database->currentRequestFields(); 
     for (int i = 0; i < l.count(); ++i) { 
      b.insert(Qt::UserRole + i + 1, l.at(i).toLocal8Bit()); 
     } 
    } 
    return b; 
} 

m_database будучи сеанс базы данных «toto.sqlite» в этом случае и m_query быть " SELECT id FROM test ".

Дело в том, что сеанс моей базы данных асинхронен, и m_database->currentRequestFields() недоступен сразу. Однако я получаю сигнал, сообщающий мне, когда это так, я хотел бы обновить список имен роли в данный момент, а не раньше.

Даже если m_database будет, вероятно, выглядеть как черный ящик, вот что мне делать, чтобы обновить модель:

void DatabaseListModel::updateModel() 
{ 
    if (m_query != "" && m_database) { 
     m_mutex.lock(); 
     beginResetModel(); 
     m_cache.clear(); 

     QObject::connect(m_database, &CollaoDatabase::databaseReady, this, [this] (CollaoDatabase* database) { 
      database->setQueryStringi(m_query); 
      database->executei(); //currentRequestFields() becomes available 
      database->fetchAlli(); 
      database->sendNotifierEventi(0); //when everything written before this line has been executed, ask the database to emit CollaoDatabase::notifierEventProcessed. It's not instant and might take a while depending on the query 
     }); 
     QObject::connect(m_database, &CollaoDatabase::resultReady, this, [this] (QVariantMap result) { 
      if (m_cache.size() <= 0) 
       m_cache.reserve(m_database->currentPendingFetches() + 1); 
      m_cache.append(result.values()); 
     }); 

     QObject::connect(m_database, (void (CollaoDatabase::*)())&CollaoDatabase::notifierEventProcessed, this, [this](){ 
      endResetModel(); 
      //TODO: update roleNames here 

      m_mutex.unlock(); 
      m_database = NULL; //as soon as stop() is called, we cannot assume the existance of this object anymore 
      //it is therefore safer to make it null now 
     }); 
     QObject::connect(m_database, SIGNAL(notifierEventProcessed()), m_database, SLOT(stop())); 

     m_database->start(); 
    } 
} 
+1

Ролевые имена должны обновляться до концаResetModel(). Я не уверен, хотя это будет работать надежно, в прошлый раз, когда я отлаживал это, представления QML не могли справиться с изменением имен ролей, даже если они только изменились во время сброса модели. –

+0

Кроме того, я не вижу смысла динамически создавать имена ролей. Как вы планируете обновлять делегат QML для изменения имен ролей? Не могли ли вы использовать «role001» для «role999» и поместить изменения данных столбца SQL в эти фиксированные имена ролей? –

+0

Фактически имена ролей не «обновляются», их инициализация задерживается, но выполняется только один раз.Мне удалось сделать что-то свое, позвонив beginResetModel ПОСЛЕ ТОГО, что currentRequestFields() станет доступным. Как только я смогу удалить «своеобразное» из предыдущего предложения, я опубликую рабочий код – Nyashes

ответ

0

Хорошо, я наконец-то получил такое поведение, которое я хотел, что может задержать первую инициализацию имен ролей моего itemModel. Код по существу то же самое с некоторым переупорядочением. Особенно имена ролей ДОЛЖНЫ быть доступны перед вызовом beginResetModel. вы можете сравнить этот фрагмент с тем, который указан в моем вопросе

void DatabaseListModel::updateModel() 
{ 
    if (m_query != "" && m_database) { 
     m_mutex.lock(); 

     QObject::connect(m_database, &CollaoDatabase::databaseReady, this, [this] (CollaoDatabase* database) { 
      database->setQueryStringi(m_query); 
      database->executei(); 
      database->sendNotifierEventi(1); 
      database->fetchAlli(); 
      database->sendNotifierEventi(0); 
     }); 
     QObject::connect(m_database, &CollaoDatabase::resultReady, this, [this] (QVariantMap result) { 
      if (m_cache.size() <= 0) { 
       m_fields = result.keys(); 
       beginResetModel(); 
       m_cache.reserve(m_database->currentPendingFetches() + 1); 
       m_numRows = m_database->currentPendingFetches() + 1; 
       emit numRowsChanged(); 
       m_progress = 0; 
      } 

      m_cache.append(result.values()); 
      ++m_progress; 
      if (m_progress % (m_numRows/100 + 1) == 0) 
       emit progressChanged(); 
     }); 

     QObject::connect(m_database, (void (CollaoDatabase::*)(int))&CollaoDatabase::notifierEventProcessed, this, [this](int eventIndex){ 
      switch (eventIndex) { 
      case 0: /*terminate*/ 
       emit progressChanged(); 
       endResetModel(); 
       m_mutex.unlock(); 
       m_database->stop(); 
       m_database = NULL; //as soon as stop() is called, we cannot assume the existance of this object anymore 
       //it is therefore safer to make it null now 
       break; 

      case 1: /*now able to reset the model*/ 
       m_cache.clear(); 
       break; 
      } 
     }); 

     m_database->start(); 
    } 
} 
0

одна идея, которая может соответствовать вашим потребностям (предполагаю, что Вы хотите хороший интерфейс для пользователей этой модели и имея запросов на выборку только), чтобы структурировать ваш запрос следующим образом:

  • Строка таблицы
  • String [] столбцы
  • выбор строки
  • String [] selectionArgs
  • Строка группеПо
  • Строка, имеющий
  • Строка OrderBy
  • предел Строка

(идея украдена из http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#query%28java.lang.String,%20java.lang.String[],%20java.lang.String,%20java.lang.String[],%20java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String%29)

Таким образом, ваш простой пример может выглядеть подобные

DatabaseModel { 
    id: dmodel 

    table: "test" 
    colums: ["id"] 
    database: "toto.sqlite" 
} 

Таким образом, у вас есть имена столбцов, доступные на ранней стадии, чтобы использовать их для ролевых наманов.

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