Как сделать гиперссылку на элемент в QAbstractItemModel? - PullRequest
0 голосов
/ 25 апреля 2019

Используемые версии Qt: 4.7.1 и 4.8

Я храню иерархические данные в виде узлов в модели, производной от QAbstractItemModel. У меня есть QTreeView в графическом интерфейсе приложения для отображения иерархических данных. (Для этого вопроса иерархические данные могут быть несущественными; общая проблема, с которой я столкнулся, относится к любым данным в любой модели и представлении.)

У меня есть текстовое поле (виджет QPlainTextEdit, но это не обязательно) в графическом интерфейсе приложения, в котором отображается гиперссылка. Когда пользователь нажимает на гиперссылку, я могу перехватить это и получить URL гиперссылки. Пока все хорошо.

Когда я перехватываю эту гиперссылку, я заставлю QTreeView перейти к определенному узлу, расширяя его родителей по мере необходимости, чтобы пользователь мог его видеть.

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

<a href="node://something">Click me to see node A</a>

Итак, вопрос в том, что может идентифицировать этот конкретный узел и может быть закодировано как текстовая строка?

Я читал о QPersistentModelIndex. Это звучит как разумная вещь для начала. В то время, когда я форматирую гиперссылку, я определенно знаю QModelIndex конкретного узла и могу из него построить QPersistentModelIndex. Но я заблудился о том, как преобразовать это в строку, а затем позже преобразовать строку обратно в QModelIndex, из которого я могу вывести конкретный узел.

Любые предложения приветствуются.

Ответы [ 2 ]

2 голосов
/ 25 апреля 2019

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

//MyModel.h
class MyModel : public QAbstractItemModel
{
    enum MyRoles {
         UrlRole = Qt::UserRole
    };
    // (...)
}

//MyModel.cpp
QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == UrlRole)
    {
        return "uniqueUrl"; //Up to you to decide what you return here
    }
    // (...)
}

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

QModelIndex MyDialog::getIndexForUrl(QString myUrl)
{
    QModelIndex index = QModelIndex();
    QModelIndexList resultList = ui->treeView->model()->match(QModelIndex(),
        MyModel::UrlRole, "uniqueUrl", 1, Qt::MatchFixedString | Qt::MatchCaseSensitive);

    if (!resultList.empty())
    {
        index = resultList.first();
    }
    return index;
}

Возможно, вам потребуется настроить флаги и начальный индекс в зависимости от того, как вы определили модель.

1 голос
/ 25 апреля 2019

Использование QAbstractItemModel::match() для поиска элементов в модели данных с помощью пользовательской роли данных, как предлагает @Cendolt, является отличной идеей. Я смог использовать эту идею без необходимости переопределять match() в моей пользовательской модели данных.

Параметры, которые я предоставляю QAbstractItemModel::match(), немного отличаются. В сочетании с остальной частью примера @ Cendolt, следующее работает для моей ситуации.

QAbstractItemModel * pModel = ...;

// Start searching from the root of the tree.
QModelIndex startIndex = pModel->index( 0, 0 );

QModelIndexList results = p->match(
  startIndex,
  MyModel::UrlRole,
  "uniqueUrl",
  1,
  Qt::MatchRecursive );

Действительный индекс начала

Указание начального QModelIndex с нулями для строки и столбца необходимо для того, чтобы поиск вообще продолжался. Когда я использовал построенный по умолчанию QModelIndex, поиск никогда не вызывал метод data() моей модели. Я полагаю, что это потому, что построенный по умолчанию QModelIndex имеет -1 для строки и столбца, что делает его недопустимым индексом. В коде для QAbstractItemModel::match() ({Qt dir} \ src \ corelib \ kernel \ qabstractitemmodel.cpp) обратите внимание, что он пропускает вызов data(), если индекс недействителен.

Флажки матча

Специально для иерархических данных необходимо использовать флаг Qt::MatchRecursive. В противном случае поиск не сканируется на дочерние узлы.

...