vulcan
17th January 2013, 22:00
Hi all,
First post here - I'm beginning on Qt, having just gotten a good foothold [though I suppose these things are always subjective] on C++. Here's my issue:
I'm creating a QTreeView hooked up to a custom model that stores file paths for the program to process, sorted by "Device" (or some other arbitrary header). If the program gets passed a valid file path, it should automatically parent it to a new device.
So, the idea is to have:
Root Item
|
- Device Item #1
- File #1
- File #2
- ....
- Device Item #2
[/code]
In the data structure, everything seems fine. Things are constructed appropriately, in Debug mode, I can walk through from the root item all the way to each child through the recursive layers of QList<Node *>. All the data seems correct.
When I hook it up to the QTreeView, and try to expand, I end up with the DisplayRole data of the parent being displayed for all the children. I've tried variations with deeper levels of children/parents, but it always shows me incorrect data for the children. In what seems like adding insult to injury, the WhatsThisRole data actually displays correctly - I can hover over the item and it will show me the correct text (it showing me the correct text was an addition by me in the data() function just to make sure I wasn't going crazy). Adding to the confusion, it appears that the selection model seems to be off a bit - I can't unclick items once selected, and selecting a child item selects all child items, same parent or not.
It has to be something in my code. I have a bunch of logging/debugging lines set into it that will take a bit to back out (without losing them). I'm assuming though that the issue is in my Model implementation. Being my first time with this, I'm heavily leaning on the examples provided in books and online to get a good model implementation going. Code below.
QModelIndex ParseList::index(int row, int column, const QModelIndex &parent) const
{
if(!head || row < 0 || column < 0)
{
return QModelIndex();
}
ParseNode * parentNode = nodeFromIndex(parent);
ParseNode * childNode = parentNode->getChild(row);
if(!childNode)
{
return QModelIndex();
}
QModelIndex temp = createIndex(row,column, childNode);
return createIndex(row, column, childNode);
}
QModelIndex ParseList::parent(const QModelIndex &child) const
{
ParseNode * node = nodeFromIndex(child);
if(!node)
return QModelIndex();
ParseNode * parentNode = node->getParent();
if(!parentNode)
{
return QModelIndex();
}
ParseNode * grandparentNode = parentNode->getParent();
if(!grandparentNode)
{
return QModelIndex();
}
int row = grandparentNode->indexOf(parentNode);
return createIndex(row, 0, parentNode);
}
int ParseList::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
{
return 0;
}
ParseNode *parentNode = nodeFromIndex(parent);
if(!parentNode)
{
return 0;
}
return parentNode->childCount();
}
int ParseList::columnCount(const QModelIndex &parent) const
{
return ParseNode::dataColumns;
}
QVariant ParseList::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
{
return QVariant();
}
ParseNode * node = nodeFromIndex(index);
if (!node)
{
return QVariant();
}
//TODO: Decide if smaller functions would be better
// - small private functions
switch(index.column())
{
case 0:
switch(role)
{
case Qt::DisplayRole:
{
return node->getPathString(); //stored as QString in node
}
case Qt::WhatsThisRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
return node->getPathString();//tr("Path of selected log"); //Added for debug
default:
return QVariant();
}
case 1:
switch(role)
{
case Qt::DisplayRole:
return node->getParseStatus() ? tr("Yes") : tr("No"); //Stored as bool in underlying class
case Qt::WhatsThisRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
return node->getParseStatus() ?
tr("Log has been parsed") :
tr("Log has not been parsed");
default:
return QVariant();
}
case 2:
switch(role)
{
case Qt::DisplayRole:
switch(node->getPathType()) //public enum declared by ParseNode
{
case ParseNode::File:
return tr("File");
case ParseNode::FileButNotReadable:
return tr("File - Unreadable");
case ParseNode::Directory:
return tr("Directory");
case ParseNode::Invalid:
return tr("Invalid");
case ParseNode::Device:
return tr("Device");
default:
return QVariant();
}
case Qt::WhatsThisRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
switch(node->getPathType())
{
case ParseNode::File:
return tr("File from system");
case ParseNode::FileButNotReadable:
return tr("File exists, but is unreadable");
case ParseNode::Directory:
return tr("Directory from system");
case ParseNode::Invalid:
return tr("Invalid path specified");
default:
return QVariant();
}
default:
return QVariant();
}
default:
return QVariant();
}
}
And here's a screencap with things hooked up and at their worst:
8592
When I take out the "auto-reparenting" code, everything displays correctly on the top level, but again, all the children display the parent's data.
Hopefully I've provided a good start of information - does anyone have any ideas? I can work on trimming things up further to get a .zip of what I'm seeing together as a compilable example.
I'm using Qt 4.8.1 with MinGW as a compiler. The IDE I'm using is Qt Creator 2.4.1.
Thanks in advance!
First post here - I'm beginning on Qt, having just gotten a good foothold [though I suppose these things are always subjective] on C++. Here's my issue:
I'm creating a QTreeView hooked up to a custom model that stores file paths for the program to process, sorted by "Device" (or some other arbitrary header). If the program gets passed a valid file path, it should automatically parent it to a new device.
So, the idea is to have:
Root Item
|
- Device Item #1
- File #1
- File #2
- ....
- Device Item #2
[/code]
In the data structure, everything seems fine. Things are constructed appropriately, in Debug mode, I can walk through from the root item all the way to each child through the recursive layers of QList<Node *>. All the data seems correct.
When I hook it up to the QTreeView, and try to expand, I end up with the DisplayRole data of the parent being displayed for all the children. I've tried variations with deeper levels of children/parents, but it always shows me incorrect data for the children. In what seems like adding insult to injury, the WhatsThisRole data actually displays correctly - I can hover over the item and it will show me the correct text (it showing me the correct text was an addition by me in the data() function just to make sure I wasn't going crazy). Adding to the confusion, it appears that the selection model seems to be off a bit - I can't unclick items once selected, and selecting a child item selects all child items, same parent or not.
It has to be something in my code. I have a bunch of logging/debugging lines set into it that will take a bit to back out (without losing them). I'm assuming though that the issue is in my Model implementation. Being my first time with this, I'm heavily leaning on the examples provided in books and online to get a good model implementation going. Code below.
QModelIndex ParseList::index(int row, int column, const QModelIndex &parent) const
{
if(!head || row < 0 || column < 0)
{
return QModelIndex();
}
ParseNode * parentNode = nodeFromIndex(parent);
ParseNode * childNode = parentNode->getChild(row);
if(!childNode)
{
return QModelIndex();
}
QModelIndex temp = createIndex(row,column, childNode);
return createIndex(row, column, childNode);
}
QModelIndex ParseList::parent(const QModelIndex &child) const
{
ParseNode * node = nodeFromIndex(child);
if(!node)
return QModelIndex();
ParseNode * parentNode = node->getParent();
if(!parentNode)
{
return QModelIndex();
}
ParseNode * grandparentNode = parentNode->getParent();
if(!grandparentNode)
{
return QModelIndex();
}
int row = grandparentNode->indexOf(parentNode);
return createIndex(row, 0, parentNode);
}
int ParseList::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
{
return 0;
}
ParseNode *parentNode = nodeFromIndex(parent);
if(!parentNode)
{
return 0;
}
return parentNode->childCount();
}
int ParseList::columnCount(const QModelIndex &parent) const
{
return ParseNode::dataColumns;
}
QVariant ParseList::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
{
return QVariant();
}
ParseNode * node = nodeFromIndex(index);
if (!node)
{
return QVariant();
}
//TODO: Decide if smaller functions would be better
// - small private functions
switch(index.column())
{
case 0:
switch(role)
{
case Qt::DisplayRole:
{
return node->getPathString(); //stored as QString in node
}
case Qt::WhatsThisRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
return node->getPathString();//tr("Path of selected log"); //Added for debug
default:
return QVariant();
}
case 1:
switch(role)
{
case Qt::DisplayRole:
return node->getParseStatus() ? tr("Yes") : tr("No"); //Stored as bool in underlying class
case Qt::WhatsThisRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
return node->getParseStatus() ?
tr("Log has been parsed") :
tr("Log has not been parsed");
default:
return QVariant();
}
case 2:
switch(role)
{
case Qt::DisplayRole:
switch(node->getPathType()) //public enum declared by ParseNode
{
case ParseNode::File:
return tr("File");
case ParseNode::FileButNotReadable:
return tr("File - Unreadable");
case ParseNode::Directory:
return tr("Directory");
case ParseNode::Invalid:
return tr("Invalid");
case ParseNode::Device:
return tr("Device");
default:
return QVariant();
}
case Qt::WhatsThisRole:
case Qt::StatusTipRole:
case Qt::ToolTipRole:
switch(node->getPathType())
{
case ParseNode::File:
return tr("File from system");
case ParseNode::FileButNotReadable:
return tr("File exists, but is unreadable");
case ParseNode::Directory:
return tr("Directory from system");
case ParseNode::Invalid:
return tr("Invalid path specified");
default:
return QVariant();
}
default:
return QVariant();
}
default:
return QVariant();
}
}
And here's a screencap with things hooked up and at their worst:
8592
When I take out the "auto-reparenting" code, everything displays correctly on the top level, but again, all the children display the parent's data.
Hopefully I've provided a good start of information - does anyone have any ideas? I can work on trimming things up further to get a .zip of what I'm seeing together as a compilable example.
I'm using Qt 4.8.1 with MinGW as a compiler. The IDE I'm using is Qt Creator 2.4.1.
Thanks in advance!