Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Несколько источников данных + одно представление
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Модель/Представление
Анна
Задача:
Есть несколько тоднотипных структур с массивами данных. Данные из массива текущей структуры отображаются во вьювере.

Допустим, один массив во вьювере отображается с 0-го по 5-й элементы, и выбран 3-й элемент, а второй массив отображается с 12-го по 17-й (например, ползователь прокрутил список) и выбран 12-й.
Хочется, чтобы при переключении текущей структуры положение вьюпорта и выбранного элемента соответственно менялось.

Кто должен отвечать за хранение "настроек отображения" для каждой структуры? Вроде бы проще всего отдать всё это на откуп вьюверу. Но не уверена.
lanz
Мне кажется лучше отделить этот код от кода отображения и засунуть его в контроллер - т.е. в то место, где происходит переключение между различными структурами, поскольку вид один, а заводить в нем список структур с ссответствующей инфой по отображению каждой - сильно связывает структуры и вид.

Лучше завести свой контроллер отображения для каждой структуры.
Анна
Мысли вслух:
А если появится второй, третий вьювер... Я их регистрирую в контроллере, и для каждого запоминаю, как именно в нём отображались данные.
Тогда всё будет работать так:
1.Структура стала текущей.
2.Контроллер текущей структуры выполняет действия:
- захватывает на себя сигналы от вьювера "изменился текущий элемент" и от его скроллеров "бегунок переместился"
- "раздаёт пинки" всем, зарегистрированным у него вьюверам -"отобрази с такого-то по такой-то"...
...
Почти универсально для таблицы и списка...

С деревом, где можно свернуть/развернуть элементы такое реализовать проблематично.
-----------------------------------
не бейте меня. Я стараюсь мыслить системно... Гы-гы-гы...
lanz
В контроллере дерева можно хранить дерево свернутых/развернутых узлов например (первое что приходит в голову).

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

то есть, это некий мап

std::map<указатель_на_объект, структура_описания_свойств_отображения_объекта>
Анна
Алексей1153, а что вы подразумеваете под "указатель_на_объект" ?
у вьювера уже есть модель...
Я думала, что можно одной и той же модели в качестве источника данных подсовывать разные структуры. Таким извращением не занималась, пока что. Это чисто теоретические изыскания.
Однажды столкнулась с тем, что вювер как-то неадекватно повёл себя при смене модели "на ходу". Отсюда и растут ноги моих рассуждений.

структура1\ / (вьювер2)
структура2--- модель --- вьювер1
структура3/ ...

Сдаётся мне, всё это фигня и извращение.

Немножко поразмышляла.
Думаю, нужен симбиоз ваших двух предложений:

сделать std::map<пара_указателей_источник_данных_вьювер, труктура_описания_свойств_отображения_объекта>,
но не во вьювере, а в контроллере, который будет наблюдать за вьювером, и фиксировать его действия.
lanz
Цитата
Однажды столкнулась с тем, что вювер как-то неадекватно повёл себя при смене модели "на ходу"


Вот это поворот! А не вспомните случайно подробности?
Вью вроде бы все делает как надо
(в фолде исходники qt 4.8 )
Раскрывающийся текст
void QAbstractItemView::setModel(QAbstractItemModel *model)
{
    Q_D(QAbstractItemView);
    if (model == d->model)
        return;
    if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
        disconnect(d->model, SIGNAL(destroyed()),
                   this, SLOT(_q_modelDestroyed()));
        disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
                   this, SLOT(dataChanged(QModelIndex,QModelIndex)));
        disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
                   this, SLOT(_q_headerDataChanged()));
        disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
                   this, SLOT(rowsInserted(QModelIndex,int,int)));
        disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
                   this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
        disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
                   this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
        disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
                   this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
        disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
                   this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
        disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
                   this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
        disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
                   this, SLOT(_q_columnsInserted(QModelIndex,int,int)));

        disconnect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
        disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
    }
    d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel());

    // These asserts do basic sanity checking of the model
    Q_ASSERT_X(d->model->index(0,0) == d->model->index(0,0),
               "QAbstractItemView::setModel",
               "A model should return the exact same index "
               "(including its internal id/pointer) when asked for it twice in a row.");
    Q_ASSERT_X(!d->model->index(0,0).parent().isValid(),
               "QAbstractItemView::setModel",
               "The parent of a top level index should be invalid");

    if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
        connect(d->model, SIGNAL(destroyed()),
                this, SLOT(_q_modelDestroyed()));
        connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
                this, SLOT(dataChanged(QModelIndex,QModelIndex)));
        connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
                this, SLOT(_q_headerDataChanged()));
        connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
                this, SLOT(rowsInserted(QModelIndex,int,int)));
        connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
                this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
        connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
                this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
        connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
                this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
        connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
                this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
        connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
                this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
        connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
                this, SLOT(_q_columnsInserted(QModelIndex,int,int)));

        connect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
        connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
    }

    QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
    connect(d->model, SIGNAL(destroyed()), selection_model, SLOT(deleteLater()));
    setSelectionModel(selection_model);

    reset(); // kill editors, set new root and do layout
}
Алексей1153
Анна, указатель - это буквально указатель )

поскольку список текущих настроек отображений объектов не может принадлежать самим объектам (будет конфликт), то этот список должен быть у вьюера. Причём важно своевременно синхронизировать список при удалении/добавлении наблюдаемых объектов. Либо при доступе проверять, есть ли такой указатель в штатном кутешном списке вьюера.
И отсюда вытекает более правильное, на мой взгляд решение: менеджер объектов и вьюеров. У него есть список объектов, список вьюеров и список настроек

class manager
{

//структура настроек отображения
struct s_options
{
};

typedef std::map<object_id, object_pointer > td_obj_list;
typedef std::map<viewer_id, viewer_pointer> > td_view_list;
typedef std::map<object_id, std::map<viewer_id, s_options> > td_obj_view_list;

td_obj_list   m_obj_list;//список объектов
td_view_list  m_view_list;//список вьюеров
td_obj_view_list   m_obj_view_list;//ассоциация

public:
//методы работы с массивами - создание объектов, удаление, доступ
};

первичен объект, для него может быть несколько вьюеров, для вьюера сопоставлена структура настроек

Оцени, насколько это будет тебе удобно



смена модели вроде работает, только надо не забывать явно отцепить предыдущую, удалить её и потом прицепить новую, затем reset()

вот в деструкторах встречал падЁж, если явно не отцепить модель. Сильно тогда не вникал, почему так, просто сделал ручное удаление модели перед разрушением таблицы
lanz
Цитата
И отсюда вытекает более правильное, на мой взгляд решение:


Ну, Анна по моему то же самое предлагает:
Цитата
сделать std::map<пара_указателей_источник_данных_вьювер, труктура_описания_свойств_отображения_объекта>,
но не во вьювере, а в контроллере, который будет наблюдать за вьювером, и фиксировать его действия.


Цитата
смена модели вроде работает, только надо не забывать явно отцепить предыдущую, удалить её и потом прицепить новую, затем reset()

Как так? Вон в исходниках делается reset(), слоты сигналы только перецепляются и все.
Если вью не является родителем модели, то она и не должна его удалять, не?
Алексей1153
lanz,
Цитата(lanz @ 27.3.2013, 16:38) *
Если вью не является родителем модели, то она и не должна его удалять, не?


там дело же такое - создали на куче модель, присоединили к объекту и забыли. По идее, должна удалять, но на деле там что-то не так происходит, сначала объект удаляется, потом модель лезет по кривой памяти. У меня как-то так и происходило. Поэтому я в деструкторе модель отцеплял, тогда не падало
lanz
Не не не, вьюха не может удалять модель, а если она одна на несколько вьюх? Тут что то не связанное с привязкой (мы ведь про setModel() говорим?).
Алексей1153
lanz, ну да. Тогда согласен ) Просто у меня был несложный случай - одна модель и одно представление
Анна
Цитата(Алексей1153 @ 27.3.2013, 14:16) *
И отсюда вытекает более правильное, на мой взгляд решение: менеджер объектов и вьюеров. У него есть список объектов, список вьюеров и список настроек

Ну, в общем это и есть контроллер, причём он получает указания от третей стороны (той, которая меняет текущий объект), а пинает модель (сделай этот объект текущим) и вьюверы (перерисуйтесь в соответствии с этими установками)

В общем, мы получили Модель-Контроллер-Представление, у которой Представление само является Модель-Представление.



Цитата(lanz @ 27.3.2013, 11:22) *
Цитата
Однажды столкнулась с тем, что вювер как-то неадекватно повёл себя при смене модели "на ходу"

Вот это поворот! А не вспомните случайно подробности?

Цитата(Алексей1153 @ 27.3.2013, 14:43) *
там дело же такое - создали на куче модель, присоединили к объекту и забыли. По идее, должна удалять, но на деле там что-то не так происходит, сначала объект удаляется, потом модель лезет по кривой памяти. У меня как-то так и происходило. Поэтому я в деструкторе модель отцеплял, тогда не падало

Что-то такое и у меня было. Да. было два экземпляра QStandardModel с разной начинкой. Предполагала, что один вьювер будет отображать, то одну то, другую модель. А он при смене модели убивал предыдущую. Естественно, при попытке обратиться к убитой модели всё падало. Это было в Qt-4.4.0 два года назад. Не уверена, что точно вспомнила ситуацию. Возможно, я пыталась менять модель у сортирующей модели... Но то, что связка образовывалась раз и на всегда и смене на ходу не подлежала, это точно.
Алексей1153, а как модель отсоединяли? Вроде бы такой функции нет, во всяком случае в 4.4.0.
lanz
Цитата
А он при смене модели убивал предыдущую.


Не не не :lol: , совсем недавно видел рабочий код, который на горячую модели меняет. Если никаких дополнительных отношений (только setModel), то все в порядке.
Из Qt 4.4:
Цитата
void QAbstractItemView::setModel ( QAbstractItemModel * model ) [virtual]
Sets the model for the view to present.
Note: The view does not take ownership of the model unless it is the model's parent object because it may be shared between many different views.
Note: This function will also create and set a new selection model, replacing any previously set with setSelectionModel(), but the old selection model will not be deleted.

Может это баг был в 4.4.0.

И QAbstractProxyModel не удаляет...
Анна
Цитата(lanz @ 28.3.2013, 16:39) *
И QAbstractProxyModel не удаляет...

Да, наверное, что-то путаю. Но то, что происходило неожиданное для меня удаление это точно. А кто удалял, не помню и кода не сохранилось.
Алексей1153
Анна, setModel(0)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2020 IPS, Inc.