Results 1 to 15 of 15

Thread: Sharing Selections between Model and ProxyModel

  1. #1
    Join Date
    Jun 2006
    Posts
    12
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Question Sharing Selections between Model and ProxyModel

    Hi All-

    I am new to Qt 4 (I have used Qt 3 for sometime however), and I am trying to get a handle on the use of the model/view architecture. Specifically, the data that will ultimately populate the model is hierarchal in nature and I plan on having two separate views: one a QTreeView and the other a QTableView that will just show the leaves of the tree. I am assuming that I will need to implement a proxymodel in order to mask a tabular model on top of the hierarchical model and translate indices between the two types of views.

    Working under that assumption, I have been trying to learn the ins and outs of how a proxymodel and a model are supposed to interact with one another. Using Qt's sortingmodel example - found in QTDIR/examples/itemviews/sortingmodel/main.cpp - as a starting point, I have been trying to figure out how one is supposed to share a selection between the two views. Therefore, I have made the following change to that aforementioned main.cpp file:

    ----------------------------------------------------------------------------------------------
    sortedView.header()->setClickable(true);

    sortedView.setSelectionModel(unsortedView.selectio nModel()); // line added

    sortedView.show();
    ----------------------------------------------------------------------------------------------

    As may come to no surprise to some of you, this didn't work. I know that I should be using mapSelectionToSource and/or mapSelectionFromSource somewhere, but I'm not sure where. Should I re-implement QTreeView in order to tell the object that its referenced model is a proxymodel? That doesn't seem right. I would assume that since the QSortFilterProxyModel was developed by Trolltech, that it already has the important code where its needed, so that's doesn't seem right either. Should I make a change to the TreeModel referenced in the example? Any thoughts on how to get going here?

    Thank you for your time!

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    As far as I understand models and selections, you can't share a selection between different models, becuase their indexes don't match. If you want to have a simmilar selection model for both models, you have to implement a controller which will be connected to selectionChanged() signals of the models and will map selections from one model to the other (for example using the same scheme the proxy model uses).

  3. #3
    Join Date
    Jun 2006
    Posts
    12
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Sharing Selections between Model and ProxyModel

    Quote Originally Posted by wysota
    As far as I understand models and selections, you can't share a selection between different models, becuase their indexes don't match. If you want to have a simmilar selection model for both models, you have to implement a controller which will be connected to selectionChanged() signals of the models and will map selections from one model to the other (for example using the same scheme the proxy model uses).
    Thanks. I'll give that a try. Since a wrapper is by definition an interface to some underlying structure, I would have thought this would be something encapsulated in some way since I can't imagine that I would be the only one that would need to share selections between a model and a WRAPPER of that model.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    The point is that you need to translate selections between different models. It's not a wrapper -- "controller" or "synchroniser" are better words for that. You are really implementing an additional listener layer -- you need to monitor for changes in one selection model and react by changing the other one (just make sure you don't fall into an infinite loop).

  5. The following user says thank you to wysota for this useful post:

    mentat (28th June 2006)

  6. #5
    Join Date
    Jun 2006
    Posts
    12
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Sharing Selections between Model and ProxyModel

    Quote Originally Posted by wysota
    The point is that you need to translate selections between different models. It's not a wrapper -- "controller" or "synchroniser" are better words for that. You are really implementing an additional listener layer -- you need to monitor for changes in one selection model and react by changing the other one (just make sure you don't fall into an infinite loop).
    I actually meant that the proxy is considered a wrapper..at least that's how it is documented, but I'll give your suggestion a try.

    In general, I've had a lot of trouble with proxymodels, and understanding how they are related with the underlying model. For instance, for the life of me, I can not get a tablular view of the data by re-implementing mapFromSource and mapToSource to translate or compress the underlying hierarchical model into a tabular model. I guess my question becomes: when are these map*Source functions called when the view is being built since obviously the QTableView itself doesn't call them? Is there any better documentation or real examples of M/V then those on the Qt site? In general, when it comes from starting from square one as I am, it is extremely difficult to figure out which end is up based on a few sentences here or there.

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    Quote Originally Posted by mentat
    I actually meant that the proxy is considered a wrapper..at least that's how it is documented, but I'll give your suggestion a try.
    It is a wrapper in that way that it transforms the already existing model to provide a new hierarchy.


    In general, I've had a lot of trouble with proxymodels, and understanding how they are related with the underlying model. For instance, for the life of me, I can not get a tablular view of the data by re-implementing mapFromSource and mapToSource to translate or compress the underlying hierarchical model into a tabular model. I guess my question becomes: when are these map*Source functions called when the view is being built since obviously the QTableView itself doesn't call them? Is there any better documentation or real examples of M/V then those on the Qt site? In general, when it comes from starting from square one as I am, it is extremely difficult to figure out which end is up based on a few sentences here or there.
    QTableView doesn't have to call them. It calls data() to read the data from the model. And then the proxy should map the request (for example the index) using methods you mentioned to fetch the data from the underlying model and give that data back to the object which requested it (like the view in this case).

    I belive that if you wanted to make a simple transformation of the model where you'd like to transpose the model (exchange columns with rows), you'd have to implement such a proxy:

    Qt Code:
    1. class TransposeProxyModel : public QAbstractProxyModel{
    2. public:
    3. TransposeProxyModel(QObject *p = 0) : QAbstractProxyModel(p){}
    4. QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const{
    5. return index(sourceIndex.column(), sourceIndex.row());
    6. }
    7. QModelIndex mapToSource ( const QModelIndex & proxyIndex ) const{
    8. return sourceModel()->index(proxyIndex.column(), proxyIndex.row());
    9. }
    10. QModelIndex index(int r, int c, const QModelIndex &ind) const{
    11. return createIndex(r,c);
    12. }
    13. QModelIndex parent(const QModelIndex&) const {
    14. return QModelIndex();
    15. }
    16. int rowCount(const QModelIndex &) const{
    17. return sourceModel()->columnCount();
    18. }
    19. int columnCount(const QModelIndex &) const{
    20. return sourceModel()->rowCount();
    21. }
    22. QVariant data(const QModelIndex &ind, int role) const {
    23. return sourceModel()->data(mapToSource(ind), role);
    24. }
    25.  
    26. };
    To copy to clipboard, switch view to plain text mode 

    Edit: I forgot to implement the rest of pure virtual methods
    Last edited by wysota; 28th June 2006 at 21:30.

  8. The following user says thank you to wysota for this useful post:

    mentat (28th June 2006)

  9. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    And a small example to illustrate.
    Attached Images Attached Images
    Attached Files Attached Files

  10. The following user says thank you to wysota for this useful post:

    mentat (28th June 2006)

  11. #8
    Join Date
    Jun 2006
    Posts
    12
    Thanks
    5
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Sharing Selections between Model and ProxyModel

    Quote Originally Posted by wysota
    Qt Code:
    1. QVariant data(const QModelIndex &ind, int role) const {
    2. return sourceModel()->data(mapToSource(ind), role);
    3. }
    4.  
    5. };
    To copy to clipboard, switch view to plain text mode 
    I think that may have been what I was forgetting. The good news, while the app is now crashing (probably due to a still-to-be-bugfixed transformation algo on my part), it is now calling map*Source correctly! Thanks for your help. I'll bug fix the code this evening and see what I can see. Hopefully this will mean that I have a working proxy model. Then I would just need to implement the selection code noted previously, and everything should be working.

  12. #9
    Join Date
    Nov 2006
    Posts
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Sharing Selections between Model and ProxyModel

    Quote Originally Posted by wysota View Post
    And a small example to illustrate.
    I have a couple of questions. It appears that changes in the table on the left are not reflected in the table on the right until I move the slider or shade-and-unshade the window or do something else that causes a repaint. Is there a way to keep the model and its proxy and view in sync?

    Also, I noticed that changing items on the right (the proxy model's view) does not result in changing items on the left. Is there an easy way to make it bi-directional?

  13. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    The example is very simple and only illustrates the way of handling things. To implement features you want, you'd probably have to reimplement setData() and connect proper signals and slots so that changes propagate between models.

  14. #11
    Join Date
    Nov 2006
    Posts
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Sharing Selections between Model and ProxyModel

    By reimplementing setData() in the proxy model, I managed to get changes in the proxy model to be reflected by in the original model.

    However, I am still having a slight problem keeping the proxy in sync with the original model. For example, if I changed row 1, column 1, from "1" (the original value) to "A", the proxy model's view is not updated until I do something like move the scroll bar or something else that generates events or signals.

    Which signal should I connect to which slot (and which object)?

  15. #12
    Join Date
    Jan 2010
    Posts
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Sharing Selections between Model and ProxyModel

    The transpose proxy code (http://wiki.qtcentre.org/index.php?t...se_Proxy_Model) works fine but only with quadratic models where there are the same number of rows and columns. If there are e.g. more columns than rows the data() function is not called for all cells that it needs to be called for. Is there anyone who knows how to implement this transpose with a on-quadratic model?

  16. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    The model is broken, it was just an example. But it should work for non-square models too, I don't see what would prevent it from that. The only two things that are not in the model is reacting to changes in the source model and handling hierarchical source models. Apart from that the example is fully functional.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  17. #14
    Join Date
    Jan 2010
    Posts
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Sharing Selections between Model and ProxyModel

    It does not work for non-square models since the data-functions is not called enough number of times if there is e.g. more columns than rows

  18. #15
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Sharing Selections between Model and ProxyModel

    You are wrong, I just checked it. The model works fine for non-square models.

    Qt Code:
    1. int main(int argc, char **argv){
    2. QApplication app(argc, argv);
    3. QStandardItemModel model(3,5);
    4. for(int i=0;i<5;i++)
    5. for(int j=0;j<3;j++){
    6. model.setData(model.index(j,i), qrand()%20);
    7. }
    8. v1.setModel(&model);
    9. TransposeProxyModel proxy;
    10. proxy.setSourceModel(&model);
    11. v2.setModel(&proxy);
    12. v1.show();
    13. v2.show();
    14. return app.exec();
    15. }
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.