Solved emit dataChanged refreshes QTableView only once.
-
Hi!
I'm working on my code actually and I spotted a problem. I have an app that filters files. Every time I add new filter to QTreeView I want to refresh view and add it to Table. So far I created code like this
//constructor FilterModel::FilterModel(QObject* parent, const std::shared_ptr<FilterManager>& filterManager) : QAbstractTableModel(parent), mFilterManager(filterManager) { mFilterManager->addListener([this](unsigned int id){ QModelIndex idx1 = index(mFilterManager->getIndexById(id), NAME_COLUMN); QModelIndex idx2 = index(mFilterManager->getIndexById(id), DESCRIPTION_COLUMN); emit dataChanged(idx1, idx2, QVector<int>{Qt::DisplayRole}); } ); } //Add Listener method void FilterManager::addListener(std::function<void(unsigned int)> f) { listeners.append(f); } //notify method void FilterManager::notifyListeners(unsigned int id) { for (auto&& listener : listeners) { listener(id); } }
notifyListeners is triggered every time data changes (eg. filter is added or activity is changed). View refreshes only when I resize window, and do it once in one execution of program.
I'm using 5.2.1, on Ubuntu.
Thanks.
-
can you add:
connect(this,&FilterModel::dataChanged,[](){qDebug("changed");});
toFilterModel::FilterModel
to make sure the signal is emittedQ_ASSERT(idx1.isValid()); Q_ASSERT(idx2 .isValid());
to the lambda insideaddListener
to make sure you are passing valid indexes to the view
-
So each time you update something, you are calling your listener functions, right?
Are you sure you are passing valid ids to them? Are you sure the constructed idx1 and idx2 are valid and correct?
Are you sure dataChanged() is really being emitted? Because you are trying to emit it from a different object (FilterManager instead of FilterModel)?
-
@sweetMango
I'm not sure what you're saying you do/do not want, or what you are/are not seeing, but I think the view only refreshes when it next hits the event loop and gets time to repaint, no matter how many times it might have received & acted on multipledataChanged
signals. If you want it to update immediately on each one, I think you need to call http://doc.qt.io/qt-5/qwidget.html#repaint. But maybe that's not what you mean....EDIT Looks like @VRonin understands what you're saying better than I do, sorry!
-
@VRonin
I've applied your suggestions, and every time I add filter, console shows "changed", so signal is emitted, but view refreshes only once in lifetime of program.@sierdzio
Yes, every time I change something, I'm calling notifyListeners. I'm pretty sure, that ids are correct. The goal is to refresh only one row in view, with specific filter. So before refresh it don't exist in View, but after refresh I want it to pop up in
QTableView.@JonB
Still thanks for your reply! -
@sweetMango said in emit dataChanged refreshes QTableView only once.:
So before refresh it don't exist in View, but after refresh I want it to pop up in
Ok, this is the key of the problem.
dataChanged
only refreshes the contents of existing indexes. You need to usebeginInsertRows
/endInsertRows
to notify the view of new rows spawningEdit:
sorry for the double ninja @sierdzio -
@sweetMango said in emit dataChanged refreshes QTableView only once.:
don't exist in View, but after refresh I want it to pop up in
QTableView.Then
dataChanged
is wrong. You need to usebeginInsertRows()
andendInsertRows()
instead. -
@sweetMango
As @sierdzio has just beaten me to posting: when changing the model:- If data in an existing row has changed, you need to emit
dataChanged
. - But if a new row has been inserted or an existing row deleted you need to call
begin/endInsert/DeleteRows()
.
The view needs to know differently from
dataChanged
when the number of rows changes. - If data in an existing row has changed, you need to emit
-