crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> beginInsertRows, Сложная модель
PAFOS
  опции профиля:
сообщение 21.2.2011, 15:18
Сообщение #1


Активный участник
***

Группа: Участник
Сообщений: 258
Регистрация: 27.12.2010
Из: Дмитров
Пользователь №: 2309

Спасибо сказали: 29 раз(а)




Репутация:   8  


Здравствуйте. Нужен хелп.

Есть 2 SQL таблицы.

leafs( leaf_id int primary key auto_increment, name text )
sizes( size_id int primary key auto_increment, leaf_id int, name )

соответственно sizes.size_id = leaf_id

Сделал свою модель. В моделе храню две QSqlTableModel - одна для leafs, другая для sizes
В своей моделе сделал иерархию. Корень записи из leafs, ветка 1-го уровня - записи из sizes.

Для показа/редиктирования модели сделал два виджета QTableView.
Один показывает leafs, другой sizes. Когда выбираю строку из leafs, генерится сигнал currentRowChanged(QModelIndex current,QModelIndex previous). В нем я делаю m_sizesModel->setRootIndex(current);

Все работает, записи добавляются и в ту и другую таблицы, данные изменяются корректно.

Когда доходит дело до удаления записей начинается лажа.
согласно документации для удаления записей я должен переопределить метод removeRows( int row, int count, QModelIndex parent)
в нем я должен вызвать метод beginRemoveRows() прежде чем удалять данные и endRemoveRows() после того как данные удалены.

В метод приходят корректные аргументы (т.е. валидный индекс, номер строки и кол-во)
при вызове метода beginRemoveRows(parent,row,row+count-1) прога намертво виснет!

даже не знаю в чем беда! :blink:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Rocky
  опции профиля:
сообщение 21.2.2011, 15:26
Сообщение #2


Старейший участник
****

Группа: Участник
Сообщений: 530
Регистрация: 22.12.2008
Из: Санкт-Петербург
Пользователь №: 463

Спасибо сказали: 22 раз(а)




Репутация:   7  


Цитата(PAFOS @ 21.2.2011, 15:18) *
соответственно sizes.size_id = leaf_id

Или sizes.leaf_id = leafs.leaf_id ?


Цитата(PAFOS @ 21.2.2011, 15:18) *
В метод приходят корректные аргументы (т.е. валидный индекс, номер строки и кол-во)
при вызове метода beginRemoveRows(parent,row,row+count-1) прога намертво виснет!

Точно валидные? А данных много? Может выложишь минимальный компилируемый код, демонстрирующий проблему?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
PAFOS
  опции профиля:
сообщение 25.2.2011, 17:58
Сообщение #3


Активный участник
***

Группа: Участник
Сообщений: 258
Регистрация: 27.12.2010
Из: Дмитров
Пользователь №: 2309

Спасибо сказали: 29 раз(а)




Репутация:   8  


Разобрался. Неверно указывал parent для индексов, поэтому получались бесконечные вызовы beginRemoveRows;
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
PAFOS
  опции профиля:
сообщение 26.2.2011, 13:29
Сообщение #4


Активный участник
***

Группа: Участник
Сообщений: 258
Регистрация: 27.12.2010
Из: Дмитров
Пользователь №: 2309

Спасибо сказали: 29 раз(а)




Репутация:   8  


что-то я поторопился...

Упростил задачу до нельзя.

Есть две таблицы PROFILE_SYSTEMS и PROFILES
структура PROFILE_SYSTEMs: system_id INT PK NN AI, name TEXT
структура PROFILES: profile_id INT PK NN AI, system_id INT NN, name TEXT

соответственно вырисовывается иерархия - корень - PROFILE_SYSTEMS.system_id - потомок PROFILES.profile_id
Сделал модель, которая содержит в себе две QSqlTableModel
Вот код модели:

Заголовочный файл:

Раскрывающийся текст
class ProfilesModel : public QAbstractItemModel
{
    Q_OBJECT

private:
    QSqlTableModel *m_systemsModel;
    QSqlTableModel *m_profilesModel;

    enum Tables{ SystemsTable, ProfilesTable };

    struct InternalId
    {
        QModelIndex parentIndex;
        Tables table;

        bool operator==( const InternalId &other ) const
        { return parentIndex == other.parentIndex && table == other.table; }
    };

    enum SystemsTableColumns{ s_SystemId, s_Name };
    enum ProfilesTableColumns{ p_ProfileId, p_SystemId, p_Name };



    mutable QList<InternalId> m_internalIds;

    void setCurrentSystem( const QModelIndex &system ) const;

public:
    explicit ProfilesModel(QObject *parent = 0);


    virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
    virtual QModelIndex parent ( const QModelIndex & index ) const;

    virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
    virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;

    virtual bool insertRows ( int row, int count, const QModelIndex & parent = QModelIndex() );
    virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex() );
    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
    virtual int columnCount(const QModelIndex &parent) const;

    virtual Qt::ItemFlags flags ( const QModelIndex & index ) const;

};

#endif // PROFILESMODEL_H


Исходный код:

Раскрывающийся текст
ProfilesModel::ProfilesModel(QObject *parent) :
    QAbstractItemModel(parent)
{
    m_systemsModel = new QSqlTableModel(this);
    m_systemsModel->setTable("profile_systems");
    m_systemsModel->setEditStrategy( QSqlTableModel::OnFieldChange );
    m_systemsModel->select();

    m_profilesModel = new QSqlTableModel(this);
    m_profilesModel->setTable("profiles");
    m_profilesModel->setEditStrategy( QSqlTableModel::OnFieldChange );
    m_profilesModel->select();

}


QModelIndex ProfilesModel::index(int row, int column, const QModelIndex &parent) const
{
    InternalId id;

    if( parent.isValid() )
    {
        id.parentIndex = index(parent.row(),s_SystemId);
        id.table = ProfilesTable;
    }
    else
    {
        id.parentIndex = parent;
        id.table = SystemsTable;
    }



    int index = m_internalIds.indexOf( id );
    if( index == -1 )
    {
        m_internalIds << id;
        index = m_internalIds.count() - 1;
    }

    InternalId &iid = m_internalIds[index];
    return createIndex(row,column,(void*)&iid);
}

QModelIndex ProfilesModel::parent(const QModelIndex &index) const
{
    InternalId *id = static_cast<InternalId*>(index.internalPointer());
    if( id == 0 )
        return QModelIndex();

    return id->parentIndex;
}


bool ProfilesModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    InternalId *id = static_cast<InternalId*>(index.internalPointer());
    if( id == 0 )
        return false;

    switch( id->table )
    {
    case SystemsTable:
        {
            return m_systemsModel->setData( m_systemsModel->index(index.row(), index.column()), value, role);
        }
    case ProfilesTable:
        {
            setCurrentSystem( id->parentIndex );
            return m_profilesModel->setData( m_profilesModel->index(index.row(), index.column()), value, role);
        }
    default:
        {
           return false;
       }
    }
}


QVariant ProfilesModel::data(const QModelIndex &index, int role) const
{
    InternalId *id = static_cast<InternalId*>(index.internalPointer());
    if( id == 0 )
        return QVariant();


    switch( id->table )
    {
    case SystemsTable:
        {
            return m_systemsModel->index( index.row(), index.column() ).data(role);
        }
    case ProfilesTable:
        {
            setCurrentSystem( id->parentIndex );
            return m_profilesModel->index( index.row(), index.column() ).data(role);
        }
    default:
        {
            return QVariant();
        }
    }
}


bool ProfilesModel::insertRows(int row, int count, const QModelIndex &parent)
{
    InternalId *id = static_cast<InternalId*>(parent.internalPointer());
    if( id == 0 )
    {

        QSqlRecord rec = m_systemsModel->record();
        rec.setNull("system_id");
        rec.setValue("name",tr("Unnamed"));

        bool ok = true;
        for( int i = row; i < row+count; i++ )
            ok = m_systemsModel->insertRecord(row,rec);

        if( ok )
        {
            beginInsertRows(parent,row,count+row-1);
            endInsertRows();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {

        QSqlRecord rec = m_profilesModel->record();
        rec.setNull("profile_id");
        rec.setValue("name",tr("Unnamed"));
        rec.setValue("system_id",parent.data(Qt::EditRole));

        bool ok = true;
        int last = row+count;
        for( int i = row; i < last; i++ )
            ok = m_profilesModel->insertRecord(i,rec);

        if(ok)
        {
            beginInsertRows(parent,row,count+row-1);
            endInsertRows();
            return true;
        }
        else
        {
            return false;
        }
    }
}

bool ProfilesModel::removeRows(int row, int count, const QModelIndex &parent)
{
    InternalId *id = static_cast<InternalId*>(parent.internalPointer());
    if( id == 0 )
    {
        if( m_systemsModel->removeRows(row,count) )
        {
            beginRemoveRows(parent,row,row+count-1);
            endRemoveRows();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        setCurrentSystem(parent);

        if( m_profilesModel->removeRows(row,count) )
        {
            beginRemoveRows(parent,row,row+count-1);
            endRemoveRows();
            return true;
        }
        else
        {
            return false;
        }
    }
}


int ProfilesModel::rowCount(const QModelIndex &parent) const
{
    if( parent.isValid() )
    {
        setCurrentSystem(parent);
        return m_profilesModel->rowCount();
    }
    else
    {
        return m_systemsModel->rowCount();
    }
}

int ProfilesModel::columnCount(const QModelIndex &parent) const
{
    if( parent.isValid() )
    {
        return m_profilesModel->columnCount();
    }
    else
    {
        return m_systemsModel->columnCount();
    }
}

Qt::ItemFlags ProfilesModel::flags(const QModelIndex &index) const
{
    InternalId *id = static_cast<InternalId*>(index.internalPointer());
    if( id == 0 )
        return 0;

    switch( id->table )
    {
    case SystemsTable:
        {
            return m_systemsModel->flags( m_systemsModel->index(index.row(),index.column()) );
        }
    case ProfilesTable:
        {
            return m_profilesModel->flags( m_profilesModel->index(index.row(),index.column()) );
        }
    default:
        {
            return 0;
        }
    }
}

void ProfilesModel::setCurrentSystem(const QModelIndex &system) const
{
    QString filter = "system_id = " + system.data(Qt::EditRole).toString();
    if( m_profilesModel->filter() != filter )
        m_profilesModel->setFilter(filter);
}


для показа модели поместил на форму два QListView
один показывает PROFILE_SYSTEMS.name
другой показывает PROFILES.name

вот исходный код


Раскрывающийся текст
ProfilesForm::ProfilesForm(QWidget *parent) :
    QWidget(parent)
{
    setupUi(this);


    m_model = new ProfilesModel();


//    m_tableSizes->setItemDelegate( new QItemDelegate() );
//    m_tableSizes->setSelectionModel( new QItemSelectionModel(m_model) );
    m_listSystem->setModel( m_model );
    m_listSystem->setModelColumn( 1 );
    m_listSystem->setItemDelegate( new QItemDelegate() );
    m_listSystem->setSelectionModel( new QItemSelectionModel(m_model) );


    m_listProfiles->setModel(m_model);
    m_listProfiles->setItemDelegate( new QItemDelegate() );
    m_listProfiles->setSelectionModel( new QItemSelectionModel(m_model) );
    m_listProfiles->setRootIndex( m_model->index(0,0) );
    m_listProfiles->setModelColumn( 2 );

    connect(m_listSystem->selectionModel(),SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),this,SLOT(systemChanged(QModelIndex,QModelIndex)));
}

void ProfilesForm::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        retranslateUi(this);
        break;
    default:
        break;
    }
}

void ProfilesForm::on_m_pushAddProfileSystem_clicked()
{
    m_model->insertRow( m_model->rowCount() );
}

void ProfilesForm::on_m_pushDeleteProfileSystem_clicked()
{
    QModelIndex idx = m_model->index( m_listSystem->currentIndex().row(), 0 );
    m_model->removeRow(idx.row());
}

void ProfilesForm::on_m_pushAddProfile_clicked()
{
    QModelIndex idx = m_model->index( m_listSystem->currentIndex().row(), 0 );
    m_model->insertRow( m_model->rowCount(idx), idx);
}

void ProfilesForm::on_m_pushDeleteProfile_clicked()
{
    QModelIndex idx = m_model->index( m_listSystem->currentIndex().row(), 0 );
    m_model->removeRow( m_listProfiles->currentIndex().row(), idx);
}

void ProfilesForm::systemChanged(const QModelIndex &current, const QModelIndex &)
{
    QModelIndex idx = m_model->index(current.row(),0);
    m_listProfiles->setRootIndex( idx );
    m_listProfiles->setModelColumn( 2 );
}


функция beginRemoveRows() ведет себя очень странно - если в модели больше 3 элементов и я удаляю предпоследний, то возврата из beginRemoveRows() происходит.

Теперь вопрос - каким образом указывать предков для элементов таблицы PROFILES? У меня сейчас так - каждый QModelIndex из таблицы PROFILES имеет предка PROFILE_SYSTEMS.system_id

М
Оборачивайте длинные куски кода в тэг [expand][/expand]
Справка по кнопкам и тэгам форума
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
PAFOS
  опции профиля:
сообщение 26.2.2011, 14:38
Сообщение #5


Активный участник
***

Группа: Участник
Сообщений: 258
Регистрация: 27.12.2010
Из: Дмитров
Пользователь №: 2309

Спасибо сказали: 29 раз(а)




Репутация:   8  


ВОН ОН ГДЕ ЖУК ЗАРЫЛСЯ!!!! :blink:
При удалении QModelIndex (что неизбежно делать надо при removeRows()) я забывал удалять из m_internalIds идентификаторы, тем самым путая логику.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 12.7.2020, 14:43