PDA

View Full Version : QSqlTableModel and QTableView critics.



Avrohom
10th September 2009, 18:20
Hi,

I am in middle of developing a database front-end, and I’m employing the QSqlTableModel together with a QtableView widget among others in order to accomplish this task.

I came across several issues using them both, which I think causes one to conclude that those components are not really suitable for real-world database applications. I hope that someone can prove me wrong.

So, let’s start listing them:

1. view->resizeColumnsToContents() does not resize the columns properly, i.e I have got a column with double values, it get’s resized to show the integer part of the number where the fractional (the digits after the decimal point) gets elided (…). However, funny enough, when double-clicking on the column-separator on the header at run-time it resizes ok.
2. The model->rowsInserted signal will fire on the occasion of a data-change as well, so there’s no real way of determining when a row has actually been added or it has just been changed.
3. On a newly added line (model->insertRow()) I am getting SpinBox editors for numeric columns, but for older rows, I am always getting a regular LineEdit editor.
4. I opted for model()->setEditStrategy(QSqlTableModel::OnRowChange), so every change will get submitted when leaving that row, that will work fine when the user gets into actually editing a cell on a different row. However, if the user clicks away on a different row, or tabs his way through to another row, that change will not get submitted.
5. While a newly (un-submitted) (model->insertRow()) row is present, when the user edit’s a cell of another row, anything typed will be applied onto the new row / record, and not onto the row the user thinks he is editing.

Have anyone came across those issues yet? I know that for problem #1, I can subclass a QItemDelegate and change the sizeHint, but it seems to me to much work-around to re-implement a ItemDelegate just for the sake of that, which is basically a bug on QT’s end. I also know that I can manually submit with submit() or submitAll() before closing that form, but it is esential that those changes gets submitted on row-change (which I believe QSqlTableModel::OnRowChange stands for).

Does anyone know of any good grid that I can incorporate into a QT project that’s serious enough for professional database work? Or does anyone know of any good grid for c++ in general (not MFC)?

How difficult would it be to re-implement a TableModel and View to address those problems? Where would be a good starting point? What would be the best approach to accomplish this?
I would highly welcome any comments on this subject, so please, please come forward with your suggestions.

caduel
10th September 2009, 20:46
a few notes:


the view probably does not resize when (new) data is added to the model; the columns' initial sizes thus based on an empty model. you can iterate over the columns and call QTreeView::resizeColumnToContents()
see QTreeView::expandsOnDoubleClick()
what are "older rows"? what editor should you get and why?
yes, you do have to start editing another row, simply clicking will not cause a commit (You can try QAbstractItemView::setEditTriggers(; or revert to manual submit if you want perfect control)


These views (and models) are a relatively recent addition and unfortunately not as mature as some other things. Column size managemant is a pain, for example.

ChrisW67
10th September 2009, 23:50
I came across several issues using them both, which I think causes one to conclude that those components are not really suitable for real-world database applications. I hope that someone can prove me wrong.

As a blanket statement, I don't think this is warranted. There are quite a few idiosyncrasies that make using them a bit more awkward than they could have been.

For example, if you share a QSqlTableModel on manual submit between two views and edit through one of them you get the situation where edits to existing rows, and new rows, are seen in the other view immediately (no commitAll() required) , but deleted rows remain visible until all changes are committed to the database. In the edited view the deleted row is marked "!" in the vertical header view (if visible). In the other view this is not the case and I've not found another way to determine if a row is scheduled for deletion. Signals can do some of this if he second view is open when the delete is made, but are not useful if you open the second view later.

Avrohom
11th September 2009, 01:44
a few notes:


the view probably does not resize when (new) data is added to the model; the columns' initial sizes thus based on an empty model. .
I am calling view->resizeColumnsToContents() after the model / view has been populated with data. Also, I cannot really see the difference between resizeColumnsToContents and resizeColumnToContents(int column).

what are "older rows"? what editor should you get and why?

Older rows, I ment for rows that have been submitted already, in contrast to a newly added row, where the row has not yet been submitted. I think it's very un-professional to have a different editor (regular QLineEdit) for the same column on the older rows, and a QSpinBox editor for the new row.


yes, you do have to start editing another row, simply clicking will not cause a commit (You can try QAbstractItemView::setEditTriggers(; or revert to manual submit if you want perfect control)

So with manual submit, how do I get to know when the user navigates to a different row? There's not really any signal for that.

Avrohom
11th September 2009, 01:57
For example, if you share a QSqlTableModel on manual submit between two views and edit through one of them you get the situation where edits to existing rows, and new rows, are seen in the other view immediately (no commitAll() required) , but deleted rows remain visible until all changes are committed to the database. In the edited view the deleted row is marked "!" in the vertical header view (if visible). In the other view this is not the case and I've not found another way to determine if a row is scheduled for deletion. Signals can do some of this if he second view is open when the delete is made, but are not useful if you open the second view later.
How do you delete those rows? Have you tried view->removeRow?

ChrisW67
11th September 2009, 03:17
Removing the row is a function of the model, not the view: QSqlTableModel::removeRow().
With OnManualSubmit the removed row remains visible in the view with a marker, so usually I use a QTableView::hideRow() to actually hide the row from view.

In the secondary view the removed row remains visible until QSqlTableModel::commitAll() while other modifications are reflected in real time (i.e. not waiting until they are written to the database). It's this inconsistency that causes me angst.