QStandardItemModel* из потока без GUI не выдавал сигнал itemChanged

Я начал загрузку базы данных в потоке без графического интерфейса с помощью QtCuncurrent::run. В этом потоке без графического интерфейса мне нужно создать QStandardItemModel*, после чего я получил модель в графическом потоке с

model = modelWatcher.result();

по сигналу QFutureWatcher Finished(). Это работает довольно хорошо (пользовательский интерфейс построен успешно), но сигнал itemChanged() не испускается при изменении данных элемента (состояние флажка изменилось). Когда я создаю модель в потоке графического интерфейса, коллизий нет. Connect работает без ошибок утверждения:

bool ok = connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(onFolderStateChanged(QStandardItem*)), static_cast<Qt::ConnectionType>(Qt::UniqueConnection));
Q_ASSERT(ok);

Как я вижу в этом потоке (примеров кода нет, и я неправильно понял основная идея) Я не могу создать модель (часть Qt5Gui) в потоке, отличном от Gui. Но это работает для меня! Пользовательский интерфейс построен) Также я должен объявить отправленный тип с помощью:

qRegisterMetaType<QStandardItemModel*>("QStandardItemModel*");

И другие мои отправки, как:

qRegisterMetaType<QList<QTreeWidgetItem*> >("QList<QTreeWidgetItem*>");

работает хорошо (хотя это также часть Qt5Gui).

Я не знаюt understand how can I **get the model from nonGui thread with full functionality** like itemChanged signals? It что-то вроде emit mysignal(QStandardItemModel*); ? В таком случае, почему другие задачи работают нормально без каких-либо излучателей? включая сигналы currentChanged и т. д..


person Meteo ir3    schedule 05.07.2016    source источник


Ответы (2)


Когда я отправляю модель из потока, отличного от Gui, некоторые сигналы теряются, потому что указатель модели и связанные данные неверны, если я не ошибаюсь. Также QStandardItemModel - является частью Qt5Gui и не является потокобезопасным. Это означает, что модель и представление должны быть собраны в GUI-потоке, а данные должны быть отправлены из рабочего потока и привязаны к модели в GUI-потоке. В моей ситуации это не просто - у меня большое дерево, и я не хочу создавать свою собственную структуру для разбора дерева - но это "верный способ"). Я использую более простое решение — я просто отправляю указатель parentItem на новую модель в потоке GUI — и это работает. Если кто-то знает, как просто отправить древовидную структуру из рабочего потока - расскажите об этом в этой теме) В любом случае - с использованием текстового представления данных между потоками - его более предпочтительный метод (например, JSON/XML... любое собственное представление, основанное на по индексам элементов, перечисленных в ``QList>` и т.д...)

person Meteo ir3    schedule 08.07.2016

Вы пробовали это?

bool ok = connect(model, SIGNAL(itemChanged(QStandardItem*)), this,
SLOT(onFolderStateChanged(QStandardItem*)),
static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)); 
person Fryz    schedule 05.07.2016
comment
Может быть, мне нужно сделать model-›moveToThread(this-›thread()); или что-то другое.. ? Если я создам модель в потоке пользовательского интерфейса, мне нужно отправить все зависимые данные в поток графического интерфейса из рабочего потока. Правильно ли это? - person Meteo ir3; 06.07.2016
comment
Действительно, если вы хотите, чтобы ваш слот выполнялся в отдельном потоке без графического интерфейса, рекомендуется подход с рабочим потоком, как описано здесь doc.qt.io/qt-5/qthread.html - person Fryz; 06.07.2016
comment
QtConcurrent — это более высокоуровневый API, чем QThread. Я не говорю, что QThread лучше или хуже, он другой, и вы сами решаете, какое решение является лучшим для вашей конкретной проблемы. Возможно, вы можете использовать оба API в вашем случае, поэтому я бы сказал, что вы можете выбрать то, что вам удобнее. - person Fryz; 06.07.2016