Как полностью изменить базовые данные QAbstractTableModel?

Это мой первый пост здесь, но я получил большую помощь от всех вас, ребята, так как я начал программировать.

Я новичок в Qt и сейчас пытаюсь сделать свой первый проект. Мой вопрос касается связи между моделью, базовыми данными и представлением.

Сначала я отделил фоновые вещи (хранение данных и т. д.) от графического интерфейса. Теперь у меня есть класс шаблона Matrix, и я написал класс шаблона MatrixModel, который наследуется от QAbstractTableModel. Это работает нормально, это означает, что я могу редактировать таблицу и обновлять значения в представлении и в данных из модели.

Теперь мой вопрос: как изменить данные в модели без написания нового метода?

главное окно.cpp:

matrix<int> m = {{1,2,3},{4,5,6},{7,8,9}};
MatrixModel<int>* model = new MatrixModel<int>(m);
QTableView* tableView = new QTableView;
tableView->setModel(model);

Есть ли способ вызвать m.transpose() для базовых данных модели? Что произойдет, если я изменю m? Влияет ли это на данные модели? Я пробовал много вещей, но ничего не получалось. Одна «проблема» заключается в том, что я не могу использовать стандартный синтаксис сигнала/слота, потому что я работаю с классами шаблонов.

Моя последняя попытка состояла в том, чтобы создать класс обновления в модели:

template<typename T>
void MatrixModel<T>::updateAll() {
    QModelIndex topLeft = index(0,0);
    QModelIndex bottomRight = index(rowCount()-1, columnCount()-1);
    emit dataChanged(topLeft, bottomRight);
}

и я попытался подключить его с помощью кнопки и лямбда-функции:

connect(transposeButton, &QPushButton::clicked, [=,&m,&model]() {
m.transpose(); model->updateAll();
});

но это, похоже, привело к сбою моей программы, если я нажму кнопку. Я действительно в отчаянии xD Надеюсь, вы можете мне помочь. Если вам нужна дополнительная информация, просто спросите ^^

Наилучшие пожелания

Деннис

РЕДАКТИРОВАТЬ 1: Хорошо, пока я понял (с вашей помощью :)), что мне нужно снова написать функции матрицы в модели (например, транспонировать()) и выдать изменения данных оттуда (с помощью emit dataChanged или beginResetModel( )...), но я не могу изменить модели, лежащие в основе данных. если я напишу

Это в главном окне:

connect(transposeButton, &QPushButton::clicked, [&model]() {
    model->transpose();
});

Это в модели:

template<typename T>
void MatrixModel<T>::transpose() {
    m(0,0) = 5;
}

моя программа просто вылетает, если я нажимаю кнопку транспонирования. Если я прокомментирую строку

m(0,0) = 5;

вышел, все работает.

РЕДАКТИРОВАТЬ 2: Возможно, есть проблема с хранилищем данных, поэтому вот мой конструктор копирования и частные переменные моего матричного класса:

private:
std::vector <T> data;
size_t rows, columns;

//Copy constructor
template<typename T>
matrix<T>::matrix(const matrix<T>& other)
    : rows(other.rows), columns(other.columns) {
    data = other.data;
}

person syc    schedule 13.05.2016    source источник
comment
если размеры вашей модели меняются, сигнала dataChanged() недостаточно. Вы должны вызвать beginResetModel() перед изменением данных, а затем вызвать endResetModel(), когда закончите. . .   -  person Mike    schedule 14.05.2016
comment
поэтому, если ваша матрица не является квадратной, вызов transpose(), а затем просто испускание сигнала dataChanged() может привести к сбоям и доступу к недопустимым индексам в вашей матрице.   -  person Mike    schedule 14.05.2016
comment
Хорошо, я понял, но я могу просто вызвать это из моей модели. Но я вызываю функцию m.transpose() из моего mainwindow.cpp, где я не могу вызвать beginResetModel (потому что она защищена). И я не хочу снова писать все функции в своей матричной модели.   -  person syc    schedule 14.05.2016
comment
И кроме того, что я пытаюсь с квадратным, чтобы уменьшить проблемы, которые я должен смотреть. Но одно на ваше усмотрение. Что произойдет, если я выпущу layoutChanged? Разве это не переставить размеры?   -  person syc    schedule 14.05.2016


Ответы (2)


У вас должна быть переменная matrix в качестве закрытого члена в вашей модели, чтобы все изменения в matrix выполнялись с помощью функций в вашей модели. это означает, что ваша модель будет иметь общедоступную функцию transpose, которая вызывает transpose для ваших данных matrix, а затем выдает сигнал dataChanged(). И у вас не должно быть прямого доступа к вашему matrix, потому что его изменение без ведома модели не даст того, что вы хотите. таким образом, вы не обязаны вызывать updateAll после каждого изменения переменной matrix, поскольку ваша модель внесла изменения и соответственно обновилась. . .

person Mike    schedule 14.05.2016
comment
Ладно, просто так подумал :P поэтому мне нужно переписать функции для моей модели. Но я читал, что мы не должны использовать resetmodel, потому что он снова все рисует. Не лучше ли излучать сверху слева вниз справа? Кроме того, моя программа зависала, если я пытался вызвать функции модели (даже простые, такие как новая функция транспонирования, где я beginResetModel транспонирую endResetModel . Спасибо за вашу помощь :) - person syc; 14.05.2016
comment
Я понял, что удаление beginResetModel() и endResetModel() работает. Так что редактирование m внутри модели работает. - person syc; 14.05.2016
comment
если размеры вашей модели не изменились, достаточно выпустить dataChanged() , но если ваши размеры меняются, вы должны вызывать такие функции, как beginRemoveRow или beginResetModel, или .. а затем endRemoveRow или endRemoveRow... после изменения структуры данных - person Mike; 14.05.2016
comment
Извините .... это не я прокомментировал xD, может быть, что-то не так с оператором подключения? - person syc; 14.05.2016
comment
Он просто падает. Кажется, это так, если я вызываю функцию модели из лямбда-функции подключения - person syc; 14.05.2016
comment
происходит ли сбой в лямбда-функции? - person Mike; 14.05.2016
comment
Если я отлаживаю, он останавливается на строке с оператором подключения. А точнее не знаю :С - person syc; 14.05.2016
comment
Проблема на 100% в лямбда-функции (и вызывающих операторах там). Если она пуста, она работает, даже с model-›transpose(); IFF функция транспонирования пуста. Но если я напишу там что-то вроде m(0,0)= 10; чтобы изменить базовые данные, программа вылетает, если я нажимаю кнопку. - person syc; 14.05.2016
comment
ваша переменная matrix m является локальной переменной в конструкторе модели? он должен быть членом модели. если это локальная переменная, то сбой происходит из-за того, что матрица может использовать недопустимую память при вызове лямбда-функции. опубликуйте больше кода, чтобы я мог вам помочь. - person Mike; 14.05.2016
comment
У меня есть частная переменная-член m в модели, которая получает данные конструктором (который также принимает матрицу). Все остальное работает (изменения в представлении, затем вызов setData, затем вызов данных для получения записей таблицы), и все изменения в представлении отображаются напрямую. - person syc; 14.05.2016
comment
а как у вас работает конструктор копирования матрицы? использовать только мелкую копию ?? - person Mike; 14.05.2016
comment
хм, ладно... может, в этом проблема... но без графического интерфейса, я думаю, все работает. Мой матричный класс просто использует std::vector‹T›. И мой конструктор копирования просто использует конструктор копирования или вектор, который является глубоким копированием или? - person syc; 14.05.2016
comment
Смотрите мою правку. Просто скажите, что вам нужно ^^ И спасибо за помощь :) - person syc; 14.05.2016

Я понял...

connect(transposeButton, &QPushButton::clicked, [model]() {
    beginResetModel();
    m(0,0)=50;
    endResetModel();
});

работает... модель уже является указателем, поэтому я даю тот же указатель на лямбда-функцию. Теперь мне просто нужно выяснить, что не так с моей функцией транспонирования, потому что она все еще не работает, но сбои исчезли: P спасибо за ваши предложения :)

person syc    schedule 14.05.2016