Solved Help creating a tree that traverses the map of a graph
-
I'd like the ability to traverse through a map of a graph. I chose a tree in order to visualize it and focus on the regions that I'm interested in (closing the others to keep them small yet still visible).
I'm rather new to C++ and QT, so this is one of the exercises I've imposed upon myself. I followed the editable tree tutorial, but unfortunately, I've run into some blues. The errors I get are:
invalid use of incomplete type ‘class QAbstractItemModel’
and
expected ‘)’ before ‘’ token*
I did some digging and it looks like there's some sort of circular dependency. I've played with a ton of permutations of #include based on the tutorial, but I can't see to get QAbstractItemModel to behave properly (the 2 highlights are just the problems that stand out from the myriad of others). I'm not sure if it may also be a qmake problem, but I've played around with that a lot as well.
Here is the beginning of each file for reference. In addition, I have zipped up the entire project. It's a little bit messy in MainWindow since I wanted to manipulate the map with keys and save it to a file, so it has a couple extra tests.
(If anyone wonders why I called it "Monstrocity", it's because I plan on sticking a lot of tests into a single project, and it feels weird calling it a "rough draft")
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = Monstrocity TEMPLATE = app CONFIG += c++14 DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ mainwindow.cpp \ treemap.cpp \ treemapmodel.cpp \ main.cpp HEADERS += \ mainwindow.h \ treemap.h \ treemapmodel.h FORMS += \ mainwindow.ui
main.cpp:
#include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[])
MainWindow.h
#include <QMainWindow> //#include <QModelIndex> #include <QFile> #include <QDebug> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow
MainWindow.cpp
#include "mainwindow.h" #include "treemapmodel.h" #include "ui_mainwindow.h" #include <QKeyEvent> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
TreeMap.h
#include <QString> #include <QVector> class TreeMap
TreeMap.cpp
#include "treemap.h" TreeMap::TreeMap(QString name, TreeMap *parentNode = 0)
TreeMapModel.h
#include <QAbstractItemModel> #include <QModelIndex> #include <QVariant> class TreeMap; class TreeMapModel : public QAbstractItemModel
TreeMapModel.cpp
#include "treemap.h" #include "treemapmodel.h" TreeMapModel::TreeMapModel() ```[0_1512071154512_Monstrocity.tar.gz](Uploading 100%)
-
Hi and welcome to devnet,
Your archive is not accessible.
The first error usually comes from a missing include.
-
It's saying I don't have enough privileges to upload it. Perhaps a security measure? I suppose I'll post the full code. I know that the code will most likely have other errors though. Here goes:
(.pro file is already up)
main.cpp#include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> //#include <QModelIndex> #include <QFile> #include <QDebug> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); protected: void keyPressEvent(QKeyEvent *); void keyReleaseEvent(QKeyEvent *); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h" #include "treemapmodel.h" #include "ui_mainwindow.h" #include <QKeyEvent> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QFont font; font.setFamily("Source Code Pro"); font.setFixedPitch(true); //font.setPointSize(10); font.setPointSizeF(11.3); ui->textEdit->setFont(font); QFile somefile("../mainwindow.cpp"); if(!somefile.open(QFile::ReadOnly| QFile::Text)) { qDebug() << "not open"; } QTextStream in(&somefile); ui->textEdit->setText(in.readAll()); // QTextEdit *testTextEdit = new QTextEdit(this); // ui->verticalLayout->addWidget(testTextEdit); } void MainWindow::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { ui->textEdit->setText("You pressed ESC"); } else if(event->key() == Qt::Key_Alt) { } } void MainWindow::keyReleaseEvent(QKeyEvent *event) { if(event->key() == Qt::Key_A) { ui->textEdit->setText("You released A"); } else if(event->key() == Qt::Key_Alt) { } } MainWindow::~MainWindow() { delete ui; }
TreeMap.h:
#ifndef TREEMAP_H #define TREEMAP_H #include <QString> #include <QVector> class TreeMap { public: TreeMap(QString name, TreeMap *parentNode = 0); ~TreeMap(); TreeMap nodeAt(int position) const; int nodeCount() const; QString data() const; bool insertNode(int position); TreeMap* getParent(); bool removeNode(int position); int nodeIndex() const; bool setData(const QString &value); private: QString nodeName; QVector<TreeMap> nodes; TreeMap *parent; }; #endif // TREEMAP_H
TreeMap.cpp
#include "treemap.h" TreeMap::TreeMap(QString name, TreeMap *parentNode = 0) { parent = parentNode; nodeName = name; } TreeMap::~TreeMap(QString name, TreeMap *parentNode = 0) { qDeleteAll(nodes); } TreeMap TreeMap::nodeAt(int position) const { return nodes[position]; } int TreeMap::nodeCount() const { return nodes.length(); } int TreeMap::nodeIndex() const { if (parent) return parent->nodes.indexOf(const_cast<TreeItem*>(this)); return 0; } QString TreeMap::data() const { return nodeName; } bool TreeMap::insertNode(int position) { if (position < 0 || position > nodes.length()) return false; nodes.append(new TreeMap("", this)); return true; } bool TreeMap::removeNode(int position) { if (position < 0 || position > nodes.length()) return false; nodes.remove(position,1); return true; } bool TreeMap::setData(QString &value) { if (position < 0 || position > nodes.length()) return false; nodeName = value; return true; } TreeMap* TreeMap::getParent() { return parent; }
TreeMapModel.h:
#ifndef TREEMAPMODEL_H #define TREEMAPMODEL_H #include <QAbstractItemModel> #include <QModelIndex> #include <QVariant> class TreeMap; class TreeMapModel : public QAbstractItemModel { Q_OBJECT public: TreeMapModel(); ~TreeMapModel(); // Defines for read: QString data(const QModelIndex &index, int role = Qt::DisplayRole); QString headerData() const override; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override{return 1;} Qt::ItemFlags flags(const QModelIndex &index) const override; // Defines for write: bool setData(const QModelIndex &index, const QString &value, int role = Qt::EditRole) override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; bool insertRow(int position, const QModelIndex &parent = QModelIndex()) override; bool removeRow(int position, const QModelIndex &parent = QModelIndex()) override; private: TreeMap rootNode; TreeMap *getItem(const QModelIndex &index) const; }; #endif // TREEMAPMODEL_H
TreeMapModel.cpp:
#include "treemap.h" #include "treemapmodel.h" TreeMapModel::TreeMapModel() { rootNode = new TreeMap("Root"); } TreeMapModel::~TreeMapModel() { delete rootNode; } QVariant TreeMapModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); TreeMap *node = getItem(index); return node->data(); } TreeMap *TreeMapModel::getItem(const QModelIndex &index) const { if (index.isValid()) { TreeMap *item = static_cast<TreeMap*>(index.internalPointer()); if (item) return item; } return rootNode; } Qt::ItemFlags TreeMapModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; return Qt::ItemIsEditable | QAbstractItemModel::flags(index); } QModelIndex TreeMapModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() && parent.column() != 0) return QModelIndex(); TreeMap*parentItem = getItem(parent); TreeItem *childItem = parentItem->nodeAt(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } bool TreeMapModel::insertRow(int position, const QModelIndex &parent) { TreeMap *parentItem = getItem(parent); bool success; beginInsertRows(parent, position, position); success = parentItem->insertNode(position); endInsertRows(); return true; } bool TreeMapModel::removeRow(int position, int rows, const QModelIndex &parent) { TreeMap *parentItem = getItem(parent); bool success = true; beginRemoveRows(parent, position, position); success = parentItem->removeNode(position); endRemoveRows(); return success; } QModelIndex TreeMapModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeMapModel *childItem = getItem(index); TreeMapModel *parentItem = childItem->getParent(); if (parentItem == rootNode) return QModelIndex(); return createIndex(parentItem->nodeCount(), 0, parentItem); } int TreeMapModel::rowCount(const QModelIndex &parent) const { TreeMap *parentItem = getItem(parent); return parentItem->nodeCount(); } bool TreeMapModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::EditRole) return false; TreeMapModel *item = getItem(index); bool result = item->setData(0, value); if (result) emit dataChanged(index, index); return result; } QString TreeMapModel::headerData() const override {return "";}
-
You forgot a start before
rootNode
in the declaration. -
-
Thanks for that catch, but it wasn't the error.
invalid use of incomplete type ‘class QAbstractItemModel’
If I uncomment the #define<QModelIndex> in the MainWindow class, the error originates from there (though the location is in the qabstractitemmodel.h file), and when I comment it, it comes from TreeMapModel.h
-
Sorry but I'm going to be blunt: start by cleaning up your code.
It's full of errors:
- Wrong signatures for function you want to override
- You are trying to override non-virtual methods
- Wrong type used
- You have default values in methods implementation signatures
- You want to use a QVector on a type that doesn't match the requirements to be stored in a QVector or your QVector variable declaration is wrong.
- Mismatch of function signature between declaration and implementation
- You are using undeclared variables.
-
I mostly left them in there for the sake of thoroughness. I know those other errors have nothing to do with it. I created a new widget project. It has the very basic default implementation. The only difference is the include for QModelIndex (I tried QAbstractItemModel and their combinations to no avail). So here are the only 2 files worth posting:
QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ShowError TEMPLATE = app DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ main.cpp \ mainwindow.cpp HEADERS += \ mainwindow.h FORMS += \ mainwindow.ui
MainWindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QModelIndex> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
And the result always yields:
In file included from /home/chris/Qt5.9.2/5.9.2/gcc_64/include/QtCore/QAbstractItemModel:1:0,
from ../ShowError/mainwindow.h:5,
from ../ShowError/main.cpp:1:
/home/chris/Qt5.9.2/5.9.2/gcc_64/include/QtCore/qabstractitemmodel.h:174:41: error: expected ‘)’ before ‘’ token
explicit QAbstractItemModel(QObject parent = Q_NULLPTR);
^ -
Did you modify that header at some point ?
-
Nope. (posts need at least 8 characters)
-
And your header also looks like this at line 174 ?
class Q_CORE_EXPORT QAbstractItemModel : public QObject { Q_OBJECT friend class QPersistentModelIndexData; friend class QAbstractItemViewPrivate; friend class QIdentityProxyModel; public: explicit QAbstractItemModel(QObject *parent = Q_NULLPTR); virtual ~QAbstractItemModel(); Q_INVOKABLE bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const; Q_INVOKABLE virtual QModelIndex index(int row, int column,
-
Correct
(more than 8 chars)
-
@Trayon said in Help creating a tree that traverses the map of a graph:
#include <QModelIndex>
And you get error by simply including this in a default GUI project ?
-
Yes, that is correct.
-
@Trayon
Your Qt installation must be broken then as in a default project
there cant be any circular dependency.invalid use of incomplete type ‘class QAbstractItemModel’
That error went away ? and now its just
"explicit QAbstractItemModel(QObject parent = Q_NULLPTR);"
error: expected ‘)’ before that is left?In a clean project, only thing that can be wrong is the Qt files then.
Did you use Refactor and replace or anything that might have altered the Qt files ?And just to be 100% clear,
you made a new default project with File->New and
adding #include <QModelIndex>
to that , gives error ?
If yes, then reinstall Qt. -
Reinstalled QT. Thanks for that tip. It got rid of those errors, but now I'm getting something a bit odd.
The error I got was:
no matching function for call to ‘QVector<TreeMap>::indexOf(const TreeMap)’*Here:
int TreeMap::nodeIndex() const { if (parent) return parent->nodes.indexOf(this); return 0; }
Here's TreeMap.h for reference:
#ifndef TREEMAP_H #define TREEMAP_H #include <QString> #include <QVector> class TreeMap { public: TreeMap(QString name, TreeMap *parentNode = 0); ~TreeMap(); TreeMap nodeAt(int position) const; int nodeCount() const; QString data() const; bool insertNode(int position); TreeMap* getParent(); bool removeNode(int position); int nodeIndex() const; bool setData(const QString &value); private: QString nodeName; QVector<TreeMap> nodes; TreeMap *parent; }; #endif // TREEMAP_H
-
Hi,
You have a QVector of TreeMap object,
this
is a pointer to the current object. -
Hi
nodes.indexOf(this);
"This" is a const TreeMap *
but it wants a &
int indexOf(const T &t, int from = 0) const;so you can do
int TreeMap::nodeIndex() const {
nodes.indexOf(*this);
}However, QVector wants an assignable data type so you will need some extra functions
http://doc.qt.io/qt-5/containers.html#assignable-data-typesomething like (stripped down)
class TreeMap { public: TreeMap(QString name, TreeMap* parentNode = 0) {} int nodeIndex() const; TreeMap(const TreeMap& other) {/* IMPLEMENT*/} TreeMap& operator=(const TreeMap& other) {/* IMPLEMENT*/} bool operator==(const TreeMap& other) {/* IMPLEMENT*/} // most likely wants this too private: QVector<TreeMap> nodes; };
-
Thanks mrjj.
A few more things to add. You most likely know I'm following the example here:
http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.htmlWhy is it that the example doesn't implement these functions? QList has the same shortcoming as QVector when I tried changing it. Also, should I start a new thread with the new errors that pop up in my program, or should I continue posting here as they come?
-
That example is using a QList of pointer to TreeItem you are using a QVector of TreeMap object.