Russian Qt Forum

Qt => Qt Quick => Тема начата: SektorCT от Ноябрь 10, 2023, 18:11



Название: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 10, 2023, 18:11
Всем привет.
Есть treeView в котормо рисуется bookmark дерево. Есть оглавления и под оглавления, и само собою можно арскрывать их.
Со стороны логики прилетает изменение номера текущей страницы и я в этмо случаи должен отметить в модели цветом нужный пункт, но этого не происходит.
Вопрос: как обновить модель без beginResetModel() и endResetModel()? Или как сохранить состояние открытых пунктов?

Благодарю.


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: kambala от Ноябрь 10, 2023, 20:26
можно попробовать поменять свойство айтема напрямую через itemAtCell() / itemAtIndex(), но подход с обновлением модели мне кажется более правильным. Как сохранить состояние пунктов — ну ручками и сохранить :) и в модели возвращать сохраненное состояние для соответствующей роли.


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 11, 2023, 17:28
(https://ibb.co/9N414WJ)
Вот на первой картинке тут на 1 страние 3 раздела, под намерами 1, 1.1 и 1.2.
Само собою границами отмечается у меня все пункты что на 1 странице, то есть на текушей.

(https://ibb.co/S5JGTt7)
На второй такой же случай, на 1 странице несколько пунктов, они отмечены.

(https://ibb.co/zJcFVqp)
Проблема возникает если я выбираю пункт уже из открытой ветки, то есть модель не перерисовывается.

Это я для уточнения привел пример.


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: kambala от Ноябрь 11, 2023, 23:21
картинок нет, да суть проблемы и так ясна: у тебя меняются данные модели, что должно привести к изменению отображения, но ничего не меняется, потому что, судя по всему, ты не отправляешь сигнал dataChanged


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 11, 2023, 23:38
 :'(
картинок нет, да суть проблемы и так ясна: у тебя меняются данные модели, что должно привести к изменению отображения, но ничего не меняется, потому что, судя по всему, ты не отправляешь сигнал dataChanged

Странно  картинками, отправляю еще раз
https://ibb.co/9N414WJ (https://ibb.co/9N414WJ)

https://ibb.co/S5JGTt7 (https://ibb.co/S5JGTt7)


https://ibb.co/zJcFVqp (https://ibb.co/zJcFVqp)

На третей нажат пункт 2.5.4 и так как на даннйо странице присутствует только данный пункт то границы должны были быть у него, но ничего ни меняется. Только темным цветом окрашивается та часть куда я нажимаю.


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 11, 2023, 23:47
картинок нет, да суть проблемы и так ясна: у тебя меняются данные модели, что должно привести к изменению отображения, но ничего не меняется, потому что, судя по всему, ты не отправляешь сигнал dataChanged

Не могли бы обьяснить как я должен этот сигнал использовать? А точнее в каком месте? Я смотрел там у него аргументы индексы и роль.


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: kambala от Ноябрь 12, 2023, 10:10
насколько я понимаю, логика должна быть такая:
1. тыкаем в раздел
2. в модели меняется текущая страница
3. модель сообщает, что какие-то ее данные изменились
4. это приводит к автоматическому обновлению / перерисовке тривью

вот сигнал dataChanged как раз для п.3 и служит. ты должен определить какой элемент (индекс) изменился, также опционально можно указать какая именно роль изменилась. beginResetModel можно использовать как альтернативу, если меняется много индексов сразу:
Цитировать
When a model radically changes its data it can sometimes be easier to just call this function rather than emit dataChanged() to inform other components when the underlying data source, or its structure, has changed.

код начнешь показывать или так и будем сидеть рассуждать? :)


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 12, 2023, 15:14

код начнешь показывать или так и будем сидеть рассуждать? :)

Да, надо было сразу кинуть.
Так, тут qml часть и делегат дял которого и роль нужная мне и нажатие(хотя оно думал не нужно в решении данной проблемы)
Код:
delegate: Item
{
    id: treeDelegate

    implicitWidth: padding + text.x + text.implicitWidth + padding
    implicitHeight: text.height

    property var delegateIndex : treeDelegate.treeView.index(row, column)

    readonly property real indent: 20
    readonly property real padding: 5

    required property TreeView treeView
    required property bool isTreeNode
    required property bool expanded
    required property bool selected
    required property int hasChildren
    required property int depth

    Item
    {
        id: rectIndicator

        height: parent.height
        width: height
        anchors.verticalCenter: parent.verticalCenter

        x: padding + (treeDelegate.depth * treeDelegate.indent)
        visible: treeViewBookmark.model.isHasChild(treeDelegate.delegateIndex)

        Image
        {
            id: indicator

            anchors.fill: parent
            height: 5
            verticalAlignment: Image.AlignVCenter
            horizontalAlignment: Image.AlignHCenter
            source: model.eIndicator
            rotation: treeDelegate.expanded ? 90 : 0
        }
    }

    Rectangle
    {
        id: labelRect

        color: treeViewBookmark.idx === treeDelegate.delegateIndex ? model.eColorBackgroundWithoutChild : style.hovered ? model.eColorBackgroundWithChild : "transparent"
        border.width: 1
        border.color: model.eBorderColor // вот эта ролько обработка которой и нужна
        width: text.width
        height: text.height

        x: padding + (treeDelegate.isTreeNode ? (treeDelegate.depth + 1) * treeDelegate.indent : 0)

        HoverHandler
        {
            id: style
        }

        Text
        {
            id: text

            clip: true
            text: model.display
            color: model.eValueTextColor

            font.pixelSize: 10 // constant from XD
            antialiasing: true
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
        }

        TapHandler
        {
            acceptedButtons: Qt.LeftButton
            onTapped:
            {
                treeViewBookmark.toggleExpanded(row)

                var numberPage = treeViewBookmark.model.page(delegateIndex)
                root.pelData.signalUpdateCurrentPage(numberPage)
            }
        }
    }

Тут С++ часть с использованием роли и той переменнйо что отвечает за текузий номер страницы что прилетает из логики
Код:
void CC2gdocv_CustomPdfBookmarkModel::setCurrentPage(int currentPage)
{

    m_SelectedCurrentPage.setValue(currentPage);
}

QBindable<int> CC2gdocv_CustomPdfBookmarkModel::getCurrentPage()
{
    return &m_SelectedCurrentPage;
}

QVariant CC2gdocv_CustomPdfBookmarkModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return QVariant{};
    }

    if (role == Qt::DisplayRole)
    {
        role = Qt::UserRole + index.column();
    }

    switch (role)
    {
        case static_cast<int>(RoleAttributes::eNameRole):
        {
            return QPdfBookmarkModel::data(index, role).toString();
        }
        case static_cast<int>(RoleAttributes::ePageRole):
        {
            auto localRole = static_cast<int>(QPdfBookmarkModel::Role::Page);
            auto localRoleTitle = static_cast<int>(QPdfBookmarkModel::Role::Title);
//                auto localIndex = QPdfBookmarkModel::index(index.row(), 0, index);

            qDebug() << "DATA role page: " << QPdfBookmarkModel::data( index, localRole).toInt() + 1 << QPdfBookmarkModel::data( index, localRoleTitle).toString();

            return QPdfBookmarkModel::data( index, role).toInt() + 1;
        }
        case static_cast<int>(RoleAttributes::eBorderColor):
        {
            auto localRole = static_cast<int>(QPdfBookmarkModel::Role::Page);

            const int intNumberPage =  QPdfBookmarkModel::data( index, localRole).toInt();

            qDebug() << intNumberPage << ": " << m_SelectedCurrentPage.value();

            if(intNumberPage == m_SelectedCurrentPage.value())
            {
                return QVariant::fromValue(getColorBorder() );
            }
            else
            {
                return QVariant::fromValue(QColor(Qt::transparent ));
            }

//                qDebug() << "DATA role page: " << QPdfBookmarkModel::data( index, localRole).toInt() + 1;


        }
        default:
            break;
    }

    return QVariant{};
}


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: kambala от Ноябрь 12, 2023, 18:52
страница у тебя влияет на роль eBorderColor, значит при изменении страницы надо послать dataChanged для старых и новых выделенных индексов с указанием этой роли (видимо внутри setCurrentPage())


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 12, 2023, 21:07
страница у тебя влияет на роль eBorderColor, значит при изменении страницы надо послать dataChanged для старых и новых выделенных индексов с указанием этой роли (видимо внутри setCurrentPage())

Я не совсем понимаю что значит "для старых и новых индексов". То что 3 аргумент это роль я понял(хотя сигнал принимает QList ролей а не одну роль), но вот два первых аргумента индексы я тут немного в замешательстве.
Метод setCurrentPage() получает аргументом новую текущую страницу из другого класса. Это я решил обьяснить если этот класс важен.
Или могли бы вы этот кусов кода написать для демонстрации?


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: kambala от Ноябрь 12, 2023, 22:56
метод CC2gdocv_CustomPdfBookmarkModel::data() принимает индекс, для которого рассчитывается значение переданной роли, у тебя там для eBorderColor есть логика определения каким цветом выделять заданный индекс. А теперь тебе надо по сути сделать обратную операцию: по заданному номеру страницы определить каким индексам модели она соответствует, таким образом ты сможешь получить как старые индексы (те, что выделены сейчас), так и новые (для новой страницы в setCurrentPage). По коду кажется, что можно просто пробежаться по всем доступным индексам и выполнить код, который сейчас у тебя для eBorderColor, но может можно и как-то быстрее (зависит от твоей внутренней логики и доступных данных).


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: SektorCT от Ноябрь 12, 2023, 23:51
... А теперь тебе надо по сути сделать обратную операцию: по заданному номеру страницы определить каким индексам модели она соответствует,

То есть мне надо найти все индыксы где есть соответствие со страницей текущей? А как это сделать?)
В голову приходит только идеть еще контейнер с ключ(страница) и значение(индекс).

В общем я заполнил вот такой контейнер QMap<int, QList<QPersistentModelIndex>* >* m_pBookmarkMap;
И получается что в нужном мне кейсе под нужнйо ролью мне надо пройти данный контейнер, по ключу страницы найти индексы и заменить?
А что с ролями та делать? Там же лист ролей


Название: Re: Перерисовка модели в TreeView с сохранением состояния
Отправлено: kambala от Ноябрь 13, 2023, 12:10
как сделать — это ж ты должен знать, твой код и твоя логика :) Вот для eBorderColor у тебя есть код получения страницы для данного индекса, можно этот код переиспользовать, только сделать цикл по всем доступным индексам (или какому-то их подмножеству, если логика позволяет упрощение) и найти где полученная страница совпадает с текущей.

Если вычисления там тяжелые, то лучше закэшировать, да. Только непонятно зачем ты хранишь указатель на список и указатель на словарь, а не по значению. Дальше просто в setCurrentPage() получаешь список индексов для старой страницы и для новой, и вот эти индексы подаешь в dataChanged.

лист ролей — ну создай лист из одного элемента, в чем проблема :) если подашь пустой список, то будут пересчитаны все роли, что в данном случае не нужно.
Код
C++ (Qt)
QList{{static_cast<int>(RoleAttributes::eBorderColor)}}
// or
QList<int>{} << static_cast<int>(RoleAttributes::eBorderColor)