Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate)
-
Hi,
I have
QTableView
withQStandardItemModel
. In some columns I set different delegates like delegate forQComboBox
orQSpinBox
.
I added functionality to copy/past data that usesQStandardItemModel::setData()
.The problem is that it allows to copy for example text in column where I set spinbox delegate. Thus it is possible to see that column with spinbox delegate has textual data. This is not good .
How can I set data to the model and check if data is appropriate for the column? Or at least set data to the model and then update this model to remove inapropriate data in cells?
-
I've found a solution for my case.
Afterpaste()
command wich is invoid TableView::keyPressEvent(QKeyEvent *event)
I do:setCurrentIndex(index); // set current index edit(index); // starts editing of item
Whenever
edit(..)
is invoked a delegate is created and if displayed data is invalid then it removes it. And if data is acceptable then delegate accepts it.
`setCurrentIndex(..)' is needed as only current indexes can be editable -
@Please_Help_me_D said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
The problem is that it allows to copy for example text in column where I set spinbox delegate. Thus it is possible to see that column with spinbox delegate has textual data. This is not good .
Can you explain this more? How do you copy text when there is a spinbox?
-
@Christian-Ehrlicher Hi
Here is the picture:
Actually I can set any data to the cell via
model->setData()
and no matter whether there is a delegate or not the cell will accept this data. But after I double click on the cell then the can either stay or it will be removed if data is inapropriate for the delegate.I just remembered one thing: I have both proxy (
QSortFilterProxyModel
) andQStandardItemModel
as a source model. I implemented copy/past according to this post: https://www.walletfox.com/course/qtableviewcopypaste.php
I thinksetData()
is applied to the proxy model (according the post) -
@Please_Help_me_D said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
Actually I can set any data to the cell via model->setData()
I'm not with you (unless I misunderstand): it is your job to write code in
setData()
to only accept whatever you wish to be acceptable/valid for the index/item (returnfalse
if not). Doesn't matter where the input data emanates from: input widgets, paste, whatever. Also, I don't get why you show a column containing letters, and have a delegate which is a spinbox, one of those two seems inconsistent. -
@JonB said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
Also, I don't get why you show a column containing letters, and have a delegate which is a spinbox, one of those two seems inconsistent.
Correct, the data is absolutely wrong - why should I use a spinbox in a textual field?
-
@Christian-Ehrlicher said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
Also, I don't get why you show a column containing letters, and have a delegate which is a spinbox, one of those two seems inconsistent.
I think you don't understand the problem.
I need to forbid to paste textual data to the column where data is supposed to be numbers (for example where spinbox delegate is). If I have spinbox delegate in column "coord_1 col" then I want that this column accepts only numbers acceptable in spinbox. I don't understand how to do that?
@JonB said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
I'm not with you (unless I misunderstand): it is your job to write code in setData() to only accept whatever you wish to be acceptable/valid for the index/item (return false if not).
Well I think the same but: copy/past are methods of a
QTableView
, delegates are also available fromQTableView
andsetData(...)
is a model's method.
The only way I see how to achieve my goal is:
implement new model's method likesetFilteredData(QVariant var, Qt::role)
. This method should get treeView and from this treeView it should check whether there is delegate. If there is then it should set data viaQAbstractItemDelegate::setEditorData(...)
and if there is not then I can set data viasetData(...)
.I think my logic is uneffective because I need to get
tableView
from model. Usually I would implement it from searching through parents of model and I don't like it as I'm not shure whether I can always find some widget through parent in all possible cases.Probably you can see other ways of doing this?
-
@Please_Help_me_D said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
I think you don't understand the problem.
I think actually I do :)
Like I said, it is your job to write the necessary validation/rejection logic here. It doesn't matter that paste is functionality is in the view. The view cannot put data into the model which the model does not accept, and it is the model's job to reject any illegal data, not the view's. This is good logic, because you should not rely on the assumption that data can only be presented to the model from the view: assume that there is no view, or that the user by-passes any view, and write your model logic accordingly.
You should subclass your
QStandardItemModel
if necessary if you need to override itssetData()
(e.g. for validation), and write your logic there. Maybe the subclassing is the bit you are missing, if you useQStandardItemModel
directly. AnyQItemDelegate::setModelData()
will go via that, so you'll get it rejected by the view editor as a bonus.implement new model's method like [...]
This method should get treeView and from this treeView it should check whether there is delegate.
If there is then it should set data via QAbstractItemDelegate::setEditorData(...) and if there is not then I can set data via setData(...).Absolutely not! Models should never know about views or delegates. (BTW, separately, I think you are confusing
setEditorData()
withsetModelData()
.) Your "because I need to get tableView from model. ": except in exceptional circumstances, you should never try to get views from model, and there should not be any reason to want to do so.Like I say, maybe if you realize that can subclass your current
QStandardItemModel
, and that will allow to overridesetData()
and returnfalse
on invalid data, it will all become clearer. -
@JonB said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
Like I say, maybe if you realize that can subclass your current QStandardItemModel, and that will allow to override setData() and return false on invalid data, it will all become clearer.
If I understand you I need to do all the checks inside model's
setData(..)
. But in this case I will have two steps of checking:- in delegate
- in model
And those those steps should do the same job. I don't think that this is good solution.
For example for third column I set spinboxDelegate which accepts only integers. This delegate is available from treeView.
To forbid pasting textual data to the third colum I implement filtering inMyModel->setData(QVariant data)
which should check whetherdata
contains only integer.
Or I misunderstand something?By the way my treeView has different delegates for different columns, there are: spinbox, doubleSpinbox, comboWidget
-
@Please_Help_me_D said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
To forbid pasting textual data to the third colum
I still don't understand - if there is a spinbox delegate you can't paste anything but numbers in there...
-
@Please_Help_me_D said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
And those those steps should do the same job. I don't think that this is good solution.
Well it's a shame you feel like that, since that is the correct thing to do. Models should always do the correct data validation, always. As I said before, models can receive data without going through a view. The view on top of that, with its own validation, is simply "the icing on the cake", to aid the end user. It is code which fails to validate data in the backed (model), and relies on the front-end (view) to have ensured data is correct/acceptable which potentially leads to half the data problems/attacks/hacks we have in the world....
It is possible that you may find some way of sharing the validation code from somewhere common which can be used by both model & view.
Also, as I said, the view setting model data should detect rejection from the model's
setData()
so it can use that in part for its validation purposes.If like you I had data which is of different types for different columns, I either would not go directly through
setData()
and instead expose typed getters/setters for each column, or I would use my own custom model and not plainQStandardItemModel
. It also makes coding easier.Anyway, since you have your own views on what is a good solution, I leave you to decide.
-
@Christian-Ehrlicher said in Restrict setting inapropriate data to the model with delegates (like text data to spinbox delegate):
I still don't understand - if there is a spinbox delegate you can't paste anything but numbers in there...
Actually I can :)
Here on the picture is my explanation how I see that:
@JonB thank you for sharing opinion. I decided to take some time to thing about all of this. I should be missing something important
-
You're responsible by yourself to set the correct data to your model.
-
I've found a solution for my case.
Afterpaste()
command wich is invoid TableView::keyPressEvent(QKeyEvent *event)
I do:setCurrentIndex(index); // set current index edit(index); // starts editing of item
Whenever
edit(..)
is invoked a delegate is created and if displayed data is invalid then it removes it. And if data is acceptable then delegate accepts it.
`setCurrentIndex(..)' is needed as only current indexes can be editable