С Новым годом! Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.74/155: Рейтинг темы: голосов - 155, средняя оценка - 4.74
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
1

Своя модель для QTreeView

17.01.2015, 01:38. Показов 29108. Ответов 13
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Хочу отобразить дерево...
модель: своя модель унаследованная от QAbstractItemModel.
Представление: QTreeView, добавленное на форму.
Данные: Пусть будет две строки добавленные в QStringList, обе являются итемами верхнего уровня, ну не считая самого верхнего...
Будем только отображать, добавлять ничего не будем.

Для наследования от QAbstractItemModel, нужно переопределить функции data(),index(),parent(),columnCount(),rowCount().
Код:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#ifndef TREEMODEL_H
#define TREEMODEL_H
 
#include <QObject>
#include <QAbstractItemModel>
 
 
class TreeModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    explicit TreeModel(QObject *parent = 0);
 
    QVariant data(const QModelIndex &index, int role) const;
 
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
 
    QModelIndex index(int row, int column, const QModelIndex &parent) const;
 
    QModelIndex parent(const QModelIndex &child) const;
 
    int columnCount(const QModelIndex &parent) const;
 
    int rowCount(const QModelIndex &parent) const;
 
signals:
    
public slots:
    
};
 
#endif // TREEMODEL_H
 
#include "treemodel.h"
 
TreeModel::TreeModel(QObject *parent) :
    QAbstractItemModel(parent)
{
 
}
 
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    QString str1 = "1111";
    QString str2 = "2222";
    QStringList list;
    list << str1 << str2;
    if(!index.isValid())
    {return QVariant();}
    if (role != Qt::DisplayRole)
    {return QVariant();}
    if(role == Qt::DisplayRole)
    {
        return list[index.row()];
    }
 
    return QVariant();
}
 
QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
     {
         return (section+1);
     }
     return QVariant();
}
 
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
 
//    if(!parent.isValid())
//    {
//        return QModelIndex();
//    }
 
    QModelIndex index = createIndex(row,column,0);
     return index;
}
 
QModelIndex TreeModel::parent(const QModelIndex &child) const
{
    if (!child.isValid())
    {
        return QModelIndex();
    }
 
    return QModelIndex();
}
 
int TreeModel::columnCount(const QModelIndex &parent) const
{
    return 1;
}
 
int TreeModel::rowCount(const QModelIndex &parent) const
{
    return 2;
}
С data() и headerdata() вроде все более менее понятно,
index() - я так понимаю, функция должна возвращать индекс текущего элемента, в createindex вместо parent я указал 0, хотя ведь должен быть предок, rootitem, в общем не понимаю, что при условии таких данных как у меня подавать сюда и как в целом описывать фукнкию.
parent() - олжна возвращать индекс предка, но что у нас является предком? Предком должен быть один, невидимый rootitem, а его детьми как раз мои строки...
columncount(); - тут все понятно, у меня всего две переменные оиднакового уровня расположенные в 1-й колонке
rowcount(); тоже понятно, раз QStringList содержит две переменные одинакового уровня, то строки должно быть две, для текущего родителя (rootitem).

После компиляции получаем QTreeView с двумя нашими строками, однако почему-то они отображают в виде стрелок, что у них есть потомки, при нажатии программа вылетает, при двойном щелчке по итему программа вылетает, почему?
Как бы выглядел код, если бы первая строка str1 была child для rootitem, а str2 child для str1?

Да, я смотрел Example в документации, но так и не понял, зачем они какой-то класс создают, а просто подать данные в модель нельзя? Без создания лишних классов, и там уже рассортировать, кто будет в списке parent, кто в списке child-ов
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.01.2015, 01:38
Ответы с готовыми решениями:

Модель для QTreeView
Добрый день/ночь, возникла проблема при написании своей модели. На втором уровне вложенности у меня...

Модель для QTreeView от класса QAbstractItemModel
Привет, я уже измучился с непониманием как работает QAbstractItemModel. У меня есть список файлов...

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

Редактирование данных в QTreeView и отпрака их в модель
Доброго времени суток, уважаемые! Подскажите пожалуйста, можно ли редактировать данные в QTreeView...

13
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
17.01.2015, 09:13 2
Цитата Сообщение от Xantrax Посмотреть сообщение
После компиляции получаем QTreeView с двумя нашими строками, однако почему-то они отображают в виде стрелок, что у них есть потомки, при нажатии программа вылетает, при двойном щелчке по итему программа вылетает, почему?
Извини, но у тебя очень многое реализовано через ж. Есть хороший пример по поводу написания модели дерева. Есть само пояснение по структуре модель/вид. Прочти, если хочешь более внятно понять.
В этом пояснении, например сказано, что rowCount используется для подсчёта childrens в parent. Он применяется ко всем элементам. У тебя он всегда возвращает "2". Даже в том случае, когда вид запрашивает у модели есть ли у твоих строк их собственные дети. Твоя модель отвечает - да. Поэтому они у тебя и отображаются, как элементы, имеющие детей. Поэтому они и вылетают при нажатии - ведь вид пытается отобразить детей, которые не существуют.
Конкретно с данной проблемой лучше переписать:
C++ (Qt)
1
2
3
4
5
6
int TreeModel::rowCount(const QModelIndex &parent) const
{
    if (!parent.isValid())
        return 2;
    return 0;
}
А вообще лучше прочитать мануалы, которые я тебе выше дал и понять что там и как.
1
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
19.01.2015, 13:55  [ТС] 3
Хорошо, дерево где все элементы являются узлами верхнего уровня с этим все ясно.
Теперь давайте представим что у них появились подветки(child). Т.е. данными поступающими в модель в данном случае будут: QStringList parent_list <---тут две строки (parent_list.size() = 2), пусть они будут у нас элементами верхнего уровня и QStringList child_list <--- тут тоже две строки (child_list.size() = 2), пусть они будут подветками наших парентов.

Не по теме:

Или как-то по другому нужно организовать данные? Типа QMap<QString,QStringList>my_map?


Опять же в модели унаследованной от QAbstractItemModel нам нужно переопределить методы data(),index(), parent(), ColumnCount(), RowCount()...

Начнем с простого, колонка в любой ветке будет всего одна, соответственно:
C++ (Qt)
1
2
3
4
5
int TreeModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 1;
}
Далее RowCount()... Для элементов верхнего уровня parent-а не будет, соответственно:
C++ (Qt)
1
2
3
4
5
6
7
8
int TreeModel::rowCount(const QModelIndex &parent) const
{
    if(!parent.isValid())
    {
        return parent_list.size();
    }
    return child_list.size();
}
Далее метод parent(), смотрим что возвращает QModelIdex, соответственно должен возвращать index(колонку строку) где находится родитель:
C++ (Qt)
1
2
3
4
5
6
QModelIndex TreeModel::parent(const QModelIndex &child) const  //не понял зачем в функцию подается индекс child
{
    //[B]тут проблемы начинаются...[/B]
       QModelIndex parent = this->index(child.row(),1,0); //не правильно скорее всего
       return parent;
}
Далее метод idex(), должен вернуть текущий индекс в соответствии с пришедшей в эту функцию строкой, колонкой и parent:


Не успеваю дописать пост... позже продолжу... подсказывайте ежели что.. ))
0
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
19.01.2015, 14:12 4
Ты лучше приведи пример как должен в конечном итоге выглядеть твой список.

По поводу того, что данные можно размещать прямо в модели - да, можно. Модель и данные разделяются для того, чтобы в случае чего можно было проще изменять(или даже заменять) то или другое. Если тебе это не надо - можешь не разделять модель и данные.
0
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
19.01.2015, 15:46  [ТС] 5
Вот так должно в итоге выглядеть моё представление:
Своя модель для QTreeView


 Комментарий модератора 
Все файлы должны быть размещены на форуме!
0
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
19.01.2015, 18:13 6
Цитата Сообщение от Xantrax Посмотреть сообщение
Вот так должно в итоге выглядеть моё представление:
Извини за вопрос, но не могу не задать: а зачем такое извращение?
Без ответа на этот вопрос я тебе помочь не смогу - потому что определение parent происходит через внутреннюю структуру данных, а раз данные у тебя для всех одни и те же, следовательно и parent для них определить невозможно.
0
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
19.01.2015, 19:37  [ТС] 7
Не понял, а в чем тут извращение, простое дерево же...
Название: Viewjpg_2709303_15662642.jpg
Просмотров: 684

Размер: 24.6 Кб
Хорошо, давайте сделаем данные разные для разных парентов(1111 и 2222)...
Название: View2jpg_4568927_15662699.jpg
Просмотров: 684

Размер: 24.0 Кб

 Комментарий модератора 
Все файлы должны быть размещены на форуме!
0
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
19.01.2015, 20:17 8
Цитата Сообщение от Xantrax Посмотреть сообщение
Не понял, а в чем тут извращение, простое дерево же...
Извращение - потому что непонятно зачем оно такое нужно и потому что это крайне трудно реализовать.
Цитата Сообщение от Xantrax Посмотреть сообщение
Хорошо, давайте сделаем данные разные для разных парентов(1111 и 2222)...
В данном случае используй стандартную модель QStandardItemModel. Точнее - наследуйся от неё и изменяй что тебе нужно. Или, если нужна какая-то своя модель - наследуйся от QAbstractItemModel и используй QStandardItem или наследников от неё. Или, если даже QStandardItem не удовлетворяет - пиши собственный класс данных.
В любом случае - просто обойтись двумя таблицами тут не получится, здесь нужны данные, специально спроектированные под дерево.
0
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
19.01.2015, 22:41  [ТС] 9
Т.е. унаследоваться от QAbstractTableModel и создать свою модель только для отображения в представлении QTableView просто.
А создать древовидную модель отнаследовавшись от QAbstractItemModel и отобразить результаты в представлении QTreeView сложно?
Хм, а как же тогда отображают древовидные данные обычно? Неужели просто используя QStandardItemModel?
А зачем наследоваться от QStandardItemModel, какую дополнительную функциональность можно добавить при наследовании?
0
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
19.01.2015, 23:26 10
Цитата Сообщение от Xantrax Посмотреть сообщение
Т.е. унаследоваться от QAbstractTableModel и создать свою модель только для отображения в представлении QTableView просто.
А создать древовидную модель отнаследовавшись от QAbstractItemModel и отобразить результаты в представлении QTreeView сложно?
Хм, а как же тогда отображают древовидные данные обычно? Неужели просто используя QStandardItemModel?
А зачем наследоваться от QStandardItemModel, какую дополнительную функциональность можно добавить при наследовании?
QAbstractTableModel - это базовая модель для таблиц, в которой уже реализован функционал для таблиц. Вы же хотите функционал древовидной модели.
QAbstractItemModel это вообще базовая для всех моделей структура. Её ещё можно назвать интерфейсом. Поэтому в ней мало чего реализовано и вам придётся все её виртуальные функции реализовывать вручную.

Для древовидных данных используют в качестве базового класса или QStandardItemModel или, если функционал её элементов(QStandardItem) вас не удовлетворяет, - QAbstractItemModel.
В QStandardItemModel базовый функционал, в том числе и для деревьев - уже реализован. Но вы можете его изменить, если вас что-то не устраивает, переопределив виртуальные функции.
1
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
19.01.2015, 23:49  [ТС] 11
Странно, QAbstractListModel есть, QAbstractTableModel есть, а QAbstractTreeModel нет, точнее есть, но он называется QStandardItemModel...
Да нет, функционал QStandardItemModel меня полностью устраивает, просто как-то обидно, в QAbstractTableModel я переопределял все необходимые виртуальные функции, а тут на тебе, из коробки работает...

Вопрос:
C++ (Qt)
1
2
3
4
5
6
7
8
QStandardItem *apple = new QStandardItem("Яблоки");
treemdl->appendRow(apple);                         //<---QStandardItemModel *treemdl = new QStandardItemModel(this);
connect(connect(treeView, SIGNAL(clicked(QModelIndex)),this, SLOT(clicked(QModelIndex)));
 void MyWidget::clicked(const QModelIndex &index)
 {
     QStandardItem *item = myStandardItemModel->itemFromIndex(index);
     QString a = item->text();
 }
Мало ли что с текстом случится, как бы вернуть объект по индексу полученному в результате щелчка мыши?
А для обработки clicked() только правой кнопкой мыши на item нужно переопределять представление (Treeview)?
0
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
20.01.2015, 00:16 12
Цитата Сообщение от Xantrax Посмотреть сообщение
Странно, QAbstractListModel есть, QAbstractTableModel есть, а QAbstractTreeModel нет,
Ничего странного нет. Просто смысла в нём никакого. Все абстрактные модели рассчитаны на работу с пользовательскими данными. И смысла в QAbstractTreeModel нет никакого, потому что в ней переопределять придётся ровно тоже функции, что и в QAbstractItemModel.
Работа с деревьями - она такая, наиболее сложная и комплексная.
Цитата Сообщение от Xantrax Посмотреть сообщение
Мало ли что с текстом случится, как бы вернуть объект по индексу полученному в результате щелчка мыши?
А для обработки clicked() только правой кнопкой мыши на item нужно переопределять представление (Treeview)?
По хорошему надо новую тему открывать. Тут правило такое: один вопрос - одна тема.

А зачем тебе по правому щелчку мыши? Он обычно для вызова меню используется.
А так - можешь отслеживать нажатия ​mouseReleaseEvent(QMouseEvent * event) и затем определять элемент по indexAt(const QPoint & point). Тогда никакого переопределения QTreeView не потребуется.
0
20 / 20 / 2
Регистрация: 28.11.2012
Сообщений: 366
23.01.2015, 12:16  [ТС] 13
А зачем тебе по правому щелчку мыши? Он обычно для вызова меню используется.
Да, мне как раз по правому щелчку мыши и нужно выводить контекстное меню...
А так - можешь отслеживать нажатия ​mouseReleaseEvent(QMouseEvent * event) и затем определять элемент по indexAt(const QPoint & point). Тогда никакого переопределения QTreeView не потребуется.
А пример можно какой-нибудь, я что-то не пойму, как не переопределяя представления (QTreeView), можно отследить нажатие правой кнопкой мыши по итему?
0
205 / 165 / 41
Регистрация: 25.10.2013
Сообщений: 527
23.01.2015, 13:53 14
Цитата Сообщение от Xantrax Посмотреть сообщение
Да, мне как раз по правому щелчку мыши и нужно выводить контекстное меню...
А пример можно какой-нибудь, я что-то не пойму, как не переопределяя представления (QTreeView), можно отследить нажатие правой кнопкой мыши по итему?
Тогда тебе надо другое - сигнал void ​customContextMenuRequested(const QPoint & pos).
Создаешь слот, обрабатывающий его, подсоединяешь. Ну а дальше в слоте для определения элемента используй что тебе больше подходит - indexAt() или currentItem().
Пример:
C++ (Qt)
1
2
 view->setContextMenuPolicy(Qt::CustomContextMenu);
 connect(view,SIGNAL(customContextMenuRequested(const QPoint &)),this,SLOT(слот_обработчик(const QPoint &)));
0
23.01.2015, 13:53
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.01.2015, 13:53
Помогаю со студенческими работами здесь

Вставка значений из одного QtreeView в другое QTreeView
Здравствуйте, форумчане. Реализовал TreeModel по документации...

Создание простой модели для QTreeView
Помогите разобраться в создании простой модели для QTreeView. Для небольшого примера, данные должны...

QTreeView и отображение одних и тех же элементов для разных категорий
Есть QTreeView, есть своя моделька, есть задание добавить в неё агрегирующую категорию. По типу &gt;...

QSS: alternate-background-color у QTreeView с особым фоном для определенных элементов
Для иерархического списка QTreeView нужно сделать чередующиеся цвета для элементов. Но нужно еще...

Одна модель данных (QStandardItemModel) для QTreeView и нестольких QComboBox
Доброго времени суток, уважаемые! Подскажите пожалуйста, можно ли реализовать одну модель данных...

Стиль для QtreeView::branch
Подскажите пожалустак, как изменить ширину Branch у TreeView высота меняется при изменении...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru