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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил  (Прочитано 5667 раз)
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());
}

Что доработать, чтобы хоть что-то минимальное начало показывать? Спасибо большое!
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Январь 31, 2017, 20:08 »

Тут не через прокси надо действовать, мне кажется, а создавать свою полноценную модель.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #2 : Февраль 01, 2017, 01:17 »

Да, это делается наследованием от QStandardItemModel или даже AbstractItemModel, кроме того для каждого итема будет маленькая обертка ItemProxy, которая будет связью между данными в ветке дерева и самой моделью, которая является интерфейсом QT. Соответственно будут методы для перехода от индекса к элементу прокси и наоборот, они будут нужны например при реализации метода data  - да и всех остальных.


Во вложении кидаю свою модель, но она работает с моими компонентами БД, я выкинул модуль QtSql у себя, т.к. он не имеет нормальной поддержки транзакций. Если приложите усилия, то сможете адаптировать под любые свои цели или взять как пример. Смысл думаю там понятен будет. По возможности на вопросы готов отвечать.
« Последнее редактирование: Февраль 01, 2017, 01:51 от break » Записан
Yurko_San
Гость
« Ответ #3 : Февраль 01, 2017, 08:40 »

Спасибо большое! Доброе утро! Я заменил CIBPPSqlQuery на QSqlQuery, заменил тексты запросов и удалил CIBPPTransaction, но пока ничего не показывает. Вот клиентский код:

Код:
    CSqlTreeModel *sqlTreeModel = new CSqlTreeModel(this);
    sqlTreeModel->setTableName("");
    sqlTreeModel->prepare();
    ui->tvBranchesTree->setModel(sqlTreeModel);

Что ещё нужно дописать, чтобы стало что-то показывать?
Записан
panAlexey
Гипер активный житель
*****
Offline Offline

Сообщений: 864

Акцио ЗАРПЛАТА!!!!! :(


Просмотр профиля
« Ответ #4 : Февраль 01, 2017, 09:45 »

Любопытно, надо глянуть.
Записан

Win Xp SP-2, Qt4.3.4/MinGW. http://trdm.1gb.ru/
Yurko_San
Гость
« Ответ #5 : Февраль 01, 2017, 12:54 »

Доработал с использованием QSqlQuery. Сейчас всё из стандартных компонентов. Работает. Спасибо большое!
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #6 : Февраль 01, 2017, 16:17 »

Отлично, рад, что помогло.
Записан
panAlexey
Гипер активный житель
*****
Offline Offline

Сообщений: 864

Акцио ЗАРПЛАТА!!!!! :(


Просмотр профиля
« Ответ #7 : Февраль 01, 2017, 16:33 »

А вот и моя мазня на тему иерархических моделей.Что могет:
Показывать как только папки, так и папки с элементами, генерировать вьювы и формы.
Не особо доделано, но то что надо делает.
Типа:

Это что-то типа программного миниаксеса-построителя:
Код:
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();
}

}
« Последнее редактирование: Февраль 01, 2017, 16:41 от panAlexey » Записан

Win Xp SP-2, Qt4.3.4/MinGW. http://trdm.1gb.ru/
Yurko_San
Гость
« Ответ #8 : Февраль 02, 2017, 17:54 »

Добрый вечер! А ещё можно вопросик такого плана. Сейчас узел root не показывается, его нет в дереве, как сделать, чтобы он тоже показывался в дереве? И как сделать, чтобы можно было отображать те узлы, у которых нет родителей? Спасибо!
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #9 : Февраль 02, 2017, 18:26 »

У QTreeView есть опция, ставится прямо в дизайнере rootIsDecorated. Но иногда она не решает всех проблем, например, если надо, чтобы были соседние ветки корневыми, тогда в БД или другой древовидной модели заводится еще один рут, а опция ставится в true.

По узлам у которых нет родителей - возможно прийдется править модель, быстро с ходу не скажу, это просто абстракция, мне кажется во всех таких случая проще, чтобы у них был один общий родитель - самый верхний рут, который показывать или нет уже определяем через эту опцию. Иначе надо будет реализовывать оосбенное поведение для ветвей без родителей, что может и не очень сложно, но будет не сразу понятно в коде.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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