Название: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: Yurko_San от Январь 31, 2017, 16:45
Добрый день! Помогите пожалуйста, нет сил уже. Есть SqlQueryModel с запросом типа "SELECT id, id_parent ...", мне нужно посредством наследования от QAbstractProxyModel получить деревянную модель с узлами возможностью их раскрытия (как стандартное меню директорий и каталогов). Написал класс от QAbstractProxyModel, но пока успеха не добился. Код следующий: QString request = "SELECT " "b.id, " "b.id_parent " "FROM " "branch b " "WHERE " "b.isdeleted = 0";
m_branchModel->setQueryString(request); // это SqlQueryModel
BranchesProxyModel *branchModel = new BranchesProxyModel(m_branchModel); // это моя модель от QAbstractProxyModel branchModel->setSourceModel(m_branchModel); ui->tvBranches->setModel(branchModel); // Это QTreeView ui->tvBranchesOrig->setModel(m_branchModel); // Это QTreeView
BranchesProxyModel: #ifndef BRANCHESPROXYMODEL_H #define BRANCHESPROXYMODEL_H
#include <QAbstractProxyModel>
class BranchesProxyModel : public QAbstractProxyModel { Q_OBJECT
public: explicit BranchesProxyModel(QObject *parent = 0);
void setSourceModel(QAbstractItemModel* newSourceModel); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; };
#endif // BRANCHESPROXYMODEL_H
#include "branchesproxymodel.h"
#include <QStandardItem> #include <QMessageBox>
BranchesProxyModel::BranchesProxyModel(QObject *parent) : QAbstractProxyModel(parent) { }
void BranchesProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { QAbstractProxyModel::setSourceModel(sourceModel); connect(sourceModel, &QAbstractItemModel::dataChanged, this, &BranchesProxyModel::dataChanged); }
QModelIndex BranchesProxyModel::index(int row, int column, const QModelIndex &parent) const { if (!sourceModel()) return QModelIndex();
if (column == 1) column = 2;
QModelIndex index = sourceModel()->index(row, column); return createIndex(row, column, index.internalPointer()); }
QModelIndex BranchesProxyModel::parent(const QModelIndex &child) const { if (!child.isValid()) return QModelIndex();
if (!sourceModel()) return QModelIndex();
return mapFromSource(sourceModel()->parent(child)); }
int BranchesProxyModel::rowCount(const QModelIndex &parent) const { int result = 0; if (!sourceModel()) return result;
int rowCount = sourceModel()->rowCount(); for (int i = 0; i < rowCount; i++) { qlonglong paretnId = sourceModel()->index(i, 1).data().toLongLong(); if (paretnId < 1) ++result; }
return result; }
int BranchesProxyModel::columnCount(const QModelIndex &parent) const { return 2; }
bool BranchesProxyModel::hasChildren(const QModelIndex &parent) const { if (!sourceModel()) return false;
qlonglong id = index(parent.row(), 0).data().toLongLong(); int rowCount = sourceModel()->rowCount(); for (int i = 0; i < rowCount; i++) { qlonglong paretnId = sourceModel()->index(i, 1).data().toLongLong(); if (paretnId == id) return true; } return false; }
QModelIndex BranchesProxyModel::mapToSource(const QModelIndex &proxyIndex) const { if(!proxyIndex.isValid()) return QModelIndex();
if (!sourceModel()) return QModelIndex();
return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), mapToSource(proxyIndex.parent())); }
QModelIndex BranchesProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { if (!sourceIndex.isValid()) return QModelIndex(); return createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer()); }
Что доработать, чтобы хоть что-то минимальное начало показывать? Спасибо большое!
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: Пантер от Январь 31, 2017, 20:08
Тут не через прокси надо действовать, мне кажется, а создавать свою полноценную модель.
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: break от Февраль 01, 2017, 01:17
Да, это делается наследованием от QStandardItemModel или даже AbstractItemModel, кроме того для каждого итема будет маленькая обертка ItemProxy, которая будет связью между данными в ветке дерева и самой моделью, которая является интерфейсом QT. Соответственно будут методы для перехода от индекса к элементу прокси и наоборот, они будут нужны например при реализации метода data - да и всех остальных.
Во вложении кидаю свою модель, но она работает с моими компонентами БД, я выкинул модуль QtSql у себя, т.к. он не имеет нормальной поддержки транзакций. Если приложите усилия, то сможете адаптировать под любые свои цели или взять как пример. Смысл думаю там понятен будет. По возможности на вопросы готов отвечать.
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: Yurko_San от Февраль 01, 2017, 08:40
Спасибо большое! Доброе утро! Я заменил CIBPPSqlQuery на QSqlQuery, заменил тексты запросов и удалил CIBPPTransaction, но пока ничего не показывает. Вот клиентский код: CSqlTreeModel *sqlTreeModel = new CSqlTreeModel(this); sqlTreeModel->setTableName(""); sqlTreeModel->prepare(); ui->tvBranchesTree->setModel(sqlTreeModel);
Что ещё нужно дописать, чтобы стало что-то показывать?
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: panAlexey от Февраль 01, 2017, 09:45
Любопытно, надо глянуть.
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: Yurko_San от Февраль 01, 2017, 12:54
Доработал с использованием QSqlQuery. Сейчас всё из стандартных компонентов. Работает. Спасибо большое!
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: break от Февраль 01, 2017, 16:17
Отлично, рад, что помогло.
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: panAlexey от Февраль 01, 2017, 16:33
А вот и моя мазня на тему иерархических моделей.Что могет: Показывать как только папки, так и папки с элементами, генерировать вьювы и формы. Не особо доделано, но то что надо делает. Типа: (http://i023.radikal.ru/1702/30/2bdd638ccce4.png) Это что-то типа программного миниаксеса-построителя: void uoMainWindow::createTables() { QString dbName = qApp->applicationDirPath() + QDir::separator()+"main.db"; #ifdef Q_OS_LINUX QDir home = QDir::home(); if (!home.exists(".uoReceptor")) { home.mkpath(".uoReceptor"); } dbName = home.absolutePath() + "/.uoReceptor/" + QDir::separator()+"main.db"; #endif
m_dbMan->setupDataBase(dbName); m_receptTable = m_dbMan->addRefTable("ШаблоныPецептов","Шаблоны рецептов",6,120); m_receptTable->setOption(codeType_Number, true); m_receptTable->addField("Комментарий", fieldType_String,150); m_templField = m_receptTable->addField("Шаблон", fieldType_TextHTML); uoMdiObserver::instance()->m_receptTableId = m_receptTable->m_baseNom;
uoDbRefTable* tmlpTabl = m_dbMan->addRefTable("Лекарства","Лекарства",6, 70); tmlpTabl->addField("ЛатИмя",fieldType_String,70)->m_descr = "Латинское наименование"; tmlpTabl->addField("Описание",fieldType_Text); tmlpTabl->setOption(codeType_Number, true);
tmlpTabl = m_dbMan->addRefTable("Симптомы","Симптомы",6, 100); tmlpTabl->setOption(codeType_Number, true); tmlpTabl->addField("Описание",fieldType_Text);
tmlpTabl = m_dbMan->addRefTable("Заболевания","Заболевания",6, 100); tmlpTabl->setOption(codeType_Number, true); tmlpTabl->addField("Описание",fieldType_Text);
m_dbMan->restructuring();// Реструктуризация m_dbMan->createGuiFactory(this); m_receptTemplDocWidget = new QDockWidget(tr("Recept template"), this); m_receptTemplDocWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
uoUrl url = m_receptTable->getUoUrlByForm(uoFormT_Tree); url.setWithElem(true); m_docTreeFormRecept = m_dbMan->getForm(url); if (m_docTreeFormRecept) { m_docTreeFormRecept->setParent(m_receptTemplDocWidget); m_receptTemplDocWidget->setWidget(m_docTreeFormRecept); addDockWidget(Qt::LeftDockWidgetArea, m_receptTemplDocWidget); m_actionShowDocRecept = m_receptTemplDocWidget->toggleViewAction(); }
}
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: Yurko_San от Февраль 02, 2017, 17:54
Добрый вечер! А ещё можно вопросик такого плана. Сейчас узел root не показывается, его нет в дереве, как сделать, чтобы он тоже показывался в дереве? И как сделать, чтобы можно было отображать те узлы, у которых нет родителей? Спасибо!
Название: Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
Отправлено: break от Февраль 02, 2017, 18:26
У QTreeView есть опция, ставится прямо в дизайнере rootIsDecorated. Но иногда она не решает всех проблем, например, если надо, чтобы были соседние ветки корневыми, тогда в БД или другой древовидной модели заводится еще один рут, а опция ставится в true.
По узлам у которых нет родителей - возможно прийдется править модель, быстро с ходу не скажу, это просто абстракция, мне кажется во всех таких случая проще, чтобы у них был один общий родитель - самый верхний рут, который показывать или нет уже определяем через эту опцию. Иначе надо будет реализовывать оосбенное поведение для ветвей без родителей, что может и не очень сложно, но будет не сразу понятно в коде.
|