[SOLVED]Custom TreeView storing objects of different classes.



  • Hello everyone ,
    I am new to Qt and i need some help regarding the implementation of a treeView with objects from different class.
    I have two classes named Employee and AccountDetails
    I am trying to store both the objects in a treview as QStandardItem and visually it should be represented with two different colors like:
    "CustomTreeView":http://imageshack.us/f/27/capturehze.png/

    While retriving the data from treeView i am filtering the information based on the child rows eg:
    @void MainWindow::on_treeView_clicked(const QModelIndex &index)
    {
    int indx =0;
    QStandardItem *item = model->itemFromIndex(index);
    if(item->hasChildren())
    return;

    QVariant variant = index.data(Qt::DisplayRole);
    
    if(index.row()==0)
    {
        Employee *empInfo = reinterpret_cast<Employee*>(variant.value<void*>());
        
        if(empInfo!=NULL)
        {   ui->txtId->setText(empInfo->getId());
            ui->txtFirstName->setText(empInfo->getFirstName());
            ui->txtLastName->setText(empInfo->getLastName());
            ui->txtCity->setText(empInfo->getCity());
        }
    
    }
    
    if(index.row()==1)
    {
        AccountDetails *accountInfo = reinterpret_cast<AccountDetails*>(variant.value<void*>());
      
        if(accountInfo!=NULL)
        {
            for(int i=0;i<bankList.size();++i)
            {
                if(accountInfo->getBankName()==bankList[i])
                {
                    indx = i;
                }
            }
            ui->cmbBank->setCurrentIndex(indx);
            ui->txtAccountNumber->setText(accountInfo->getAccountNumber());
            ui->txtBalance->setText(accountInfo->getBalance());
        }
    
    }
    

    }@

    Also i am using my own delegate subclassing from QStyledItemDelegate and in the paint method i am writing the following code to display the nodes in different colors :

    @void TreeViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    QStyledItemDelegate::paint(painter,option,index);

    QVariant variant = index.data(Qt::DisplayRole);
    Employee *empInfo = reinterpret_cast<Employee *>(variant.value<void*>());
    
    if(empInfo==NULL)
        return;
    
    if(index.row()==0)
    {
        painter->setPen(Qt::red);
        QString empDetails = QString("%1").arg(empInfo->getFirstName() + "-" + empInfo->getLastName() + "-" + empInfo->getCity());
        painter->drawText(option.rect,empDetails);
        return;
    }
    
    if(index.row()==1)
    {
        AccountDetails *accountInfo = reinterpret_cast<AccountDetails*>(variant.value<void*>());
        painter->setPen(Qt::green);
        QString accountDetails = QString("%1").arg(accountInfo->getBankName() + "-" + accountInfo->getAccountNumber() + "-" +accountInfo->getBalance());
        painter->drawText(option.rect,accountDetails);
    }
    

    }@

    Here the problem is that this approach is specific based in row number of the child items in the tree node.
    I need a solution where when i click on a node i should check whether selected item object is an instance of class Employee or AccountDetails.
    I tried the following code:
    @QObject object = dynamic_cast<QObject>variant.value<void*>();
    if(qobject_cast<Employee*>(object)!=NULL)
    {
    //do something

    }
    else if(qobject_cast<Employee*>(object)!=NULL)
    {
    //do something
    }
    @

    But it didn't work. Please help



  • If your Classes Employee & AccountDetails have been registered with qRegisterMetaType or Q_DECLARE_METATYPE

    You could just use (in your paint function)

    @
    if (index.data().canConvert<Employee*>())
    // QVariant is of type Employee*
    @

    You might possibly want to use "convert":http://qt-project.org/doc/qt-4.8/qvariant.html#convert as well to be sure your converting valid data



  • Another solution could be to introduce a user type in the model and connect that with an enum describing the different types of nodes in your tree. For example like this:

    @
    enum NodeTypes { EmployeeNode, AccountDetailsNode };
    enum MyItemRoles { NodeTypeRole = UserRole + 1 };
    @

    then in the data() method of your model return one of the enum values for the NodeTypeRole. In the delegate query the type:

    @
    NodeTypes nodeType = static_cast<NodeTypes>(index.data(NodeTypeRole));

    if(nodeType == EmployeeNode) {
    // draw red
    Employee empInfo = reinterpret_cast<Employee >(variant.value<void>());
    } else if( nodeType == AccountDetailsNode) {
    // draw green
    AccountDetails accountInfo = reinterpret_cast<AccountDetails>(variant.value<void
    >());
    }
    @



  • Nosf,
    I tried to register both classes with Q_DECLARE_METATYPE and qRegisterMetatype<Employee>("Employee");
    But while converting it with:

    @if(index.data().canConvert<Employee*>())@

    it always returns false, I also tried,

    @if(qVariantCanConvert<Employee>(variant)@

    this also returns false.

    Volker,
    I got the idea about what has to be implemented but the thing is that i am confused how to use the
    UserRole in my model. As of now I am using a QStandardItemModel. Also, i tried to subclass QStandardItemModel and override the data() function of MyModel.
    While storing the item i tried the following code:

    @QStandardItem itemEmployee = new QStandardItem();
    itemEmployee->setData(QVariant::fromValue<void
    >(m_Employee),EmployeeNode);
    itemId->appendRow(itemEmployee);

    QStandardItem *itemAccounts = new QStandardItem();
    itemAccounts->setData(QVariant::fromValue<void*>(m_Accounts),AccountDetailsNode);
    itemId->appendRow(itemAccounts);@
    

    I have searched for the same problem on net and got the same solution that are listed above but while implementing its not working.

    Please help.Thanks for your time :)



  • You do not need to sublcass the standard item model. Just call data() and setData() with the UserRole. Everything else is handled by the model for you, i.e. it stores the value of the enum for you. You just need to call setData() with the UserRole at the time you populate the model.



  • Volker,

    Thanks for you help and support, I tried with that approach but didnt get the result as when i cast the Qt::UserRole it returns 0. So i got other approach.
    I subclassed both classes Employee and AccountDetails from a Base class.

    Then I tried the following code and it works

    @QVariant variant = index.data(Qt::DisplayRole);
    Employee empInfo = dynamic_cast<Employee>((Base )variant.value<void>());
    AccountDetails accInfo = dynamic_cast<AccountDetails>((Base )variant.value<void>());

    if(empInfo!=NULL)
    {
    //paint red
    }
    if(accInfo!=NULL)
    {
    //paint green
    }
    @

    Thanks for your time :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.