QItemDelegate setModelData in QTreeWidget is not called - c++

I am trying to set delegate to my QTreeWidget. The problem is that delegate setModelData is never called. createEditor and setEditorData are called.
Since the editor that I create is simple QLineEdit, commitData() signal doesn't have to be emitted. Also I tried to emit this signal just in case is needed , when editLine editingFinished() was emitted, but that doesn't solve the problem.
As I understand documentaion say that for simple widgets like QLineEdit setModelData should be called without emitting commitData signal, so the following code should work :
MyDlg::MyDlg()
{
mTreeWdg->setItemDelegate(new TestDelegate( this ));
}
MyDlg::OnTreeItemDoubleCliked(QTreeeWidget* item,int column)
{
if(column != 1) return;
item->setFlags(Qt::ItemIsEditable);
mTreeWdg->editItem(item,column);
}
TestDelegate::TestDelegate(QObject *parent )
:QItemDelegate(parent)
{
}
QWidget* TestDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if(index.column() == 1) // value column
{
QLineEdit* edit = new QLineEdit(parent);
return edit;
}
else return 0; // no editor attached
}
void TestDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column() == 1)
{
QLineEdit* edit = static_cast<QLineEdit*> (editor);
edit->setText("damn");
}
}
void TestDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index)
{
if(index.column()!= 1)
return;
}
void TestDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}

void TestDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) must be const:
void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const
Look at the declaration above.

Related

qt - clickable checkbox for boolean column in QTableView

I wanted to have a checkbox in one of the columns in my Table view. To be specific - in one of the rows, because the view is using a transposing proxy model. I did it using a QItemDelegate derivate class, as described in the doc, and here:
.h
class checkBoxDelegate : public QItemDelegate
{
Q_OBJECT
public:
checkBoxDelegate(QAbstractItemView* parentView = NULL, QObject *parent = NULL);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
//QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
~checkBoxDelegate();
private:
QAbstractItemView* parentView;
};
.cpp
checkBoxDelegate::checkBoxDelegate(QAbstractItemView* parentView, QObject *parent)
: QItemDelegate(parent), parentView(parentView)
{
}
checkBoxDelegate::~checkBoxDelegate()
{
}
QWidget *checkBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QCheckBox *editor = new QCheckBox(parent);
editor->setTristate(false);
return editor;
}
void checkBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
bool value = index.model()->data(index, Qt::EditRole).toBool();
QCheckBox *locEdit = static_cast<QCheckBox*>(editor);
locEdit->setChecked(value);
}
void checkBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
QCheckBox *locEdit = static_cast<QCheckBox*>(editor);
bool value = locEdit->isChecked();
model->setData(index, value, Qt::EditRole);
}
void checkBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
editor->setGeometry(option.rect);
}
void checkBoxDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {
QPalette::ColorGroup cg;
if (option.state & QStyle::State_Enabled) {
cg = (option.state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive;
}
else
cg = QPalette::Disabled;
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.color(cg, QPalette::Highlight));
//if (! (parentView->editTriggers() > QAbstractItemView::NoEditTriggers && option.state & QStyle::State_Selected) )
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
//QSize checkBoxDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const {
// return QItemDelegate::sizeHint ( option, index );
//}
The delegete is bound to a row in my view
checkBoxDelegate* cBD = new checkBoxDelegate(ui.personalData);
ui.personalData->setItemDelegateForRow(4, cBD);
It "kind of" works, the check box appears - centered:
But when I edit that cell, the control returned by createEditor(...) is drawn next to original checkbox:
,
I achieved what I wanted by adding this line:
if (! (parentView->editTriggers() > QAbstractItemView::NoEditTriggers && option.state & QStyle::State_Selected) ) //this one
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
in the paint(...) method .
I ended up with something like that:
if (! (option.state & QStyle::State_Selected) || option.state & QStyle::State_HasFocus)
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
May seem strange, but I could't make it better. It appears, that Qt behaves kind of strange in this piece of code. When the table cell is selected (not in edit mode), it has option.state = State( "Active | Enabled | HasFocus | Selected" ). And when in edit mode, it has State( "Enabled | Selected" ) . Why no longer "Active" ? Why no longer HasFocus ? Ok, focus is probably passed to the QCheckBox. I expected, to have QStyle::State_Editing state - but it didn't
I'm still not sure if this is the best way to do it?

QTableView + QCompleter delegate returns wrong value

I'm using Qt (C++), specifically I have a table that auto-completes using a QCompleter. I'm very new to Qt and struggling with this.
My problem is that even though the QCompleter shows the correct values, the data it returns is always the data for the first element.
For example, if I have the following data (fields separated by dashes, data made up):
1-David-197598713-Los Angeles
2-Daniel-1933398713-NYC
3-Don-1975555-Argentina
And I type D, the QCompleter shows the 3 options, but regardless of which I pick, this happens:
The actual cell edits "correctly" (the value reflects what's been picked)
The callback receives the WRONG value (always the ID of the first element)
So in this case I'd always get (Assuming the name is the autocomplete field):
1-Daniel-197598713-Los Angeles or 1-Don-197598713-Los Angeles or 1-David-197598713-Los Angeles
Also, for some motive the setEditorData procedure does nothing at all (if I comment it, the behavior doesn't change at all)
This is my entire delegate source:
productNameDelegate::productNameDelegate(QObject *parent) : QItemDelegate(parent)
{
}
QWidget *productNameDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QLineEdit *editor = new QLineEdit(parent);
QCompleter *q = new QCompleter(db::getProductsNames());
q->setCaseSensitivity(Qt::CaseInsensitive);
q->setCompletionMode(QCompleter::PopupCompletion);
editor->setCompleter(q);
return editor;
}
void productNameDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{ //TODO this procedure doesn't affect the code at all
QString value = index.model()->data(index, Qt::EditRole).toString();
QLineEdit *LineEdit = static_cast<QLineEdit*>(editor);
LineEdit->setText(value);
}
void productNameDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QLineEdit *LineEdit = static_cast<QLineEdit*>(editor);
QString value = LineEdit->text();
int code=LineEdit->completer()->currentIndex().data(Qt::UserRole).toInt(); //FIXME: siempre devuelve el primer elemento de la lista
if (index.column()==2 && index.row()>=6 && index.row() <= 25)
m->addProducto(code, index.row());
model->setData(index, value, Qt::EditRole);
}
void productNameDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
void productNameDelegate::setModel(factura* m) {
this->m=m;
}

How can I set the background color of some special row in QTableView?

I read an older post however that is not work for me.
I would like to set the background color of every row whose 6th argument is true.
I tried to overwrite the Paint method in my subclass of QSqlRelationalDelegate but apparently it does not do anything.
MoviesDelegate::MoviesDelegate(QObject *parent)
: QSqlRelationalDelegate(parent)
{ }
void MoviesDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if( index.sibling( index.row(), 6 ).data().toBool() )
{
QStyleOptionViewItemV4 optionViewItem = option;
optionViewItem.backgroundBrush = QBrush( Qt::yellow );
drawDisplay( painter, optionViewItem,
optionViewItem.rect,index.data().toString() );
drawFocus( painter, optionViewItem, optionViewItem.rect);
}
else
QSqlRelationalDelegate::paint(painter, option, index);
}
How can I fix it?
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
// Grab cell value and cast it to boolean
bool boolValue = index.model()->data(index).toBool();
// Paint cell background depending on the bool value
if(boolValue)
painter->fillRect(option.rect, QColor(179, 229, 255));
else
painter->fillRect(option.rect, Qt::red);
// Paint text
QStyledItemDelegate::paint(painter, option, index);
}

QComboBox doesn't show its item list

I have problem with QComboBox as item delegeate editor for QTableWidget.
QTableWidget uses SqlTypeDelegate as item delegate.
When I draw QTableWidget inside QGraphicsScene(through QGraphicsProxyWidget) then QComboBox popup list of available items is not shown.
But if I'm using QTableWidget as a normal widget(drawn not through QGraphicsScene\View) then QComboBox behavior is normal - it shows item list.
What should I do to force QComboBox to show its item list?
below sample code:
main.cpp:
#include <QtGui/QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QTableWidget>
#include "sqltypedelegate.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene scene;
QTableWidget *table = new QTableWidget(4,2);
table->setItemDelegate(new SqlTypeDelegate(table));
QGraphicsProxyWidget *proxy = scene.addWidget(table);
QGraphicsView view(&scene);
view.show();
return app.exec();
}
sqltypedelegate.h:
#include <QItemDelegate>
#include <QStyledItemDelegate>
#include <QModelIndex>
#include <QObject>
#include <QSize>
#include <QComboBox>
class SqlTypeDelegate : public QItemDelegate
{
Q_OBJECT
public:
SqlTypeDelegate(QObject *parent = 0);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
sqltypedelegate.cpp:
#include <QtGui>
#include "sqltypedelegate.h"
SqlTypeDelegate::SqlTypeDelegate(QObject *parent)
: QItemDelegate(parent)
{}
QWidget *SqlTypeDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem(QString("decimal(50)"));
editor->addItem(QString("integer"));
editor->addItem(QString("varchar(50)"));
editor->addItem(QString("char"));
editor->setEditable(true);
return editor;
}
void SqlTypeDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QString value = index.model()->data(index, Qt::EditRole).toString();
QComboBox *comboBox = static_cast<QComboBox*>(editor);
comboBox->setEditText(value);
}
void SqlTypeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
model->setData(index, comboBox->currentText(), Qt::EditRole);
}
void SqlTypeDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
comboBox->setGeometry(option.rect);
}
Finaly I've found solution: event filters!
Just lurk for QEvent::MouseButtonRelease and then call showPopup.
bool SqlTypeDelegate::eventFilter(QObject *object, QEvent *event)
{
QComboBox * comboBox = dynamic_cast<QComboBox*>(object);
if (comboBox)
{
if (event->type() == QEvent::MouseButtonRelease)
{
comboBox->showPopup();
return true;
}
}
else
{
return QItemDelegate::eventFilter( object, event );
}
return false;
}
I got the same problem and my workaround is add two line codes to createEditor(...).
editor->move(option.rect.x(),option.rect.y());
editor->showPopup();
Then when double clicking the table item, the QComboBox will show the popup items triggered by the second mouse button pressing and hide the popup items triggered by the second mouse button releasing. This works for Qt 4.8.
I also tried the Qt5.0 and the application crashed with or without this workaround.
I have reported this issue as a bug.

Mystery: In Qt, why would editorEvent be called, but not createEditor?

I'm subclassing QAbstractItemDelegate. This is my code. Suggestions are welcome:
QWidget *ParmDelegate::createWidget(Parm *p, const QModelIndex &index) const {
QWidget *w;
if (index.column() == 0) {
w = new QLabel(p->getName().c_str());
} else {
if (p->isSection())
return NULL;
w = p->createControl();
}
return w;
}
QWidget *ParmDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
cout << "createEditor called" << endl;
Parm *p = reinterpret_cast<Parm*>(index.internalPointer());
QWidget *retval = createWidget(p, index);
retval->setFocusPolicy(Qt::StrongFocus);
retval->setParent(parent);
return retval;
}
void ParmDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QRect rect(option.rect);
editor->setGeometry(QRect(QPoint(0,0), rect.size()));
}
void ParmDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
Parm *p = reinterpret_cast<Parm*>(index.internalPointer());
scoped_ptr<QWidget> w(createWidget(p, index));
if (!w)
return;
QRect rect(option.rect);
w->setGeometry(QRect(QPoint(0,0), rect.size()));
w->render(painter, rect.topLeft());
}
QSize ParmDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
Parm *p = reinterpret_cast<Parm*>(index.internalPointer());
scoped_ptr<QWidget> w(createWidget(p, index));
if (!w)
return QSize(0,0);
return w->sizeHint();
}
bool ParmDelegate::editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index ) {
cout << "editorEvent called" << endl;
return false;
}
When this is run, I only see that editorEvent gets called twice for every edit event -- no createEditor!
From Qt's AbstractItemDelegate documentation:
To provide custom editing, there are two approaches that can be used. The first approach is to create an editor widget and display it directly on top of the item. To do this you must reimplement createEditor() to provide an editor widget, setEditorData() to populate the editor with the data from the model, and setModelData() so that the delegate can update the model with data from the editor.
The second approach is to handle user events directly by reimplementing editorEvent().
This appears to say that you are missing something to trigger the first approach. My guess is that your model's data() function isn't returning the proper value for the Qt::EditRole option.
I had implemented a TableView which i had inhertied from QItemDelegate. Then i had similar problem. I tracked it down to not calling 'return QItemDelegate::editorEvent(event, model, option, index);' in the editorEvent(...) method.
You can try this. Maybe it helps.