gpt4 book ai didi

qt - 自定义 listModel 不通知 View

转载 作者:行者123 更新时间:2023-12-04 13:15:23 24 4
gpt4 key购买 nike

我有我的自定义列表模型,我在其中放置了应该显示在 QML View 上的数据。但由于某种原因,QML 中的 View 有时会正常更新,有时会使用以前的数据,有时不会执行更新。

这是我填充模型的函数 - 这个函数是从其他线程调用的。

void MyScreen::fillListModel()
{
const QString SEPARATOR = " ";
myListModel->resetModel();

for (int i = 0; i < MAX_ROWS; ++i)
{
QString key = QString::fromUtf16(MyData::getParameterKey(i).c_str());
QString val = QString::fromUtf16(MyData::getParameterVal(i).c_str());
myListModel->addItem(key + SEPARATOR + val);
}
}

模型重置的实现:

void BrowsingModelBase::resetModel()
{
beginResetModel();
m_items.clear();
endResetModel();
}

addItem() 的实现:

void BrowsingModelBase::addItem(const BrowsingItemModelBase &item)
{
int count = m_items.size();
beginInsertRows(QModelIndex(), count, count);
m_items.append(item);
endInsertRows();
}

最后是我的 QML 文件:

MyScreen {

Column {
id: myFlowList
y: 110
x: 220

ListView {
height:1000
spacing: 35;

model: myListModelRoot.myListModel

delegate: Text {
text: text1
}
}
}
}

奇怪的是在循环之后用line

myListModel->addItem(key + SEPARATOR + val);

当我使用 myListModel 中的数据打印日志时,它会填充适当的数据,但 View 通常会使用以前的数据进行更新。数据更改信号是否有可能卡在某处?知道解决方案是什么吗?

最佳答案

假设您从另一个线程调用模型的方法,并且该模型从根本上不是线程安全的,您有两个选择:

  1. 使模型的某些方法线程安全,或者

  2. 以线程安全的方式显式调用方法。

但首先,您可以通过一次添加所有项目作为一个单元来获得一点性能。这样一来,模型将只为所有行发出一个信号,而不是每行发出一个信号。意见将非常感激。

class BrowsingModelBase {
...
};
Q_DECLARE_METATYPE(QList<BrowsingItemModelBase>)

void BrowsingModelBase::addItems(const QList<BrowsingItemModelBase> & items)
{
beginInsertRows(QModelIndex(), m_items.size(), m_items.size() + items.size() - 1);
m_items.append(items);
endInsertRows();
}

您可能还应该有一个名为 clear 的方法,而不是 resetModel,因为重置模型具有更普遍的含义:“改变它太多以至于它不是值得发出个人变革信号”。重置模型并不意味着“清除它”!因此:

void BrowsingModelBase::clear()
{
beginResetModel();
m_items.clear();
endResetModel();
}

最后,按照第二种安全调用模型方法的方法,fillListModel 变成如下。参见 this answer for discussion of postTo .

template <typename F>
void postTo(QObject * obj, F && fun) {
if (obj->thread() != QThread::currentThread()) {
QObject signalSource;
QObject::connect(&signalSource, &QObject::destroyed, obj, std::forward<F>(fun));
} else
fun();
}

void MyScreen::fillListModel()
{
auto separator = QStringLiteral(" ");
QList<BrowserItemModelBase> items;
for (int i = 0; i < MAX_ROWS; ++i) {
auto key = QString::fromUtf16(MyData::getParameterKey(i).c_str());
auto val = QString::fromUtf16(MyData::getParameterVal(i).c_str());
items << BrowserItemModelBase(key + separator + val);
}
postTo(myListModel, [this, items]{
myListModel->clear();
myListModel->addItems(items);
});
}

或者,按照第一种方法,您可以使 clearaddItems 方法线程安全:

/// This method is thread-safe.
void BrowsingModelBase::addItems(const QList<BrowsingItemModelBase> & items)
{
postTo(this, [this, items]{
beginInsertRows(QModelIndex(), m_items.size(), m_items.size() + items.size() - 1);
m_items.append(items);
endInsertRows();
});
}

/// This method is thread-safe.
void BrowsingModelBase::clear()
{
postTo(this, [this]{
beginResetModel();
m_items.clear();
endResetModel();
});
}

然后您不需要更改 fillListModel,除了让它使用 addItems:

void MyScreen::fillListModel()
{
auto separator = QStringLiteral(" ");
myListModel->clear();
QList<BrowserItemModelBase> items;
for (int i = 0; i < MAX_ROWS; ++i) {
auto key = QString::fromUtf16(MyData::getParameterKey(i).c_str());
auto val = QString::fromUtf16(MyData::getParameterVal(i).c_str());
items << BrowserItemModelBase(key + separator + val);
}
myListModel->addItems(items);
}

关于qt - 自定义 listModel 不通知 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32082901/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com