Signal when QTableWidget scroll hits the end of the table?
-
I have a table with which I've populated some Mariadb results. When scrolling, as I go down the table I would like to trigger a search for the next set of results (rather than having all results being reported at once - with some large database tables you could end up with an unruly amount of data coming back for some queries!).
It is possible to detect when the user scrolling makes the table hit the end? Both with the mouse scroll wheel and dragging the table down using he scroll bar?
Thanks.
-
I have a table with which I've populated some Mariadb results. When scrolling, as I go down the table I would like to trigger a search for the next set of results (rather than having all results being reported at once - with some large database tables you could end up with an unruly amount of data coming back for some queries!).
It is possible to detect when the user scrolling makes the table hit the end? Both with the mouse scroll wheel and dragging the table down using he scroll bar?
Thanks.
@DiBosco
Well, there is not actually anything "built in" for this. You have to roll something yourself.You can either intercept the scrollbar/mouse events, check for "reached or near the the bottom" and
fetchMore()when it hits there. Or what some people do is have therowCount()report more than the actual number of rows, so that technically you can scroll beyond the last row, and detect that andfetchMore()then. Variations on a theme.QTableWidget, as opposed toQTableView, may present some difficulties fiddling with itsrowCount()as the model is built in and kind of hidden for subclassing. But in any caseQTableWidgetis quite the wrong widget for querying a SQL database like MariaDB, especially if a large number of rows/columns. Grossly inefficient. You should change toQTableViewplusQSqlQueryModelorQSqlTableModel.as I go down the table I would like to trigger a search for the next set of results (rather than having all results being reported at once - with some large database tables you could end up with an unruly amount of data coming back for some queries!).
Be aware that so long as you are using the
QSql...Model...calls if there are a million matching rows it does not read all those million rows immediately! In fact, you should find that it (Qt) is hard-coded to fetch 256 rows at a time. The rest are still at the server while the query is active. You use void QSqlQueryModel::fetchMore() to fetch the next batch(es) of 256. This is more efficient than some sort of "issue a new query to pick up where you got to". -
Hi Jon, thanks for that.
Couple of points/follow-ups if I may.
I wasn't aware of QSqlTableModel, QSqlQueryModel etc. I have been using QSqlQuery to carry out my mariadb query and putting results into a QStringList vector, then taking that data and putting it into a QTableWidget in the order I want it. It works beautifully and is really fast, even when I return, say, a thousand records with multiple columns.
Are you basically saying this method is poor?
I do have to be careful with insertRow, setRowCount,clearContents etc etc when using a QTableWidget, but as long as I careful it all works a treat.
Now, the caveat as I said when you answered my DLL query a couple of weeks ago, I am strictly speaking an embedded software engineer, and although I am getting reasonably proficient in C++ and Qt, I am very happy to admit I am absolutely no expert, I might well be doing this in the wrong way. Or at least not the best way!
-
@JonB suggestion is the better way to do it for sure, but for your current use case, simply listen to the valueChanged signal of your QScrollbar, something like:
connect(ui->tableView->verticalScrollBar(), &QScrollBar::valueChanged, this, &MyWidget::onScrollChanged);and than simply fetch more, when reaching the end, or near the ende, in case you want to start loading a little bit earlier for a smoother experience:
void MyWidget::onScrollChanged(int value) { QScrollBar const * const bar = ui->tableView->verticalScrollBar(); if (value >= bar->maximum() - 50) { fetchNextPage(); } } -
@JonB suggestion is the better way to do it for sure, but for your current use case, simply listen to the valueChanged signal of your QScrollbar, something like:
connect(ui->tableView->verticalScrollBar(), &QScrollBar::valueChanged, this, &MyWidget::onScrollChanged);and than simply fetch more, when reaching the end, or near the ende, in case you want to start loading a little bit earlier for a smoother experience:
void MyWidget::onScrollChanged(int value) { QScrollBar const * const bar = ui->tableView->verticalScrollBar(); if (value >= bar->maximum() - 50) { fetchNextPage(); } }@J.Hilk
Ah, right, without subclassing. Do you get theQScrollBar::valueChanged()if it's from the wheel? You probably do, else you have to subclass to catch the wheel I believe.At the moment the OP is apparently using a
QTableWidget, with its own standard item model data which has to be copied to etc. from some MariaDB SQL query. I advised they would be better off changing toQTableView+QSql...Model...calls to manage fetching chunks from the database better. Then they can use thefetchMore()rather than some new query to continue. -
@DiBosco
Well, there is not actually anything "built in" for this. You have to roll something yourself.You can either intercept the scrollbar/mouse events, check for "reached or near the the bottom" and
fetchMore()when it hits there. Or what some people do is have therowCount()report more than the actual number of rows, so that technically you can scroll beyond the last row, and detect that andfetchMore()then. Variations on a theme.QTableWidget, as opposed toQTableView, may present some difficulties fiddling with itsrowCount()as the model is built in and kind of hidden for subclassing. But in any caseQTableWidgetis quite the wrong widget for querying a SQL database like MariaDB, especially if a large number of rows/columns. Grossly inefficient. You should change toQTableViewplusQSqlQueryModelorQSqlTableModel.as I go down the table I would like to trigger a search for the next set of results (rather than having all results being reported at once - with some large database tables you could end up with an unruly amount of data coming back for some queries!).
Be aware that so long as you are using the
QSql...Model...calls if there are a million matching rows it does not read all those million rows immediately! In fact, you should find that it (Qt) is hard-coded to fetch 256 rows at a time. The rest are still at the server while the query is active. You use void QSqlQueryModel::fetchMore() to fetch the next batch(es) of 256. This is more efficient than some sort of "issue a new query to pick up where you got to".@JonB said in Signal when QTableWidget scroll hits the end of the table?:
@DiBosco
Well, there is not actually anything "built in" for this. You have to roll something yourself.This is the purpose of QAbstractItemModel::canFetchMore(), coupled with fetchMore().
void QAbstractItemView::verticalScrollbarValueChanged(int value) { Q_D(QAbstractItemView); if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root)) d->model->fetchMore(d->root);There's even an example: Fetch More Example
-
@JonB said in Signal when QTableWidget scroll hits the end of the table?:
@DiBosco
Well, there is not actually anything "built in" for this. You have to roll something yourself.This is the purpose of QAbstractItemModel::canFetchMore(), coupled with fetchMore().
void QAbstractItemView::verticalScrollbarValueChanged(int value) { Q_D(QAbstractItemView); if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root)) d->model->fetchMore(d->root);There's even an example: Fetch More Example
@jeremy_k said in Signal when QTableWidget scroll hits the end of the table?:
@DiBosco
Well, there is not actually anything "built in" for this. You have to roll something yourself.This is the purpose of QAbstractItemModel::canFetchMore(), coupled with fetchMore().
The "nothing actually built in" referred to no in-built facility to recognise a scroll to the bottom of a
QTableWidgetcausing some kind of call to fetch more rows. I pointed the user atfetchMore()for the data, the bit he has to "roll" is the recognition of when to call it, such as your code. -
@jeremy_k said in Signal when QTableWidget scroll hits the end of the table?:
@DiBosco
Well, there is not actually anything "built in" for this. You have to roll something yourself.This is the purpose of QAbstractItemModel::canFetchMore(), coupled with fetchMore().
The "nothing actually built in" referred to no in-built facility to recognise a scroll to the bottom of a
QTableWidgetcausing some kind of call to fetch more rows. I pointed the user atfetchMore()for the data, the bit he has to "roll" is the recognition of when to call it, such as your code.@JonB said in Signal when QTableWidget scroll hits the end of the table?:
I pointed the user at
fetchMore()for the data, the bit he has to "roll" is the recognition of when to call it, such as your code.That's not my code. It's in the implementation of QAbstractItemView.
-
@JonB said in Signal when QTableWidget scroll hits the end of the table?:
I pointed the user at
fetchMore()for the data, the bit he has to "roll" is the recognition of when to call it, such as your code.That's not my code. It's in the implementation of QAbstractItemView.