8

I'm attempting to create a QTreeView and use a custom model for it. I have placed qDebug() statements at various places, and I have determined that data() is never being called. How can I fix this problem?

The model's code is below

#include "ModelItemNeural.h"

ModelItemNeural::ModelItemNeural(QObject *parent, NeuralNode *rootNode)
    : QAbstractItemModel(parent)
{
    this->rootNode = 0;
}

QModelIndex ModelItemNeural::index(int row, int column, const QModelIndex &parent) const
{
    // Out of bounds and null rootNode check.
    if (rootNode == 0 || row < 0 || column < 0)
    {
        return QModelIndex();
    }

    NeuralNode* parentNode = nodeFromIndex(parent);
    NeuralNode* childNode = parentNode->getInputs().value(row);

    if (childNode == 0)
    {
        return QModelIndex();
    }

    return createIndex(row, column, childNode);
}

QModelIndex ModelItemNeural::parent(const QModelIndex &child) const
{
    NeuralNode* node = nodeFromIndex(child);
    if (node == 0)
    {
        return QModelIndex();
    }

    NeuralNode* parentNode = node->getParent();
    if (parentNode == 0)
    {
        return QModelIndex();
    }

    NeuralNode* grandParentNode = parentNode->getParent();
    if (grandParentNode == 0)
    {
        return QModelIndex();
    }

    int row = grandParentNode->getInputs().indexOf(parentNode);
    return createIndex(row, 0, parentNode);
}

int ModelItemNeural::rowCount(const QModelIndex& parent) const
{
    if (parent.isValid() == false)
    {
        return 0;
    }

    if (parent.column() > 0)
    {
        return 0;
    }

    NeuralNode* parentNode = nodeFromIndex(parent);
    if (parentNode == 0)
    {
        return 0;
    }

    return parentNode->getInputs().length();
}

int ModelItemNeural::columnCount(const QModelIndex &parent) const
{
    return 2;
}

QVariant ModelItemNeural::data(const QModelIndex &index, int role) const
{
    qDebug() << "Data";
    if (index.isValid() == false)
    {
        return QVariant();
    }

    if (role != Qt::DisplayRole)
    {
        return QVariant();
    }

    NeuralNode* node = nodeFromIndex(index);
    if (node == 0)
    {
        return QVariant();
    }

    switch (index.column())
    {
        case 0:
        {
            // Stripping the name of the NeuralNode type.
            QString name = typeid(node).name();
            int index = name.indexOf(" ");
            if (index >= 0)
            {
                name = name.remove(0, index + 1);
            }

            qDebug() << "Name Column";
            return "Test";
            return name;
        }

        case 1:
        {
            qDebug() << "Value Column";
            return node->getWeight();
        }
    }

    return QVariant();
}

QVariant ModelItemNeural::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
        switch (section)
        {
            case 0:
            {
                return "Node";
            }
            case 1:
            {
                return "Weight";
            }
        }
    }

    return QVariant();
}

NeuralNode * ModelItemNeural::nodeFromIndex(const QModelIndex &index) const
{
    if (index.isValid() == true)
    {
        //return (NeuralNode*)(index.internalPointer());
        return static_cast<NeuralNode *>(index.internalPointer());
    }
    else
    {
        return rootNode;
    }
}

void ModelItemNeural::setRootNode(NeuralNode *rootNode)
{
    delete this->rootNode;
    this->rootNode = rootNode;
    reset();
}

The code from the MainWindow where the view is located is below.

#include "MainWindow.h"
#include "ui_MainWindow.h"

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

    NeuralNetwork* network = new NeuralNetwork();
    modelNeural = new ModelItemNeural();
    modelNeural->setRootNode(network);
    ui->treeView->setModel(modelNeural);

    update();
}

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

void MainWindow::on_actionNew_triggered()
{
    NeuralNetwork* network = new NeuralNetwork();

    modelNeural->setRootNode(network);
    ui->treeView->update();
}

I should mention that the header does display for this model. However, even when I set an item, nothing is displayed in the widget save the header.

Oh and NeuralNetwork is a sub of NeuralNode.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
jecjackal
  • 1,407
  • 2
  • 20
  • 35
  • Is your data() method virtual? – Sebastian Negraszus Jul 23 '11 at 18:02
  • @Sebastian N, it is overridden from QAbstractItemModel. – Lol4t0 Jul 23 '11 at 18:37
  • no the data() method is overridden from QAbstractItemModel. The signature is correct (QTCreator show's it italicized meaning it is an overriden function). – jecjackal Jul 23 '11 at 20:24
  • Well, assuming there is no magic, I think, you failed in some functions. Check, that you ever return valid index, row count >0. Also, what does it mean: `if (parent.column() > 0) { return 0; }`? Also, you needn't write `boolVar == true`. It's enough `boolVar` – Lol4t0 Jul 23 '11 at 20:35
  • Consider using ModelTest - most likely it will reveal lots of hidden bugs. http://developer.qt.nokia.com/wiki/Model_Test – ak. Oct 07 '11 at 12:27

3 Answers3

5

The problem is this fragment:

int ModelItemNeural::rowCount(const QModelIndex& parent) const
{
    if (parent.isValid() == false)
    {
        return 0;
    }

You're basically saying that the root node (indicated by invalid parent index) has zero children i.e. the model has zero top-level rows. So the view queries no further.

Just drop this check and it should work. nodeFromIndex seems to handle root node correctly.

Nikita Nemkin
  • 2,780
  • 22
  • 23
  • I made this change and data() is still not being called. However, now rowCount() is returning 0 (which is correct). The only other functions being called are headerData() and index(). Index() is now always returning a blank QModelIndex() because the root has no children. Can you have a 1 item tree? I will be adding more as the program runs. – jecjackal Jul 23 '11 at 23:53
  • @jecjackal if your tree is actually empty, why do you expect data() to be called? Add some (top level) rows first. One or one thousand, it doesn't matter. – Nikita Nemkin Jul 24 '11 at 00:23
  • I have an item there (the root item). Do I need to call "insertRows()" manually? I'll give that a shot. – jecjackal Jul 24 '11 at 18:13
  • I just found an example that came with the QT SDK 2.2.1. Its called "editableTreeModel". Its not located at the home page where a lot of the examples are stored. This model does exactly what I'm trying to do. Thanks for the help all – jecjackal Jul 24 '11 at 18:27
1

You have to override the following method in your QAbstractItemModel inherited class:

QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;

Then write this within:

return createIndex(row, column, nullptr);

Something like this:

QModelIndex index(int row, int column, const QModelIndex &parent) const { return createIndex(row, column, nullptr); }

Patapoom
  • 794
  • 1
  • 7
  • 16
0

Did you add the model (not the item) to the treeview control? Did you create items of your derived type and add them to the model? data() should be called if your model is being accessed.

Jay
  • 13,803
  • 4
  • 42
  • 69
  • yes I have both set the model to the treeview and created an item for that model. since the model sent to the treeview is a pointer, it shouldn't matter the order I do this (add to treeview vs add the item to the model). – jecjackal Jul 23 '11 at 22:01
  • If you haven't connected the model to the tree view before you add the item to the model then any signals telling the view to update would not be seen. Perhaps it's a refresh issue? I also notice you're creating your own indexes. Perhaps the index is not valid so it never tries to fetch data using that index? If you don't need special indices I would use the method from a base class. Less to go wrong ;) – Jay Jul 23 '11 at 22:15
  • I thought index() was pure virtual – jecjackal Jul 24 '11 at 00:03
  • Ah sorry. I've used a non abstract class and inherited from it. They provide most of the methods and I didn't need to change them. – Jay Jul 24 '11 at 00:31