[Qt-interest] MVC Questions and Syncing QTreeView and QTableView

Stephen Kelly steveire at gmail.com
Wed Jan 12 16:25:54 CET 2011


lbutler3 at comcast.net wrote:

> Stephen / Sean
> 
> 
> To use your analogy, it is more like option 2: I have one QTreeView where
> I display all the folders and all the files in the folders along with the
> creation time for each file or folder. The QTableView has only the files
> listed, along with their file sizes and owners. The QTableView is sorted
> in alphabetical order, or optionally file size order, not in filesystem
> tree order. It displays all of the files, not just the ones in a
> particular folder.
> 
> 
> If I try to have 1 model (certainly convenient), then the model needs to
> know what view is asking the question in order to be able to provide the
> answer. For example, column2 of the QTreeView is the creation time, while
> column2 of the QTableView is the file size. Row 3 of the QTreeView might
> be a folder, but row 3 of the QTableView would be a file. Making that work
> with 1 model didn't seem straightforward.
> 

It's not as difficult as you might think. You have your master tree model, 
and make sure its columnCount() == qMax(tableColumns, treeColumns). Also 
make sure the data that goes into those columns is available through the 
first column through custom roles. Then use two proxies for getting the data 
for each column from the master tree and delivering it through the 
appropriate column, and for filtering out the columns that are not needed:

class MyTreeDataProxy : public QSortFilter
{
  bool filterAcceptsColumn(int column) const
  {
     return column < 2;
  }

  QVariant data( index, role ) const
  {
    if (role == Qt::DisplayRole && column == 1)
     return index.sibling(index.row(), 0).data(CreationTimeRole);
  }

};

class MyTableDataProxy : public QSortFilter
{
   // Not needed in the description
  // bool filterAcceptsColumn(int column)

  bool filterAcceptsRow(int row) {
    if row is not folder 
      return true
    else 
      return false
  }
  
  // Custom sorting:
  bool lessThan() const;

  QVariant data( index, role )
  {
    if (role == Qt::DisplayRole) {
     if (column == 1)
       return index.sibling(index.row(), 0).data(FileSizeRole);
     if (column == 2)
       return index.sibling(index.row(), 0).data(OwnerRole);
  }
};

Then you use them together with a proxy to flatten the tree:

     - instance of MyTreeDataProxy >> QTreeView
    /
master tree
    \ - KDescendantsProxyModel >> instance of MyTableDataProxy >> QTableView

Then you need to link the two selection models:

// Make sure to set the source before messing with the selection models.
treeView->setSourceModel(myTreeDataProxy);
tableView->setSourceModel(myTableDataProxy);

// Link the two selection models through the proxies:
KLinkItemSelectionModel *tableSelectionModel = new KLinkItemSelectionModel( 
myTableDataProxy, treeView->selectionModel());

tableView->setSelectionModel(tableSelectionModel);

This is almost much as advanced as Qt itemsview gets, but you need to depend 
on KDE libraries. I'd prefer them in Qt, but I don't think that's going to 
happen unfortunately.

All the best,

Steve.





More information about the Qt-interest-old mailing list