Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct


    Qt World Summit: Early-Bird Tickets

    [SOLVED]Custom TreeView storing objects of different classes.

    General and Desktop
    3
    6
    5262
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S
      Sam last edited by

      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

      1 Reply Last reply Reply Quote 0
      • N
        Nosf last edited by

        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

        1 Reply Last reply Reply Quote 0
        • G
          goetz last edited by

          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
          >());
          }
          @

          http://www.catb.org/~esr/faqs/smart-questions.html

          1 Reply Last reply Reply Quote 0
          • S
            Sam last edited by

            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 :)

            1 Reply Last reply Reply Quote 0
            • G
              goetz last edited by

              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.

              http://www.catb.org/~esr/faqs/smart-questions.html

              1 Reply Last reply Reply Quote 0
              • S
                Sam last edited by

                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 :)

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post