Почему эта модель на основе QAbstractItemModel не работает?

Я создаю простое приложение QMainWindow следующим образом:

Заголовочный файл:

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QAbstractItemModel>
#include <QTreeView>
#include <QVBoxLayout>


#include <QMainWindow>

namespace Ui {
class MainWindow;
}



class MyTreeModel : public QAbstractItemModel
{
public:
    Q_OBJECT

public:
    MyTreeModel(QObject *parent=NULL);

    QModelIndex parent(const QModelIndex &index) const;
    QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const;
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role) const;


    QVariant headerData(int section, Qt::Orientation orientation,int role = Qt::DisplayRole) const;

};


class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    


    QTreeView * view;
    MyTreeModel *model;


private:
    Ui::MainWindow *ui;
    QVBoxLayout * layout;
};

#endif // MAINWINDOW_H

Исходный файл:

//mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>




QModelIndex MyTreeModel::parent(const QModelIndex &index) const
{
    return QModelIndex();
}

QVariant MyTreeModel::data(const QModelIndex &index, int role) const
{
    return "111";
}

QVariant MyTreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
        if (section==0)
            return "Column0";
        else if (section==1)
            return "Column1";
        else if (section==2)
            return "Column2";
        else
            return QVariant();
    }
    else
        return QVariant();
}

QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent)
            const
{

    return createIndex(row, column, NULL);

}

int MyTreeModel::columnCount(const QModelIndex &parent) const
{
    return 3;
}

int MyTreeModel::rowCount(const QModelIndex &parent) const
{
    return 2;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    model=new MyTreeModel();
    view= new QTreeView(this);
    view->setModel(model);

    layout= new QVBoxLayout(this);
    layout->addWidget(view);
    QWidget *window = new QWidget();
    window->setLayout(layout);
    setCentralWidget(window);
}

MainWindow::~MainWindow()
{
    delete ui;
}

Я ожидаю, что он покажет 2 строки * 3 столбца «111», но это не так. Он показывает только заголовок. Если я изменю QVariant MyTreeModel::headerData на:

QVariant MyTreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{

        if (section==0)
            return "Column0";
        else if (section==1)
            return "Column1";
        else if (section==2)
            return "Column2";
        else
            return QVariant();

}

Это ничего не покажет. Заголовок также исчезает.

Почему?

Предоставляет ли QAbstractItemModelTester какую-либо полезную диагностику?

G.M. 06.07.2024 15:10

@Г.М. Я использую Qt 4, в котором нет этого класса.

William 06.07.2024 15:15

@William Qt4 устарел как минимум 10 лет. Даже если реализация программирования модели/представления Qt за это время не сильно изменилась, тот факт, что вы используете такую ​​старую библиотеку, должен быть выделен в вашем сообщении (и в его тегах), иначе мы бы (правильно) Предположим, что вы используете поддерживаемые в настоящее время версии, которые могут вести себя по-другому.

musicamante 07.07.2024 02:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем коде есть несколько проблем. Во-первых, поскольку это одноуровневая модель, члены index, rowCount и columnCount должны возвращать «реальные» значения только тогда, когда указанный родительский индекс недействителен (т. е. номинальный корневой индекс). Итак, эти участники становятся...

QModelIndex MyTreeModel::index (int row, int column, const QModelIndex &parent) const
{
  if (parent.isValid())
    return {};
  return createIndex(row, column, nullptr);
}

int MyTreeModel::columnCount (const QModelIndex &parent) const
{
  if (parent.isValid())
    return 0;
  return 3;
}

int MyTreeModel::rowCount (const QModelIndex &parent) const
{
  if (parent.isValid())
    return 0;
  return 2;
}

Во-вторых, ваш MyTreeModel::data участник всегда возвращается (эффективно) QString("111"). Это не удастся для тех ролей, где QString невозможно преобразовать в ожидаемый тип: например. QSize для Qt::SizeHintRole. Итак, участник data становится...

QVariant MyTreeModel::data(const QModelIndex &index, int role) const
{
  if (role != Qt::DisplayRole)
    return {};
  return "111";
}

С учетом вышеуказанных изменений код работает должным образом.

Следует также отметить, что, хотя это может иметь смысл для простоты тестового примера (который по сути создает двухмерную модель таблицы), использование null в качестве указателя для createIndex() в принципе неверно при создании модели, которая могла бы быть древовидной.

musicamante 07.07.2024 02:48

@Г.М. Ваш измененный код работает! Спасибо. Фактически, когда я просто изменяю функцию данных как вашу, она может отображать 2 строки * 3 столбца «111». Но программа вылетает, когда я нажимаю стрелку в древовидном представлении, чтобы развернуть строку. Не знаю почему? Мне интересно узнать о роли и времени индекса, данных, rowCount, columnsCount, родителя в модели. Как они работают вместе, чтобы отображать фактические данные в представлении?

William 07.07.2024 10:51

@musicamante Если в createIndex() не используется нулевой указатель, что мне следует использовать для древовидной модели?

William 07.07.2024 10:52

@ Уильям, обычно тебя не должно слишком волновать «время» index(), data(), rowCount() и columnCount(): они могут вызываться в самые разные моменты в зависимости от различных потребностей. Причина, по которой вы должны все реализовать, Г.М. говорит не из-за порядка, в котором могут вызываться функции, а из-за того, что их реализация должна быть выполнена соответствующим образом: аргумент parentrowCount() и columnCount() используется для возврата количества возможных дочерних элементов для данного родительского элемента, и поскольку вы мы всегда произвольно возвращаем значение >= 0, это означает, что »

musicamante 07.07.2024 22:03

@William » у каждого элемента есть другие дочерние элементы (в вашем примере 6, 3 строки и 2 столбца). Это неправильно, поскольку вызывает бесконечную рекурсию, поскольку у каждого из этих дочерних элементов, в свою очередь, будут другие дочерние элементы. Я настоятельно рекомендую вам терпеливо изучить Руководство по программированию модели/представления и выполнить несколько правильных обучающих тестов, начиная с одномерных моделей («списков»), затем двумерных («таблиц») и, наконец, древовидных моделей, все с связанные представления: QListView, QTableView, QTreeView соответственно. Третий аргумент »

musicamante 07.07.2024 22:07

@William » createIndex() обычно не требуется для простых моделей (1D и 2D), поскольку их логические координаты в моделях очевидны, но древовидные модели требуют ссылки на данную строку и столбец, иначе модель не сможет узнать, элемент в строке X и столбце Y относится к верхнему уровню или дочернему, главному дочернему элементу и т. д. В документе выше (и в документации QAbstractItemModel) есть некоторые пояснения по этому поводу, но вам действительно следует начать с правильного понимания более простые модели перед переходом к древовидным; это шаги, которые вы не можете пропустить.

musicamante 07.07.2024 22:10

Другие вопросы по теме