Russian Qt Forum
Ноябрь 01, 2024, 02:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО][QAbstractTableModel] segfault при вызове переопределенного removeRows  (Прочитано 10422 раз)
Maquefel
Гость
« : Август 03, 2010, 15:02 »

Добрый день - не могу разобраться с проблемой.

Программа валиться при попытке вызова переопределенного метода removeRows
gdb
Код:
Program received signal SIGSEGV, Segmentation fault.
0x004369f4 in CustomersForm::slDeleteCustomer (this=0x9f85aa0)
    at ..\TrM.plasticity\forms\customersform.cpp:188
188             pModel->removeRows(row, 1, QModelIndex());
(gdb) bt
#0  0x004369f4 in CustomersForm::slDeleteCustomer (this=0x9f85aa0)
    at ..\TrM.plasticity\forms\customersform.cpp:188
#1  0x0044507a in CustomersForm::qt_metacall (this=0x9f85aa0,
    _c=QMetaObject::InvokeMetaMethod, _id=2, _a=0x226e9c)
    at moc\moc_customersform.cpp:130
#2  0x6a201d7c in QMetaObject::metacall (object=0x9f85aa0,
    cl=QMetaObject::InvokeMetaMethod, idx=38, argv=0x226e9c)
    at kernel\qmetaobject.cpp:237
#3  0x6a211b94 in QMetaObject::activate (sender=0xa00e010, m=0x1909000,
    local_signal_index=1, argv=0x226e9c) at kernel\qobject.cpp:3287
#4  0x01116338 in QAction::triggered (this=0xa00e010, _t1=false)
    at tmp/moc/debug_shared/moc_qaction.cpp:263
#5  0x01115889 in QAction::activate (this=0xa00e010, event=QAction::Trigger)
    at kernel\qaction.cpp:1255
#6  0x01517454 in QMenuPrivate::activateCausedStack (this=0xa047ab0,
    causedStack=@0x226f6c, action=0xa00e010, action_e=QAction::Trigger,
    self=true) at widgets\qmenu.cpp:1002
#7  0x01517893 in QMenuPrivate::activateAction (this=0xa047ab0,
    action=0xa00e010, action_e=QAction::Trigger, self=true)
    at widgets\qmenu.cpp:1094
#8  0x0151b9bb in QMenu::mouseReleaseEvent (this=0x229dd0, e=0x2276f8)
    at widgets\qmenu.cpp:2312
#9  0x0116ced2 in QWidget::event (this=0x229dd0, event=0x2276f8)
    at kernel\qwidget.cpp:8044
#10 0x0151c011 in QMenu::event (this=0x229dd0, e=0x2276f8)
    at widgets\qmenu.cpp:2421
#11 0x01122526 in QApplicationPrivate::notify_helper (this=0x3e5ca0,
    receiver=0x229dd0, e=0x2276f8) at kernel\qapplication.cpp:4302
#12 0x01120729 in QApplication::notify (this=0x22ff40, receiver=0x229dd0,
    e=0x2276f8) at kernel\qapplication.cpp:3867
#13 0x6a1fd47a in QCoreApplication::notifyInternal (this=0x22ff40,
    receiver=0x229dd0, event=0x2276f8) at kernel\qcoreapplication.cpp:726
#14 0x01779506 in QCoreApplication::sendSpontaneousEvent (receiver=0x229dd0,
    event=0x2276f8)
    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:218
#15 0x0111ef46 in QApplicationPrivate::sendMouseEvent (receiver=0x229dd0,
    event=0x2276f8, alienWidget=0x0, nativeWidget=0x229dd0,
    buttonDown=0x1b7841c, lastMouseReceiver=@0x1b78420, spontaneous=true)
    at kernel\qapplication.cpp:2965
#16 0x01187e6b in QETWidget::translateMouseEvent (this=0x229dd0,
    msg=@0x227bac) at kernel\qapplication_win.cpp:3171
#17 0x011834db in QtWndProc@16 (hwnd=0x2a090e, message=514, wParam=0,
    lParam=1966130) at kernel\qapplication_win.cpp:1629
#18 0x7e368734 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
#19 0x002a090e in ?? ()
#20 0x00000202 in ?? ()
#21 0x7e368816 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
#22 0x01182ab3 in qt_is_translatable_mouse_event (message=0)
    at kernel\qapplication_win.cpp:1401
#23 0x7e3689cd in USER32!GetWindowLongW () from C:\WINDOWS\system32\user32.dll
#24 0x00000000 in ?? ()

class TMCustomerItemModel : public QAbstractTableModel
переопределенная модель
Код:
class TMCustomer;
class TMCustomerItemModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    // INQUIRY
    TMCustomerItemModel(QString sDb, QObject* parent = 0);
    int rowCount(const QModelIndex &parent = QModelIndex()) const {Q_UNUSED(parent);return plCustomers.size();}
    int columnCount(const QModelIndex &parent = QModelIndex()) const {Q_UNUSED(parent);return 5;}
    QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const;        
    bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
    bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex());
    bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
    Qt::ItemFlags flags(const QModelIndex &index) const;
private:
    // CLASS MEMBERS
    QList<TMCustomer*> plCustomers;
    QSqlDatabase db;
};

место вызова
Код:
void CustomersForm::slDeleteCustomer()
{
    QItemSelectionModel *selectionModel = ui->lwCustomers->selectionModel();
    QModelIndexList indexes = selectionModel->selectedRows();
    QModelIndex index;
    ui->lwCustomers->setUpdatesEnabled(false);
    foreach (index, indexes) {
        int row = index.row();
        qDebug() << "CustomersForm::slDeleteCustomer() called on" << row;
        pModel->removeRows(row, 1, QModelIndex());
    }
    ui->lwCustomers->setUpdatesEnabled(true);
}

Прошу совета.
« Последнее редактирование: Август 17, 2010, 09:00 от Maquefel » Записан
crossly
Гость
« Ответ #1 : Август 03, 2010, 15:47 »

а можно на реализацию метода посмотреть??
Записан
Maquefel
Гость
« Ответ #2 : Август 03, 2010, 15:56 »

Прошу:
Дебаг не выводиться - валиться раньше.
Код:
bool TMCustomerItemModel::removeRows(int position, int rows, const QModelIndex &index)
{
    qDebug() << "TMCustomerItemModel::removeRows called:" << position << rows;
    Q_UNUSED(index);
    this->beginRemoveRows(QModelIndex(), position, position+rows-1);
    for (int row = 0; row < rows; ++row) {
        TMCustomer* pCustomer;
        pCustomer = plCustomers.takeAt(index.row());
        pCustomer->deleteCustomer();
        delete pCustomer;
    }
    this->endRemoveRows();
    return true;
}
Записан
BRE
Гость
« Ответ #3 : Август 03, 2010, 17:10 »

Почитай как работает метод takeAt, что происходит с индексами после его выполнения.
Для примера можно посмотреть как это реализовано в QStringListModel.
Записан
Maquefel
Гость
« Ответ #4 : Август 03, 2010, 18:12 »

Почитай как работает метод takeAt, что происходит с индексами после его выполнения.
Для примера можно посмотреть как это реализовано в QStringListModel.

Проблема в том, что он валится до takeAt.

К тому же он тут не причем.

Пример из ItemViews->Address Book

Код:
 bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
 {
     Q_UNUSED(index);
     beginRemoveRows(QModelIndex(), position, position+rows-1);

     for (int row=0; row < rows; ++row) {
         listOfPairs.removeAt(position);
     }

     endRemoveRows();
     return true;
 }

P.S. Хотя нет реализация removeRows у меня неправильная тем не менее валиться он до вызова функции takeAt. Не выводиться qDebug() << "TMCustomerItemModel::removeRows called:" << position << rows;
« Последнее редактирование: Август 03, 2010, 18:18 от Maquefel » Записан
asvil
Гость
« Ответ #5 : Август 03, 2010, 18:53 »

selectionModel на равенсто нулю почему не проверяете? Если модель для предстваления не установлена, модели "выделения" не существует.
Записан
Maquefel
Гость
« Ответ #6 : Август 03, 2010, 22:35 »

selectionModel на равенсто нулю почему не проверяете? Если модель для предстваления не установлена, модели "выделения" не существует.
Простите я видимо, чего-то не знаю - может я трасерт gdb неправильно читаю? Дело в том что проходит сигнал, валиться в области вызова функции removeRows переопределенной от QAbstractModel. foreach (index, indexes) может продолжать исполнение, если selectionModel === Null? И продолжать цикл вызывая removeRows?
Записан
asvil
Гость
« Ответ #7 : Август 03, 2010, 23:55 »

Да, я не прав, недоглядел. Ну тогда указатель на модель возможно равен нулю?
Записан
Maquefel
Гость
« Ответ #8 : Август 04, 2010, 00:33 »

Да, я не прав, недоглядел. Ну тогда указатель на модель возможно равен нулю?
Нет, или не прошел бы foreach, насколько я помню спецификацию.
Прошу обратить внимание на gdb->bt
Записан
crossly
Гость
« Ответ #9 : Август 04, 2010, 08:50 »

а давайте весь код посмотрим... Улыбающийся
Записан
Maquefel
Гость
« Ответ #10 : Август 04, 2010, 11:31 »

а давайте весь код посмотрим... Улыбающийся
h
Код:
#ifndef CUSTOMERSFORM_H
#define CUSTOMERSFORM_H

#include <QDialog>
#include <QAbstractItemModel>
#include <QSqlDatabase>
#include <QDataWidgetMapper>

namespace Ui {
    class CustomersForm;
}

class TMCustomer;

class TMCustomerItemModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    // INQUIRY
    TMCustomerItemModel(QString sDb, QObject* parent = 0);
    int rowCount(const QModelIndex &parent = QModelIndex()) const {Q_UNUSED(parent);return plCustomers.size();}
    int columnCount(const QModelIndex &parent = QModelIndex()) const {Q_UNUSED(parent);return 5;}
    QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const;       
    bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
    bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex());
    bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex());
    Qt::ItemFlags flags(const QModelIndex &index) const;
private:
    // CLASS MEMBERS
    QList<TMCustomer*> plCustomers;
    QSqlDatabase db;
};

class CustomersForm : public QDialog
{
    Q_OBJECT
public:
    explicit CustomersForm(QWidget *parent = 0);
    ~CustomersForm();

    QAction* addCustomer;
    QAction* deleteCustomer;
    TMCustomerItemModel* pModel;
protected:
    void changeEvent(QEvent *e);
signals:
    void customerSelected(int iId);
private:
    Ui::CustomersForm *ui;
    QDataWidgetMapper *mapper;
private slots:
    void slAddCustomer();
    void slDeleteCustomer();
    void slShowListMenu(const QPoint &point);
};

#endif // CUSTOMERSFORM_H

cpp
Код:
include <QMenu>
#include <QDebug>
#include <QSqlError>
#include <QModelIndex>
#include <QSqlTableModel>

#include "customersform.h"
#include "ui_customersform.h"
#include "trm_wrapper/tmcustomer.h"

TMCustomerItemModel::TMCustomerItemModel(QString sDb, QObject *parent):
        QAbstractTableModel(parent)
{
    db = QSqlDatabase::database(sDb);

    QSqlQuery query(db);
    query.prepare("SELECT id FROM trm_customers");
    query.exec();
    while(query.next()) {
        TMCustomer* pCustomer;
        pCustomer = new TMCustomer(sDb, query.value(0).toInt());
        if(pCustomer->isValid())
            this->plCustomers.append(pCustomer);
    }       
}

QVariant TMCustomerItemModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.row() < 0 || index.row() > plCustomers.size())
        return QVariant();

    if (role == Qt::DisplayRole || role == Qt::EditRole) {
        switch(index.column()) {
            case 0:
                return plCustomers.at(index.row())->getShortName();
                break;
            case 1:
                return plCustomers.at(index.row())->getFullName();
                break;
            case 2:
                return plCustomers.at(index.row())->getChiefShortName();
                break;
            case 3:
                return plCustomers.at(index.row())->getChiefFullName();
                break;
            case 4:
                return plCustomers.at(index.row())->getEmail();
                break;
        }
    }
    return QVariant();
}
bool TMCustomerItemModel::setData(const QModelIndex &index, const QVariant &value, int role) {
    if (index.isValid() && role == Qt::EditRole) {
        int row = index.row();
        bool isOk;
        switch(index.column()) {
            case 0:
                isOk = plCustomers.at(row)->setShortName(value.toString(), false);
                break;
            case 1:
                isOk = plCustomers.at(row)->setFullName(value.toString(), false);
                break;
            case 2:
                isOk = plCustomers.at(row)->setChiefShortName(value.toString(), false);
                break;
            case 3:
                isOk = plCustomers.at(row)->setChiefFullName(value.toString(),false);
                break;
            case 4:
                isOk = plCustomers.at(row)->setEmail(value.toString(), false);
                break;
        }
        if(isOk)
            emit(dataChanged(index, index));
        return isOk;
    }
    return false;
}

bool TMCustomerItemModel::insertRows(int position, int rows, const QModelIndex &index)
{
    Q_UNUSED(position);
    Q_UNUSED(rows);
    Q_UNUSED(index);
    TMCustomer *pCustomer;
    pCustomer = new TMCustomer("trm");
    beginInsertRows(QModelIndex(), rowCount() - 1, rowCount());
    plCustomers.append(pCustomer);
    endInsertRows();
}

bool TMCustomerItemModel::removeRows(int position, int rows, const QModelIndex &index)
{
    qDebug() << "TMCustomerItemModel::removeRows called:" << position << rows;
    Q_UNUSED(index);
    this->beginRemoveRows(QModelIndex(), position, position+rows-1);
    for (int row = 0; row < rows; ++row) {
        TMCustomer* pCustomer;
        pCustomer = plCustomers.takeAt(index.row());
        pCustomer->deleteCustomer();
        delete pCustomer;
    }
    this->endRemoveRows();
    return true;
}

Qt::ItemFlags TMCustomerItemModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
             return Qt::ItemIsEnabled;
    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}

CustomersForm::CustomersForm(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CustomersForm)
{
    ui->setupUi(this);
    //QSqlTableModel* pModel;
    //QSqlDatabase db = QSqlDatabase::database("trm");
    //pModel = new QSqlTableModel(this, db);
    TMCustomerItemModel* pModel;
    pModel = new TMCustomerItemModel(QString("trm"));
    //pModel->setTable("trm_customers");
    //pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    //pModel->select();
    ui->lwCustomers->setModel(pModel);
    ui->lwCustomers->setContextMenuPolicy(Qt::CustomContextMenu);

    addCustomer = new QAction(tr("Добавить заказчика"),this);
    deleteCustomer = new QAction(tr("Удалить заказчика"), this);

    connect(addCustomer, SIGNAL(triggered()), this , SLOT(slAddCustomer()));
    connect(deleteCustomer, SIGNAL(triggered()), this , SLOT(slDeleteCustomer()));

    connect(ui->lwCustomers, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slShowListMenu(const QPoint &)));

    mapper = new QDataWidgetMapper(this);
    mapper->setModel(pModel);
    mapper->addMapping(ui->leCustomerNameShort, 0);
    mapper->addMapping(ui->leCustomerNameFull, 1);
    mapper->addMapping(ui->leGeneralDirectorShortName, 2);
    mapper->addMapping(ui->leGeneralDirectorName, 3);
    mapper->addMapping(ui->leEmail, 4);
    mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
    connect(ui->lwCustomers, SIGNAL(clicked(QModelIndex)), mapper, SLOT(setCurrentModelIndex(QModelIndex)));
}

void CustomersForm::slShowListMenu(const QPoint &point)
{
    QList<QAction *> actions;
    actions.append(addCustomer);
    if (ui->lwCustomers->indexAt(point).isValid()) {
        QModelIndex index = ui->lwCustomers->indexAt(point);

        actions.append(deleteCustomer);
    }
    if (actions.count() > 0)
        QMenu::exec(actions, ui->lwCustomers->mapToGlobal(point));
}

CustomersForm::~CustomersForm()
{
    delete ui;
}

void CustomersForm::slAddCustomer()
{
    //TMCustomer *pCustomer = new TMCustomer("trm", tr("Новый заказчик"));
    //if(pCustomer->isValid())
    //    pModel->append(pCustomer);
}

void CustomersForm::slDeleteCustomer()
{
    QItemSelectionModel *selectionModel = ui->lwCustomers->selectionModel();
    QModelIndexList indexes = selectionModel->selectedRows();
    QModelIndex index;
    ui->lwCustomers->setUpdatesEnabled(false);
    foreach (index, indexes) {
        int row = index.row();
        qDebug() << "CustomersForm::slDeleteCustomer() called on" << row;
        pModel->removeRows(row, 1, QModelIndex());
    }
    ui->lwCustomers->setUpdatesEnabled(true);
}

void CustomersForm::changeEvent(QEvent *e)
{
    QDialog::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
Записан
crossly
Гость
« Ответ #11 : Август 04, 2010, 11:36 »

а можно вопрос.... для чего этот огород с TCustomer и моделью... может можно было обойтись QSqlQueryModel или QSqlTableModel ??
Записан
Maquefel
Гость
« Ответ #12 : Август 04, 2010, 11:42 »

а можно вопрос.... для чего этот огород с TCustomer и моделью... может можно было обойтись QSqlQueryModel или QSqlTableModel ??

Можно, дело в том, что потом планируеться на две базы работать. Одна не принадлежит моему приложению, и её структура, мягко говоря не подходит для работы с QSqlTableModel.
Записан
Maquefel
Гость
« Ответ #13 : Август 09, 2010, 11:15 »

Стало еще забавнее, сегфалт при вызове size

Код:
Program received signal SIGSEGV, Segmentation fault.
0x004dbd0e in QListData::isEmpty (this=0xbaadf015)
    at ../../Qt/4.7.0-beta2/include/QtCore/../../src/corelib/tools/qlist.h:95
95          inline bool isEmpty() const { return d->end  == d->begin; }
(gdb) x 0xbaadf015
0xbaadf015:     Cannot access memory at address 0xbaadf015
(gdb) bt
#0  0x004dbd0e in QListData::isEmpty (this=0xbaadf015)
    at ../../Qt/4.7.0-beta2/include/QtCore/../../src/corelib/tools/qlist.h:95
#1  0x004dad5d in QList<TMCustomer*>::isEmpty (this=0xbaadf015)
    at ../../Qt/4.7.0-beta2/include/QtCore/../../src/corelib/tools/qlist.h:139
#2  0x00444b8f in CustomersForm::slItemSelected (this=0xc759a78, index=...)
    at ..\TrM.plasticity\forms\customersform.cpp:179
#3  0x00455ee1 in CustomersForm::qt_metacall (this=0xc759a78,
    _c=QMetaObject::InvokeMetaMethod, _id=4, _a=0x2290f8)
    at moc\moc_customersform.cpp:134
#4  0x6a226f52 in QMetaObject::metacall (object=0xc759a78,
    cl=QMetaObject::InvokeMetaMethod, idx=40, argv=0x2290f8)
    at kernel\qmetaobject.cpp:237
#5  0x6a23b003 in QMetaObject::activate (sender=0xc75e330, m=0x18353a4,
    local_signal_index=1, argv=0x2290f8) at kernel\qobject.cpp:3272
#6  0x0146829e in QAbstractItemView::clicked (this=0xc75e330, _t1=...)
    at tmp/moc/debug_shared/moc_qabstractitemview.cpp:331
#7  0x0145af1c in QAbstractItemView::mouseReleaseEvent (this=0xc75e330,
    event=0x229ee4) at itemviews\qabstractitemview.cpp:1789
#8  0x014772bf in QListView::mouseReleaseEvent (this=0xc75e330, e=0x229ee4)
    at itemviews\qlistview.cpp:796
#9  0x00f0c80f in QWidget::event (this=0xc75e330, event=0x229ee4)
    at kernel\qwidget.cpp:8157
#10 0x0131391e in QFrame::event (this=0xc75e330, e=0x229ee4)
    at widgets\qframe.cpp:557
#11 0x013b7735 in QAbstractScrollArea::viewportEvent (this=0xc75e330,
    e=0x229ee4) at widgets\qabstractscrollarea.cpp:1043
#12 0x014597a4 in QAbstractItemView::viewportEvent (this=0xc75e330,
    event=0x229ee4) at itemviews\qabstractitemview.cpp:1619
#13 0x01672dcb in QAbstractScrollAreaPrivate::viewportEvent (this=0xc7799e8,
    event=0x229ee4) at widgets/qabstractscrollarea_p.h:100
#14 0x01671190 in QAbstractScrollAreaFilter::eventFilter (this=0xc753f48,
    o=0xc6c8330, e=0x229ee4) at widgets/qabstractscrollarea_p.h:116
#15 0x6a2216ed in QCoreApplicationPrivate::sendThroughObjectEventFilters (
    this=0x3e5ed0, receiver=0xc6c8330, event=0x229ee4)
    at kernel\qcoreapplication.cpp:847
#16 0x00ebd951 in QApplicationPrivate::notify_helper (this=0x3e5ed0,
    receiver=0xc6c8330, e=0x229ee4) at kernel\qapplication.cpp:4385
#17 0x00ebb631 in QApplication::notify (this=0x22ff20, receiver=0xc6c8330,
    e=0x229ee4) at kernel\qapplication.cpp:3952
#18 0x6a22141e in QCoreApplication::notifyInternal (this=0x22ff20,
    receiver=0xc6c8330, event=0x229ee4) at kernel\qcoreapplication.cpp:732
#19 0x0163114a in QCoreApplication::sendSpontaneousEvent (receiver=0xc6c8330,
    event=0x229ee4)
    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:218
#20 0x00eb9913 in QApplicationPrivate::sendMouseEvent (receiver=0xc6c8330,
    event=0x229ee4, alienWidget=0xc6c8330, nativeWidget=0xc759a78,
    buttonDown=0x18d92bc, lastMouseReceiver=..., spontaneous=true)
    at kernel\qapplication.cpp:3049
#21 0x00f2d85c in QETWidget::translateMouseEvent (this=0xc759a78, msg=...)
    at kernel\qapplication_win.cpp:3300
#22 0x00f278ad in QtWndProc@16 (hwnd=0x1b0836, message=514, wParam=0,
    lParam=2818240) at kernel\qapplication_win.cpp:1657
#23 0x7e368734 in USER32!GetDC () from C:\WINDOWS\system32\user32.dll
#24 0x00000000 in ?? ()
(gdb) x 0xbaadf015
0xbaadf015:     Cannot access memory at address 0xbaadf015
(gdb)
Записан
Maquefel
Гость
« Ответ #14 : Август 17, 2010, 09:01 »

В функции переопределил член класса pModel, отсюда нулевой указатель.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.05 секунд. Запросов: 20.