Russian Qt Forum
Ноябрь 23, 2024, 02:43 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО] QStandardItemModel QSortFilterProxyModel QThread  (Прочитано 7872 раз)
vintik
Гость
« : Июль 30, 2013, 00:25 »

Привет!
Столкнулся со следующей проблемой.
Есть вьюха и модель. Данные в модель поступают по сигналу, очень часто. Захотел засунуть модель и обработку входных сигналов в отдельный поток. Сделал это примерно так
Код:
Widget::Widget(QWidget *parent)
    : QWidget        (parent)
    , view_          (new QTableView(this))
    , data_generator_(new data_generator(this))
    , model_         (new QStandardItemModel())
    , thread_        (new QThread())
{
    view_->setModel(model_);
    connect(data_generator_, SIGNAL(data(double)), model_, SLOT(on_data(double)));
    model_->moveToThread(thread_);
    thread_->start();
}

Widget::~Widget()
{
    thread_->quit();
    thread_->wait();
    
    delete model_;
    delete thread_;
}

Это работает.
Захотелось применить прокси модель для фильтрации данных. И тут начались проблемы. Программа собирается, не ломается, но фильтрация работает криво. Если модель не мувить в поток, работает как ожидалось.
Думаю, что в данной ситуации неправильно использую прокси модель. Но где именно ошибка понять не могу.

Код:
Widget::Widget(QWidget *parent)
    : QWidget        (parent)
    , view_          (new QTableView(this))
    , data_generator_(new data_generator(this))
    , proxy_model_   (new QSortFilterProxyModel(this))
    , model_         (new QStandardItemModel())
    , thread_        (new QThread())
{
    connect(data_generator_, SIGNAL(data(double)), model_, SLOT(on_data(double)));
    proxy_model_->setSourceModel(model_);
    view_->setModel(proxy_model_);
    
    model_->moveToThread(thread_);
    thread_->start();
}

Widget::~Widget()
{
    thread_->quit();
    thread_->wait();
    
    delete model_;
    delete thread_;
}

« Последнее редактирование: Июль 31, 2013, 17:41 от vintik » Записан
popper
Гость
« Ответ #1 : Июль 31, 2013, 13:40 »

Предлагаю попробовать moveToThread поместить перед connect(...)
Записан
mutineer
Гость
« Ответ #2 : Июль 31, 2013, 13:46 »

Предлагаю попробовать moveToThread поместить перед connect(...)
Что это должно дать?

Вообще не правильно просто разнести модель и прокси-модель в разные потоки - прокси-модель делает прямые вызовы в основную модель за данными, поэтому нужны будут блокировки. Лучше чтобы модель жила в основном потоке
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Июль 31, 2013, 15:07 »

Что это должно дать?
Qt определит, что объект модели должен жить в другой нитке и будет использовать QueuedConnection.
Записан
mutineer
Гость
« Ответ #4 : Июль 31, 2013, 15:10 »

Что это должно дать?
Qt определит, что объект модели должен жить в другой нитке и будет использовать QueuedConnection.

Это проверяется в момент эмита сигнала, а не в момент коннекта
Записан
vintik
Гость
« Ответ #5 : Июль 31, 2013, 15:49 »

Предлагаю попробовать moveToThread поместить перед connect(...)
Что это должно дать?

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

Я пробовал сделать так.
Создал класс, унаследованный от QSortFilterProxyModel - proxy_model. В этом классе мембером сделал QStandardItemModel и установил её в качестве sourceModel.
Потом, установил прокси модель во вьюху. И сделал мув прокси модели в отдельный поток.

На маленьком тестовом примере - всё заработало как надо. А когда я попытался перенести такой подход в большой проект - программа начала постоянно валиться.
Природа поломки мне осталась не ясна, но происходило это как правило в момент вставки данных в модель.
В данном проекте очень часто происходит добавление/удаление данных в модели.

Коллеги подсказали, что вообще кутешная model/view НЕ потокобезопасна. и что, видимо, нужно очень внимательно синхронизировать данные.
Дальше пока не продвинулся.. как-то так
Записан
mutineer
Гость
« Ответ #6 : Июль 31, 2013, 16:09 »

Не мувай модели в треды, пусть живут в главном. Переработай схему добавления данных в модель
Записан
vintik
Гость
« Ответ #7 : Июль 31, 2013, 17:29 »

Не мувай модели в треды, пусть живут в главном. Переработай схему добавления данных в модель

Расскажу из-за чего сыр-бор. Есть модель куда очень часто поступают данные. Модель сделана для отображения данных в виде дерева в QTreeView. Есть ещё прокси модель, чтобы была возможность фильтровать данные. Когда данных становится - много приложение тормозит.
Я почему-то решил, что если кухню моделей засунуть в отдельный поток, то всё наладится.
Отсюда и возник топик.

Но теперь, как я понимаю, подобная затея порочна? (т.к. порой из вьюхи происходит обращение к модели непосредственно, без сигналов/слотов  и данные могут рассинхронизироваться)
следует модель, прокси модель и вьюху содержать в одном потоке. а работу приложения ускорять различными оптимизациями?
« Последнее редактирование: Июль 31, 2013, 17:31 от vintik » Записан
mutineer
Гость
« Ответ #8 : Июль 31, 2013, 17:31 »

Если данные поступают очень часто, то нет нужды их пихать в модель по факту прихода - все равно этого не видно будет на экране. Сделай некий буфер, в котором копи поступающие данные, а в модель их передавай раз в некоторое время, например раз в 500 мс
Записан
vintik
Гость
« Ответ #9 : Июль 31, 2013, 17:32 »

Если данные поступают очень часто, то нет нужды их пихать в модель по факту прихода - все равно этого не видно будет на экране. Сделай некий буфер, в котором копи поступающие данные, а в модель их передавай раз в некоторое время, например раз в 500 мс

да, это мысль! попробую реализовать)

и всё-таки для ясности - о потоках забыть для этого случая?
Записан
mutineer
Гость
« Ответ #10 : Июль 31, 2013, 17:35 »

Копить данные можно в потоке, но модель и вью должны жить в одном потоке
Записан
vintik
Гость
« Ответ #11 : Июль 31, 2013, 17:41 »

Копить данные можно в потоке, но модель и вью должны жить в одном потоке

я понял, спасибо большое!
Записан
Sasha
Гость
« Ответ #12 : Декабрь 10, 2013, 12:53 »

У меня тоже примерно такая же проблемма. Пошёл под отладчиком и пришёл к выводу, что причина ряда проблемм в том, что, например, прокси-модель следит за изменениями основной модели для чего коннектит сигналы основной модели к своим слотам, НО не все эти сигналы могут быть QueuedConnection. Кажется, такими не могут быть, например, имеющие в параметрах QModelIndex. Вот и получается, что сигналы не доходят. Но там, по-моему, и более серьёзные проблеммы есть, приводящие к падениям, а не просто к неправильному отображению, когда один поток использует данные, которые другой поток уже удалил.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.051 секунд. Запросов: 23.