Использую две модели, как заполнить QComboBox одной моделью
У меня две модели, Users (Имя, Фамилия, Страна) и Countries(Наименование).
Я сделал делегат для комбобокса в поле Страна таблицы Пользователи. Как мне его заполнить данными из таблицы Страны?
Country.cpp
#include "Country.h"
Country::Country()
{
}
void Country::setName(const QString name)
{
m_name = name;
}
QString Country::getName() const
{
return m_name;
}
CountryTable.cpp
#include "CountryTable.h"
CountryTable::CountryTable(QObject *parent) : QAbstractTableModel (parent)
{
listOfCountries = new QList <Country> ();
}
int CountryTable::columnCount(const QModelIndex & parent) const {
return 1;
}
int CountryTable::rowCount(const QModelIndex & parent) const {
return listOfCountries->size();
}
QVariant CountryTable::data(const QModelIndex & index, int role) const {
if (index.isValid() && role == Qt ::DisplayRole)
return getData(index.row(), index.column());
return QVariant ();
}
QVariant CountryTable::getData(int num, int position) const {
switch (position) {
case 0:
return QVariant (listOfCountries->at(num).getName());
default:
return QVariant ();
}
}
bool CountryTable::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid()) {
return false;
}
Country &country = this->getCountry(index);
switch (index.column()) {
case 0:
country.setName(value.toString());
break;
default:
return false;
}
emit dataChanged(index, index);
return true;
}
QVariant CountryTable::headerData(int section, Qt ::Orientation orientation, int role) const {
if (role != Qt ::DisplayRole)
return QVariant ();
if (orientation == Qt ::Vertical)
return QVariant (section + 1);
else
switch (section) {
case 0:
return QVariant ("Name");
default:
return QVariant ();
}
}
Qt ::ItemFlags CountryTable::flags(const QModelIndex & index) const {
return Qt ::ItemIsSelectable | Qt ::ItemIsEnabled | Qt ::ItemIsEditable;
}
Country& CountryTable::getCountry(const QModelIndex & index) const {
return (*listOfCountries)[index.row()];
}
void CountryTable::addCountry(Country& newCountry) {
beginInsertRows(QModelIndex (), listOfCountries->size(), listOfCountries->size());
listOfCountries->append(newCountry);
endInsertRows();
}
void CountryTable::delCountry(const QModelIndex &index) {
beginRemoveRows(QModelIndex (), index.row(), index.row());
listOfCountries->removeAt(index.row());
endRemoveRows();
}
User.cpp
#include "User.h"
QVector<User*> User::usersList;
User::User()
{
usersList.push_back(this);
}
User::~User()
{
}
void User::setName(const QString name)
{
m_name = name;
}
void User::setSurname(const QString surname)
{
m_surname = surname;
}
void User::setCountry(const QString country)
{
m_country = country;
}
QString User::getName() const
{
return m_name;
}
QString User::getSurname() const
{
return m_surname;
}
QString User::getCountry() const
{
return m_country;
}
QVector<User*> User::getAllUsers()
{
return usersList;
}
UsersTable.cpp
#include "UsersTable.h"
#include <QDebug>
UsersTable::UsersTable(QObject *parent) : QAbstractTableModel (parent)
{
listOfUsers = new QList <User> ();
}
int UsersTable::columnCount(const QModelIndex & parent) const {
return 3;
}
int UsersTable::rowCount(const QModelIndex & parent) const {
return listOfUsers->size();
}
QVariant UsersTable::data(const QModelIndex & index, int role) const {
if (index.isValid() && role == Qt ::DisplayRole)
return getData(index.row(), index.column());
return QVariant ();
}
QVariant UsersTable::getData(int num, int position) const {
switch (position) {
case 0:
return QVariant (listOfUsers->at(num).getName());
case 1:
return QVariant (listOfUsers->at(num).getSurname());
case 2:
return QVariant (listOfUsers->at(num).getCountry());
default:
return QVariant ();
}
}
bool UsersTable::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid()) {
return false;
}
User &user = this->getUser(index);
switch (index.column()) {
case 0:
user.setName(value.toString());
break;
case 1:
user.setSurname(value.toString());
break;
case 2:
user.setCountry(value.toString());
break;
default:
return false;
}
emit dataChanged(index, index);
return true;
}
QVariant UsersTable::headerData(int section, Qt ::Orientation orientation, int role) const {
if (role != Qt ::DisplayRole)
return QVariant ();
if (orientation == Qt ::Vertical)
return QVariant (section + 1);
else
switch (section) {
case 0:
return QVariant ("Name");
case 1:
return QVariant ("Surname");
case 2:
return QVariant ("Country");
default:
return QVariant ();
}
}
Qt ::ItemFlags UsersTable::flags(const QModelIndex & index) const {
return Qt ::ItemIsSelectable | Qt ::ItemIsEnabled | Qt ::ItemIsEditable;
}
User& UsersTable::getUser(const QModelIndex & index) const {
return (*listOfUsers)[index.row()];
}
void UsersTable::addUser(User& newUser) {
beginInsertRows(QModelIndex (), listOfUsers->size(), listOfUsers->size());
listOfUsers->append(newUser);
endInsertRows();
}
void UsersTable::delUser(const QModelIndex & index) {
beginRemoveRows(QModelIndex (), index.row(), index.row());
listOfUsers->removeAt(index.row());
endRemoveRows();
}
DelegateComboBox.cpp
#include "DelegateComboBox.h"
#include <QLineEdit>
#include <QComboBox>
#include <QDebug>
DelegateComboBox::DelegateComboBox(const QStringList &country, QObject *parent)
:QStyledItemDelegate(parent), countryList(country)
{ }
QWidget* DelegateComboBox::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QComboBox *comboBox = new QComboBox(parent);
comboBox->addItems(countryList);
comboBox->setCurrentIndex(-1);
return comboBox;
}
void DelegateComboBox::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QComboBox *comboBox = static_cast<QComboBox*>(editor);
if(text.isEmpty()){
QLineEdit *edit=new QLineEdit;
QFont font=edit->font();
font.setBold(true);
font.setItalic(true);
edit->setFont(font);
edit->setPlaceholderText("Select country");
comboBox->setLineEdit(edit);
comboBox->lineEdit()->setReadOnly(true);
return;
}
int idx=comboBox->findText(text);
comboBox->setCurrentIndex(idx);
}
void DelegateComboBox::setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
QString text = comboBox->currentText();
model->setData(index, text, Qt::EditRole);
}
void DelegateComboBox::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
MainWindow.cpp
dataTable = new UsersTable(this);
view = new QTableView (this);
view->setModel(dataTable);
view->resizeColumnsToContents();
add = new QPushButton ("Add new User");
del = new QPushButton ("Delete selected User");
showQDebug = new QPushButton ("Show");
QWidget *box = new QWidget ();
QVBoxLayout *layout = new QVBoxLayout ();
layout->addWidget(view);
QHBoxLayout *buttonLayout = new QHBoxLayout ();
layout->addLayout(buttonLayout);
buttonLayout->addWidget(add);
buttonLayout->addWidget(del);
buttonLayout->addWidget(showQDebug);
box->setLayout(layout);
setCentralWidget(box);
setWindowTitle("Table of Users");
QStringList country;
country<<"Burundi"<<"Burkina Faso"<<"Cambodia"<<"Cameroon";
auto delegate = new DelegateComboBox(country);
view->setItemDelegateForColumn(2, delegate);
connect(add, SIGNAL(clicked()), this, SLOT(addButtonClicked()));
connect(del, SIGNAL(clicked()), this, SLOT(delButtonClicked()));
connect(showQDebug, SIGNAL(clicked()), this, SLOT(showUsersData()));
Как видно, в файле MainWindow, сейчас я просто записываю данные в ручную в QStringList. Подскажите, как взять данные из модели Country?
Ответы (1 шт):
Поле Страна в модели Пользователи это выпадающий список, который вы храните (редактируете) в модели Стран. Значит вам нужно передать указатель на модель Страны в модель Пользователи и работать с ним, а вот ваш делегат ничего не должен об этом знать - его задача - отображение данных.
- Я не буду расписывать все наследования, методы, реализацию и так далее, только "крупными мазками"
UsersTableу меня этоUserTableModel, потому что это модель в виде таблицы, а не сама таблица, тоже самое касаетсяCountryTableModel. И, заметьте, неUsers, аUserи вам рекомендую использовать сущ. в ед. числе для именования типов данных.
Заведем где-нибудь константу-роль:
int CountryRole = Qt::UserRole + 1;
Суть которой в получении текущего списка стран из модели UserTableModel, которая будет служить своеобразной прокси-моделью для CountryTableModel.
class UserTableModel... {
public:
UserTableModel(CountryTableModel* countryModel)
: countryModel(countryModel) {...}
QVariant data(const QModelIndex & index, int role) const {
...
if (role == CountryRole) {
// Передаем текущий список наименований стран из CountryTableModel
return countryModel->countryList(); // QStringList
}
}
private:
CountryTableModel* countryModel;
}
Делегат.
*Лучше переименовать по сути его деятельности в CountryDelegate
class CountryDelegate {
public:
CountryDelegate::CountryDelegate(QObject *parent)
:QStyledItemDelegate(parent) {
}
// Создание QComboBox
QWidget* DelegateComboBox::createEditor(
QWidget *parent,
сonst QStyleOptionViewItem &option,
const QModelIndex &index) const {
return new QComboBox(parent);
}
// Заполнение QComboBox данными из модели
void setEditorData(QWidget *editor, const QModelIndex &index) const {
QComboBox* combo = qobject_cast<QComboBox*>(editor);
if (combo) {
// Запросим список стран из модели UserTableModel по роли CountryRole
combo->addItems(index.data(CountryRole).toStringList());
// Запросим текущее значение (то, которое отображается сейчас)
QString current = index.data(Qt::DisplayRole).toString();
combo->setCurrentText( current );
}
}
// Остальные методы такие же как у вас
}
Таким образом, мы отделили модели данных от отображения данных