PDA

View Full Version : Qstyleditemdelegate probeme with Qcombobox



advseo32
31st July 2013, 11:55
Hi every boby

i have probleme when i start implementing createEditor() function in Qstyleditemclass in Qtablewidget

her
QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{

if(creeConnexion())
{
if(index.column() == 1 || index.column() == 0)
{
QComboBox *editor = new QComboBox(parent);
editor->setEditable(true);

// Query data
QSqlQuery *query = new QSqlQuery("select designation from Produit") ;
while(query->next())
editor->addItem(query->value(0).toString());

return editor;
}

}else
// the problem her, i want to return the default editor for other cells but , the app crashed when i user this code below
return QStyledItemDelegate::createEditor(parent,option,in dex);

}

advseo32
1st August 2013, 00:44
Plz i need your help

advseo32
1st August 2013, 12:13
i wait for your help

advseo32
3rd August 2013, 12:31
Update thread !

Santosh Reddy
3rd August 2013, 12:36
What is creeConnexion()?

advseo32
3rd August 2013, 12:55
What is creeConnexion()?
It's a function to test the connexion on database

her is the function


static bool creeConnexion()
{
QSqlDatabase *db ;
db = new QSqlDatabase;
*db = QSqlDatabase::addDatabase("QSQLITE") ;
db->setHostName("localhost");
db->setDatabaseName("gestionstockDB.db");
db->setPassword("");
db->setUserName("");
// Verifier l'ouverture de la base de donn�
if(!db->open())
{
return false;
}
return true;
}

Santosh Reddy
3rd August 2013, 14:01
So do you realy want to create and open new database connection each time an item in the table is edited? and are you deleting it when editor is done?

You use QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate); only for the specific column, then you will not need to check the column number in the createEditor.

I think you are missing to mention somthing else...

advseo32
3rd August 2013, 18:48
So do you realy want to create and open new database connection each time an item in the table is edited? and are you deleting it when editor is done?

You use QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate); only for the specific column, then you will not need to check the column number in the createEditor.



I think you are missing to mention somthing else...

no i don't delete a connexion

Added after 7 minutes:

her is exactly what i want:

I have Qtablewidget
when the user clicks in column number one, the Qcombobox show up and get it content from querying
a database named "DBgestionstock", so the user can select an item from a list in Qcombobox

after implementing QstyledItemDelegate:

i get the Qcombobox show up with required content :) and that's what i want. so ( no problem in column number one )
but for other columns , the cells aren't editable( Qtablewidget cells are editable by default!!)

her is my complete code

connect.h


static bool creeConnexion()
{
QSqlDatabase *db ;
db = new QSqlDatabase;
*db = QSqlDatabase::addDatabase("QSQLITE") ;
db->setHostName("localhost");
db->setDatabaseName("gestionstockDB.db");
db->setPassword("");
db->setUserName("");
// Verifier l'ouverture de la base de donné
if(!db->isOpen())
{
if(!db->open())
{
return false;
}
return true;

}
return true;

}


comboboxDelegate.h


#include <QStyledItemDelegate>
#include <QComboBox>
class comboBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit comboBoxDelegate(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;


signals:

public slots:

};



comboboxDelegate.cpp


#include "comboboxdelegate.h"
#include <connect.h>
comboBoxDelegate::comboBoxDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
}

QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{

if(creeConnexion())
{
if(index.column() == 1 || index.column() == 0)
{
QComboBox *editor = new QComboBox(parent);
editor->setEditable(true);

// Query data
QSqlQuery *query = new QSqlQuery("select designation from Produit") ;
while(query->next())
editor->addItem(query->value(0).toString());

return editor;
}

}else
return QStyledItemDelegate::createEditor(parent,option,in dex);

}

void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QVariant value = index.model()->data(index,Qt::EditRole) ;
QComboBox *comboBox = static_cast<QComboBox*>(editor);
comboBox->setCurrentIndex(comboBox->findText(value.toString()));
}

void comboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
model->setData(index,comboBox->currentText(),Qt::EditRole);
}

void comboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}


i wish that i'm clear now :)

ChrisW67
3rd August 2013, 22:18
When you call createEditor() you call creeConnexion(), which always returns true. If the column is 0 or 1 you return an editor, otherwise your code exits the function with an undefined value. The view will likely crash the program when it tries to use the " editor" you returned. Only if creeConnexion() failed would a default editor be returned.

This could have been discovered for yourself with 30 seconds of debugger time single-stepping the delegate code after discovering the crash.


Other observations.

Every time your view calls createEditor() you:

Allocate a new QSqlDatabase object on the heap, a memory leak.
Create a new Sqlite database Connection as the new default connection invalidating every existing connection. This will possibly cause crashes elsewhere in your program.
Check that the database opens but not that it has anything in it. Sqlite can "open" an empty or non-existent file: that is how it creates a new database.
Use a relative path to a database file, so there is a good chance that it does not exist where you think it does.
When creeConnexion() returns true (it almost always will) you create a QSqlQuery on the heap and create another memory leak.


In setEditorData() and setModelData() you assume that qobject_cast() succeeded. This will crash when called on column that is not a QComboBox editor.

advseo32
3rd August 2013, 23:44
i have rewrited the code again but also it crashes when i return the default editor

her is my code so far

comboBoxDelegate.h


#include <QStyledItemDelegate>
#include <QComboBox>
#include <QSqlDatabase>
#include <QSqlQuery>
class comboBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit comboBoxDelegate(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;


signals:

public slots:
private:
QSqlDatabase *m_db;
QSqlQuery *m_query;

};


comboBoxDelegate.cpp



#include "comboboxdelegate.h"
#include <QMessageBox>
comboBoxDelegate::comboBoxDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
m_db = new QSqlDatabase;
*m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db->setHostName("localhost");
m_db->setDatabaseName("gestionstockDB.db");
m_db->setPassword("");
m_db->setUserName("");
if(m_db->open())
m_query = new QSqlQuery("select designation from Produit") ;
}

QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 1)
{
if(m_db->open())
{
QComboBox *editor = new QComboBox(parent);
editor->setEditable(true);
while(m_query->next())
editor->addItem(m_query->value(0).toString());
return editor;
}else{
QMessageBox::critical(parent,"Erreur Connexion ","Erreur, lors de la connexion au base de donnée");
return QStyledItemDelegate::createEditor(parent,option,in dex);
}
}else
return QStyledItemDelegate::createEditor(parent,option,in dex);

}

void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QVariant value = index.model()->data(index,Qt::EditRole) ;
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
comboBox->setCurrentIndex(comboBox->findText(value.toString()));
}

void comboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
model->setData(index,comboBox->currentText(),Qt::EditRole);
}

void comboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}

ChrisW67
4th August 2013, 04:49
Have you bothered to determine where it is crashing? Tell us which line it crashes on and which column you are trying to edit at the time. There are clues in my earlier post.

advseo32
4th August 2013, 08:06
When i click on column number one, so , her enter her



if(index.column() == 1)
{
if(m_db->open())
{
QComboBox *editor = new QComboBox(parent);
editor->setEditable(true);
while(m_query->next())
editor->addItem(m_query->value(0).toString());
return editor;
}else{
QMessageBox::critical(parent,"Erreur Connexion ","Erreur, lors de la connexion au base de donnée");
return QStyledItemDelegate::createEditor(parent,option,in dex);
}


because m_db->open() is always "true" , he never execute this line

return QStyledItemDelegate::createEditor(parent,option,in dex);

but in other cases

if(index.column() != 1)

he execute this line


return QStyledItemDelegate::createEditor(parent,option,in dex);

so, it crashes her

ChrisW67
4th August 2013, 08:54
At what line does it crash and what column were you trying to edit at the time?
Run the program in your debugger. Make it crash. Look at the stack back trace and find the line in your delegate code that is mentioned closest to the top of the stack. Look at the value of the variables at that time. I bet you will find a null pointer.

If it is crashing when you edit a column other than 1 then I bet it is not crashing in createEditor() but setEditorData(). However, I cannot tell you certainly where it is crashing... only you can tell us.

advseo32
4th August 2013, 09:23
Yes you're right :) it crashes on setEditorData()

I tried to edit the column Zéro
It's crashed on line 42
the value of "value" variable is invalid because index is not valid also ; ----> line 40

her is the code
#include "comboboxdelegate.h"
#include <QMessageBox>
comboBoxDelegate::comboBoxDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
m_db = new QSqlDatabase;
*m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db->setHostName("localhost");
m_db->setDatabaseName("gestionstockDB.db");
m_db->setPassword("");
m_db->setUserName("");
if(m_db->open())
m_query = new QSqlQuery("select designation from Produit") ;
}

QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{ if(!index.isValid())
return QStyledItemDelegate::createEditor(parent,option,in dex);
if(index.column() == 1)
{

if(m_db->open())
{
QComboBox *editor = new QComboBox(parent);
editor->setEditable(true);
while(m_query->next())
editor->addItem(m_query->value(0).toString());
return editor;
}else{
QMessageBox::critical(parent,"Erreur Connexion ","Erreur, lors de la connexion au base de donnée");
return QStyledItemDelegate::createEditor(parent,option,in dex);
}
}else
return QStyledItemDelegate::createEditor(parent,option,in dex);

}

void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QVariant value = index.model()->data(index,Qt::EditRole) ;
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
comboBox->setCurrentIndex(comboBox->findText(value.toString()));
}

void comboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
model->setData(index,comboBox->currentText(),Qt::EditRole);
}

void comboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}

advseo32
4th August 2013, 18:41
it works for column 1 and show Qcombobox perfectly , but when i have clicks on column 0 ( != 1)

It craches on line 35 in setEditorData() function , i can't figured out the problem happened their


#include "comboboxdelegate.h"
#include <QMessageBox>
comboBoxDelegate::comboBoxDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
m_db = new QSqlDatabase;
*m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db->setHostName("localhost");
m_db->setDatabaseName("gestionstockDB.db");
m_db->setPassword("");
m_db->setUserName("");


}

QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() != 1)
return QStyledItemDelegate::createEditor(parent, option, index);
QComboBox* editor = new QComboBox(parent);
editor->setEditable(true);
if(m_db->open())
{
QSqlQuery m_query("select designation from Produit") ;
while(m_query.next())
editor->addItem(m_query.value(0).toString());
return editor;
}

}

void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column() != 1)
QStyledItemDelegate::setEditorData(editor, index);
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
int value = index.model()->data(index,Qt::EditRole).toUInt();
comboboxDelgate->setCurrentIndex(value);
}


void comboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if(index.column() !=1)
QStyledItemDelegate::setModelData(editor, model, index);
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
model->setData(index,comboboxDelgate->currentText(),Qt::EditRole);
}


void comboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}

ChrisW67
4th August 2013, 23:03
You are telling me it crashes:


void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column() != 1)
QStyledItemDelegate::setEditorData(editor, index); // <<<<< here
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
int value = index.model()->data(index,Qt::EditRole).toUInt();
comboboxDelgate->setCurrentIndex(value);
}

I find that hard to believe. I could believe:


void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column() != 1)
QStyledItemDelegate::setEditorData(editor, index);
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
int value = index.model()->data(index,Qt::EditRole).toUInt();
comboboxDelgate->setCurrentIndex(value); // <<<< crashing here
}

especially if this:


QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() != 1)
return QStyledItemDelegate::createEditor(parent, option, index);
QComboBox* editor = new QComboBox(parent);
editor->setEditable(true);
if(m_db->open()) // <<<< is false
{
QSqlQuery m_query("select designation from Produit") ;
while(m_query.next())
editor->addItem(m_query.value(0).toString());
return editor;
}
// <<< what is returned now?
}



You need to be more methodical. Put a break point in each function of your delegate and single step through each. Inspect each step and variable at each step and understand why things are happening the way they are.

advseo32
5th August 2013, 00:37
Now it's working , thank's ChrisW67

You're right in every point, it crashes at this line

comboboxDelgate->setCurrentIndex(value);
another problem is don't check if(m_db->open == false )
I wish you to inform me if my code is bad, is good, is very good, i need your advices :)


her is the code


#include "comboboxdelegate.h"
#include <QMessageBox>
comboBoxDelegate::comboBoxDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
m_db = new QSqlDatabase;
*m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db->setHostName("localhost");
m_db->setDatabaseName("gestionstockDB.db");
m_db->setPassword("");
m_db->setUserName("");


}

QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() != 1)
return QStyledItemDelegate::createEditor(parent, option, index);
QComboBox* editor = new QComboBox(parent);
editor->setEditable(true);
if(m_db->open())
{
QSqlQuery m_query("select designation from Produit") ;
while(m_query.next())
editor->addItem(m_query.value(0).toString());
return editor;
}else
return QStyledItemDelegate::createEditor(parent, option, index);

}

void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column() != 1)
QStyledItemDelegate::setEditorData(editor, index);
else{
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
int value = index.model()->data(index,Qt::EditRole).toUInt();
comboboxDelgate->setCurrentIndex(value);
}
}


void comboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if(index.column() !=1)
QStyledItemDelegate::setModelData(editor, model, index);
else{
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
model->setData(index,comboboxDelgate->currentText(),Qt::EditRole);
}
}


void comboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}

ChrisW67
5th August 2013, 02:25
Look at createEditor(): What type of editor is returned for column1 if the database open() fails?
Once it has the editor, the view calls setEditorData() to load the editor.
What pointer value will qobject_cast<QComboBox*>() return for the type of editor you created when the database open() failed?
What happens when you use that value?

In your last listing:
Delete line 29.
Remove "else" from line 28.
Move line 27 after line 28.
How does that change the behaviour?

advseo32
5th August 2013, 09:25
Look at createEditor(): What type of editor is returned for column1 if the database open() fails?
Once it has the editor, the view calls setEditorData() to load the editor.
What pointer value will qobject_cast<QComboBox*>() return for the type of editor you created when the database open() failed?
What happens when you use that value?

In your last listing:
Delete line 29.
Remove "else" from line 28.
Move line 27 after line 28.
How does that change the behaviour?

No behaviour changed, because m_db->open() == always true and never fails

but now i have figured out what you mean,

with old code when m_db->open() fails createEditor() return nothing
so, qobject_cast<QComboBox*>() also return nothing, so the programme crashes

her is your revised code



QWidget *comboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() != 1 )
return QStyledItemDelegate::createEditor(parent, option, index);
QComboBox* editor = new QComboBox(parent);
editor->setEditable(true);
if(m_db->open())
{
QSqlQuery m_query("select designation from Produit") ;
while(m_query.next())
editor->addItem(m_query.value(0).toString());
}
return editor;

}

void comboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if(index.column() != 1)
QStyledItemDelegate::setEditorData(editor, index);
else{
QComboBox *comboboxDelgate = qobject_cast<QComboBox*>(editor);
int value = index.model()->data(index,Qt::EditRole).toUInt();
comboboxDelgate->setCurrentIndex(value);
}
}