Brandybuck
10th April 2006, 07:23
I am getting some strange behavior that has me stumped. An otherwise working model/view/delegate program will crash if a static dialog is used within the Method::setData() or Delegate::setModelData() methods. The program will pop up two dialogs, then segfault when both are closed.
I am trying to use a QMessageBox::warning() when the user enters invalid data. This is something the program needs to do. I get the same behavior with other static dialogs (QColorDialog, etc). It happens with both QTableView and QListView. The double dialog and crash happens when the user presses the enter or tab keys when finished editing in the delegate. It does NOT happen if the user clicks elsewhere in the view to finish editing.
I have created a tiny sample program to demonstrate. It's as short as I can get it with both a model and delegate. Remove the QMessageBox dialog and the program works. Keep it in and watch the strangeness when you edit a value.
#include <QtGui>
class TestModel : public QAbstractTableModel {
Q_OBJECT
public:
TestModel(QObject *parent);
~TestModel();
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
QStringList items;
};
class TestDelegate : public QItemDelegate
{
Q_OBJECT
public:
TestDelegate(QObject *parent = 0);
~TestDelegate();
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;
};
#include <QtGui>
#include "model.h"
TestModel::TestModel(QObject *parent) : QAbstractTableModel(parent)
{
items << "one" << "two" << "three" << "four";
}
TestModel::~TestModel() {}
QVariant TestModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
if (index.row() >= items.count()) return QVariant();
if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
return items[index.row()];
} else {
return QVariant();
}
}
bool TestModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
if (!index.isValid()) return false;
if (index.row() >= items.count()) return false;
if (role != Qt::EditRole) return false;
QMessageBox::information(0, "Test", "This is a test");
items[index.row()] = value.toString();
emit dataChanged(index, index);
return true;
}
Qt::ItemFlags TestModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}
int TestModel::rowCount(const QModelIndex &) const
{
return items.count();
}
int TestModel::columnCount(const QModelIndex &) const
{
return 1;
}
TestDelegate::TestDelegate(QObject *parent) : QItemDelegate(parent) {}
TestDelegate::~TestDelegate() {}
QWidget *TestDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/*option*/,
const QModelIndex &index) const
{
QStringList items;
items << "one" <<"two" <<"three" <<"four";
QLineEdit *edit = new QLineEdit(parent);
edit->installEventFilter(const_cast<TestDelegate*>(this));
return edit;
}
void TestDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QVariant value = index.model()->data(index, Qt::EditRole);
QLineEdit *edit =static_cast<QLineEdit*>(editor);
if (!edit) return;
edit->setText(value.toString());
}
void TestDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QLineEdit *edit = static_cast<QLineEdit*>(editor);
if (!edit) return;
QVariant value = edit->text();
model->setData(index, value);
}
void TestDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/*index*/) const
{
if (editor) editor->setGeometry(option.rect);
}
#include <QtGui>
#include "model.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TestModel model(0);
QTableView view;
view.setModel(&model);
TestDelegate delegate;
view.setItemDelegate(&delegate);
view.show();
return app.exec();
}
I am using qt-4.1.2 on FreeBSD 6.0. I am going to submit this a bug to Trolltech as well, as I've not found anything similar in their tracker.
I am trying to use a QMessageBox::warning() when the user enters invalid data. This is something the program needs to do. I get the same behavior with other static dialogs (QColorDialog, etc). It happens with both QTableView and QListView. The double dialog and crash happens when the user presses the enter or tab keys when finished editing in the delegate. It does NOT happen if the user clicks elsewhere in the view to finish editing.
I have created a tiny sample program to demonstrate. It's as short as I can get it with both a model and delegate. Remove the QMessageBox dialog and the program works. Keep it in and watch the strangeness when you edit a value.
#include <QtGui>
class TestModel : public QAbstractTableModel {
Q_OBJECT
public:
TestModel(QObject *parent);
~TestModel();
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
QStringList items;
};
class TestDelegate : public QItemDelegate
{
Q_OBJECT
public:
TestDelegate(QObject *parent = 0);
~TestDelegate();
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;
};
#include <QtGui>
#include "model.h"
TestModel::TestModel(QObject *parent) : QAbstractTableModel(parent)
{
items << "one" << "two" << "three" << "four";
}
TestModel::~TestModel() {}
QVariant TestModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) return QVariant();
if (index.row() >= items.count()) return QVariant();
if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
return items[index.row()];
} else {
return QVariant();
}
}
bool TestModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
if (!index.isValid()) return false;
if (index.row() >= items.count()) return false;
if (role != Qt::EditRole) return false;
QMessageBox::information(0, "Test", "This is a test");
items[index.row()] = value.toString();
emit dataChanged(index, index);
return true;
}
Qt::ItemFlags TestModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) return Qt::ItemIsEnabled;
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}
int TestModel::rowCount(const QModelIndex &) const
{
return items.count();
}
int TestModel::columnCount(const QModelIndex &) const
{
return 1;
}
TestDelegate::TestDelegate(QObject *parent) : QItemDelegate(parent) {}
TestDelegate::~TestDelegate() {}
QWidget *TestDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/*option*/,
const QModelIndex &index) const
{
QStringList items;
items << "one" <<"two" <<"three" <<"four";
QLineEdit *edit = new QLineEdit(parent);
edit->installEventFilter(const_cast<TestDelegate*>(this));
return edit;
}
void TestDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QVariant value = index.model()->data(index, Qt::EditRole);
QLineEdit *edit =static_cast<QLineEdit*>(editor);
if (!edit) return;
edit->setText(value.toString());
}
void TestDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QLineEdit *edit = static_cast<QLineEdit*>(editor);
if (!edit) return;
QVariant value = edit->text();
model->setData(index, value);
}
void TestDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/*index*/) const
{
if (editor) editor->setGeometry(option.rect);
}
#include <QtGui>
#include "model.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TestModel model(0);
QTableView view;
view.setModel(&model);
TestDelegate delegate;
view.setItemDelegate(&delegate);
view.show();
return app.exec();
}
I am using qt-4.1.2 on FreeBSD 6.0. I am going to submit this a bug to Trolltech as well, as I've not found anything similar in their tracker.