PDA

View Full Version : QCompleter with unique items



admkrk
10th March 2017, 06:37
Hi, is there a way to filter out repeated strings when using a QSqlTableModel, in a QTableView as the model for a completer?

As an example, if I have a column, FirstName, that the completer is getting the list from, and there are 4 instances of Mark, I am currently getting 4 options for Mark in the popup. I would only like it to show one. Using inline, somewhat solves that, as I have it implemented below, but the popup option works better for my purposes. I have not tried, but it seems like inline does not correct for using lowercase when using that option, which would just add even more instances, assuming the database does not care about case. The only other alternative I can think of is to create a list, for each column, and apply that individually, according to the column being edited, which pretty much defeats the advantages of using a model.

If it helps, my delegate is created like this

QWidget *Delegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QLineEdit *editor = new QLineEdit(parent);

QCompleter *completer = new QCompleter(editor);
completer->setModel(model);
completer->setCompletionMode(QCompleter::InlineCompletion);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setCompletionColumn(index.column());
editor->setCompleter(completer);

return editor;
}
I get the model this way

Delegate::Delegate(QSqlTableModel *model, QObject *parent) :
QItemDelegate(parent)
{
this->model = model;
}
and the model, in mainWindow

model = new QSqlTableModel(this);
model->setTable("Component");
model->select();
ui->dataView->setModel(model);
ui->dataView->hideColumn(0);
ui->dataView->setSortingEnabled(true);
ui->dataView->setAlternatingRowColors(true);
delegate = new Delegate(model, this);
ui->dataView->setItemDelegate(delegate);

It might just be something simple I am overlooking, but I would appreciate any suggestions.

Santosh Reddy
10th March 2017, 07:53
1. Implement a custom QSortFilterProxyModel to hide the duplicate items.

or

2. Create another QSqlTableModel and apply a SQL filter on it to select only unique items in the required column.

admkrk
10th March 2017, 17:57
I am not sure I understand either of those ways, but it gives me a direction to look. Thank you very much

admkrk
17th March 2017, 00:45
Hi,
I almost have the proxy model figured out. What I am not understanding, is where I set the column for looking for the duplicates. At present, it looks in column 0, which is the ID column, so obviously it does not find any duplicates, even though it displays data from the correct column, if that makes sense.

bool UniqueFilterModel::filterAcceptsRow(int source_row,
const QModelIndex &source_parent) const
{
QModelIndex index = sourceModel()->index(source_row,
filterKeyColumn(),
source_parent);
QString temp = index.data().toString();
qDebug() << temp;
if(!uniqueRows.contains(temp))
{
uniqueRows.insert(temp);
return true;
}

return false;
}
As near as I can tell, the problem is with filterKeyColumn(), and somewhere I need to call setFilterKeyColumn(), with the correct column. Since I am not sure where it is getting the row from, I cannot figure out where to get the column from.

Santosh Reddy
17th March 2017, 08:25
Since I am not sure where it is getting the row from,
The view/model will supply the row number, don't worry about it.


I cannot figure out where to get the column from.
Column number of the unique values you wanted, in your case the column of "FirstName"

admkrk
17th March 2017, 09:29
Thanks for getting back.

The view/model will supply the row number, don't worry about it.
That is what I expected to begin with.

Column number of the unique values you wanted, in your case the column of "FirstName"
I think this is were the misunderstanding is coming from. I used that as an example of where the data might be repeated. This needs to work with multiple columns. The completer does, but the proxy does not, as I have it written. The debug statement prints the same thing, regardless of the column selected:

"2"
"3"
"4"
"5"
"6"
"7"
"8"
"9"
"10"
Which is the ID column from the database, and is the default column for filterKeyColumn(). What I am trying to figure out is how to set the column to the one selected. I am sure I am overlooking something really simple, but I am not seeing it.

Santosh Reddy
17th March 2017, 10:43
You will have to create individual completer for each column, and each completer should have separate proxy model. The column number of the proxy model will be the column of the cell on which the completer is installed.

Hope not to confuse you :)

admkrk
17th March 2017, 20:51
Actually, that is something like what I wanted to do once I got a better understanding of how this all worked. For example, there is one column I do not want the completer on at all. I guess my next step is to figure out how to assign the delegate to a particular column, as opposed to the whole table.

I had hoped, eventually, to allow the user to create their own columns, but that is looking more problematic now.

admkrk
17th March 2017, 23:38
I think I have this solved now. setFilterKeyColumn() was the solution. I added

filter->setSourceModel(model);
filter->setFilterKeyColumn(index.column());
to my delegate, and now it gets the correct column. I also figured out how to set the delegate to specific columns. This did show me that I need to set different delegates to different columns, and not just the filter, but I should be able to figure that out easier now.