QSqlRelationalTableModel with multiple Joins?
-
@VRonin said in QSqlRelationalTableModel with multiple Joins?:
Thanks but before doing that, I was wondering if there's a way to change the content of the cell by directly typing into it.
I just want to change the data of the cell and, once changed, color that cell in a different color to alert the user of the change of that particular item/cell.
Seems a lot of hard-coding work... maybe I should find another convenient way... but for now let's see what comes out
@devhobby said in QSqlRelationalTableModel with multiple Joins?:
@VRonin said in QSqlRelationalTableModel with multiple Joins?:
Thanks but before doing that
This discussion went on way too long because you didn't bother looking at that link.
The solution is already presented there. Basically you need a proxy between the QSqlQueryModel and the view that can handle data changes. That link presents you with an example implementation. You can then use the
dataChanged
signal of the proxy to detect things you probably want to send to dbP.S.
Be careful that proxy considersQt::EditRole
as separate fromQt::DisplayRole
-
@JonB said in QSqlRelationalTableModel with multiple Joins?:
@devhobby
Well, I presume:setData()
is called whenever the data is changed/setdataChanged
signal should be emitted bysetData()
whenever new data is different from current datadata()
is called many times, with whatever role aspect is wanted, not only by your code but also by Qt code whenever it wants a piece of information
http://doc.qt.io/qt-5/qt.html#ItemDataRole-enum:
enum Qt::ItemDataRole
Each item in the model has a set of data elements associated with it, each with its own role. The roles are used by the view to indicate to the model which type of data it needs. Custom models should return data in these types.
What I have noticed:
- Double-Click signal on the Table View calls slot function onTableChanged()
- onTableChanged() calls data() when it has finished
<> - Flags are checked
- setData() is called if flag is editable
- Signal dataChanged is emitted by setData()
Where's the problem?
Say I want to allow modification of some cells (name, surname...) and forbid modification of others (primary key, foreign key...)
I have a vector of immutable columns (0, 3, 5...)
I have to check if the column being edited belongs to the vector of immutable columns... TWICE!
One inside the flag() function and one inside onTableChanged()
- Doing the check in flags() keeps me from modifying the content of the cell (hence, disabling the double-click)
- Doing the check in onTableChanged() keeps the cells from being added to the vector of cells that need to be coloured by data()
Both checks are identical, but serve for 2 different purposes: one for disabling the double-click, the other for disabling the coloration.
All of these events are not sequential. I put a symbol <> in the list above to evidence two apparently unrelated events.
If these events had been sequential, I would've written only ONE check at the beginning of the event.
So, the question is: should I keep the situation this way (2 checks)?
@devhobby
Yeah, I don't really understand what you're saying, and I don't seem to have the knack of the miraculous correct interpretations @SGaist comes up with :)If I understand right, you should have two different method overloads doing different things for what you want:
-
data()
: when called forBackgroundRole
, this will look up your vector of changed cells to determine the desired color. -
flags()
: when called, this should look up whether this is to be an editable cell, which depends on column (PK/FK versus others), but not your "edited vector". That will determine whether or not it returnsQt::ItemIsEditable
. If it's not editable, Qt won't let it get edited.
-
@devhobby
Yeah, I don't really understand what you're saying, and I don't seem to have the knack of the miraculous correct interpretations @SGaist comes up with :)If I understand right, you should have two different method overloads doing different things for what you want:
-
data()
: when called forBackgroundRole
, this will look up your vector of changed cells to determine the desired color. -
flags()
: when called, this should look up whether this is to be an editable cell, which depends on column (PK/FK versus others), but not your "edited vector". That will determine whether or not it returnsQt::ItemIsEditable
. If it's not editable, Qt won't let it get edited.
-
-
@JonB There is one more point:
setData
should actually do something.QSqlQueryModel::setData
is just areturn false;
@VRonin
Yes, he's supposed to know that from when I pointed him at:Ah ha!! Here's what we wanted to know:
http://doc.qt.io/qt-5/qsqlquerymodel.html#detailsThe model is read-only by default. To make it read-write, you must subclass it and reimplement setData() and flags(). Another option is to use QSqlTableModel, which provides a read-write model based on a single database table.
way earlier! :)
-
If you overwrote the flags method correctly, you shouldn't be able to edit the corresponding cell so you shouldn't have to make several checks.
@SGaist said in QSqlRelationalTableModel with multiple Joins?:
If you overwrote the flags method correctly, you shouldn't be able to edit the corresponding cell so you shouldn't have to make several checks.
The flag() check is:
if(MainWindow::isConstColumn(index.column())) QAbstractItemModel::flags(index) & (~Qt::ItemIsEditable); else return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
Qt::ItemIsEditable is only assigned when the cell being modified isn't found in the vector of immutable cells.
In data() the check is similar:
if (!item.isValid()) return QVariant(); if(role == Qt::BackgroundRole) { if(MainWindow::cellsEdited.contains(item)) return QColor(66, 197, 244, 150); } return QSqlQueryModel::data(item, role);
However, removing the check from either part is disastrous:
- Removing the check from flags() makes no cell editable
- Removing the check from data() makes all the cell blue as soon as the program starts
-
@SGaist said in QSqlRelationalTableModel with multiple Joins?:
If you overwrote the flags method correctly, you shouldn't be able to edit the corresponding cell so you shouldn't have to make several checks.
The flag() check is:
if(MainWindow::isConstColumn(index.column())) QAbstractItemModel::flags(index) & (~Qt::ItemIsEditable); else return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
Qt::ItemIsEditable is only assigned when the cell being modified isn't found in the vector of immutable cells.
In data() the check is similar:
if (!item.isValid()) return QVariant(); if(role == Qt::BackgroundRole) { if(MainWindow::cellsEdited.contains(item)) return QColor(66, 197, 244, 150); } return QSqlQueryModel::data(item, role);
However, removing the check from either part is disastrous:
- Removing the check from flags() makes no cell editable
- Removing the check from data() makes all the cell blue as soon as the program starts
-
@devhobby said in QSqlRelationalTableModel with multiple Joins?:
if(MainWindow::isConstColumn(index.column())) QAbstractItemModel::flags(index) & (~Qt::ItemIsEditable);
There is no
return
statement there??????@JonB said in QSqlRelationalTableModel with multiple Joins?:
@devhobby said in QSqlRelationalTableModel with multiple Joins?:
if(MainWindow::isConstColumn(index.column())) QAbstractItemModel::flags(index) & (~Qt::ItemIsEditable);
There is no
return
statement there??????Just a typo when I posted the code to the forum, the actual code has it.