PDA

View Full Version : Completer on QItemDelegate



gemidjy
25th March 2008, 22:10
Hi, I need to create a QItemDelegate in a QTableWidget cell, that would be QLineEdit in that particular cell. On that cell I need to install a QCompleter object. Thus, I subclass the QItemDelegate with my class and reimplement the virtual createEditor() method this way:


QWidget *ProductsDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QLineEdit *productsEditor = new QLineEdit(parent);
QCompleter *productsCompleter=new QCompleter();

QSqlQueryModel *sqlProductsQuery=new SqlQueryModel(productsCompleter);
sqlProductsQuery->setQuery("SELECT product_name FROM jeam_products");
productsCompleter->setModel(sqlProductsQuery);

productsEditor->setCompleter(productsCompleter);

return productsEditor;
}

Then I install the delegate in the column in the QTableWidget object with QTableWidget::setItemDelegateForColumn(...) method.

This creates the delegate fine. When I double click the cell it opens the line edit and when I press "A" it reads from the database and shows popup with completion recomendations. I have enabled all EditTriggers for the table, because basically I need all of them. That means that the AnyKey edit trigger is also enabled. So i set the focus on the cell on which the delegate is installed and type the letter (for i.e.) 'A'. If the SqlQuery finds entry in the database that starts with A, the cell immediatelly opens and closes, it loses focus and the delegate closes/destroys itself. The delegate opens for editing only if I have set the QCompleter::InlineCompletion CompletionMode or if there is no such entry in the database (ie. if I type 'W' and there is no entry that starts with 'W' in the db table).

This is very strange and I hoped I did everything right ...
Any ideas and answers would be very much appreciated.

thanks

wysota
25th March 2008, 23:12
Does it happen only for the AnyKey trigger? Your code seems fine, the problem is most likely related to the fact that the completer gains and the line edit loses focus while completing. Let's focus on pinpointing the problem first and only then think about ways of solving it.

gemidjy
25th March 2008, 23:21
To eliminate that reason I tried with setting the focus with setFocus(..reason..) but didn't help either.. what I think is that the problem is some where around the completer, when the completer is initialized, the editor is created, then it gets destructed if I activate the cell from the AnyKeyPressed edit trigger (btw, happens ONLY with this trigger and ONLY if I have selected PopupCompletion mode for the completer).

jpn
26th March 2008, 12:55
The problem is exactly what Wysota suggested. I recommend taking a quick look at src/gui/itemviews/qitemdelegate.cpp: QItemDelegate::eventFilter()'s QEvent::FocusOut branch.

Workaround suggestion (don't expect it to work 100%, it was written on the fly):


bool ProductsDelegate::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::FocusOut)
{
QWidget* focusWidget = QApplication::focusWidget();
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(object);
if (lineEdit && focusWidget)
{
QCompleter* completer = lineEdit->completer();
if (completer && focusWidget == completer->popup())
return false; // let completer popup receive focus, don't close editor
}
}
return QItemDelegate::eventFilter(object, event); // <-- it's important to call base class implementation!
}

No need to explicitly install event filter (QAbstractItemView already does that), but just override it more or less like shown above.

jpn
26th March 2008, 18:52
Actually, now that I give it a try I'm not even able to reproduce the problem. This works just fine for me (with both Qt 4.3.3 and a couple of weeks old snapshot of Qt 4.4):


// main.cpp
#include <QtGui>

class ItemDelegate : public QItemDelegate
{
public:
ItemDelegate(QObject* parent = 0) : QItemDelegate(parent) { }

QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QWidget* editor = QItemDelegate::createEditor(parent, option, index);
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
if (lineEdit)
{
QStringList stringList = QStringList() << "foo" << "bar" << "baz";
QCompleter* completer = new QCompleter(stringList, lineEdit);
lineEdit->setCompleter(completer);
}
return editor;
}
};

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTableWidget table(4, 4);
table.setEditTriggers(QAbstractItemView::AllEditTr iggers);
table.setItemDelegate(new ItemDelegate(&table));
table.show();
return app.exec();
}

Doesn't it work for you?

gemidjy
30th March 2008, 19:54
Actually, now that I give it a try I'm not even able to reproduce the problem. This works just fine for me (with both Qt 4.3.3 and a couple of weeks old snapshot of Qt 4.4):


// main.cpp
#include <QtGui>

class ItemDelegate : public QItemDelegate
{
public:
ItemDelegate(QObject* parent = 0) : QItemDelegate(parent) { }

QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QWidget* editor = QItemDelegate::createEditor(parent, option, index);
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
if (lineEdit)
{
QStringList stringList = QStringList() << "foo" << "bar" << "baz";
QCompleter* completer = new QCompleter(stringList, lineEdit);
lineEdit->setCompleter(completer);
}
return editor;
}
};

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTableWidget table(4, 4);
table.setEditTriggers(QAbstractItemView::AllEditTr iggers);
table.setItemDelegate(new ItemDelegate(&table));
table.show();
return app.exec();
}

Doesn't it work for you?


When I compile your code as standalone application it works as expected, otherwise when I apply it on my code and on my view, it doesn't work :/ happens exactly the same thing. It is because I don't put AllEditTriggers, but I have only couple of them...try setting the AnyKeyPressed trigger .. doesn't work.

gemidjy
31st March 2008, 10:29
Could this be bug in Qt ?