[PyQt] General question about Proxy Model

Maurizio Berti maurizio.berti at gmail.com
Mon May 20 00:27:15 BST 2019


Hi John,
I think that the issue comes from your implementation of the closeEditor
slot.

Since you're calling super() *after* changing the model structure, the
view's default closeEditor() method tries to interact with what it thought
it was the "current" index, but you just deleted it: the proxy model isn't
able to map the index, since it doesn't exist anymore, then it crashes
(although, in some tests I did it justs reports inconsistencies, while in
other cases it just ignored as the index is invalid or just froze the main
loop).
After moving the super() at the beginning of the method, you'll see that
everything works as expected.
The only issue with this is that the EndEditHint will be ignored, but I
think that you can manage that.
Also remember to implement the setEditorData() with the current index.data
(but you can do that within createEditor() too).

Maurizio


Il giorno dom 19 mag 2019 alle ore 18:09 John F Sturtz <john at sturtz.org> ha
scritto:

> Hi again Maurizio.  Thanks as always for your help.
>
> Minimal example is attached.  Here is a brief summary of what it is trying
> to do:
>
> This is code to manage a list of categories and subcategories.  It creates
> a dialog (Dlg, which is loaded from the attached dlg.ui file) that uses a
> QTreeView to display a list of main categories, each of which can contain
> zero or more subcategories.  The dialog has buttons to create a new main
> category, create a new subcategory, and delete either type.
>
> The actual data for a main category or subcategory is represented by a
> CategoryNodeobject.  A tree structure of these nodes is the data
> structure that underlies the source model (CategoryTreeModel).  The
> source model manipulates the data tree using the methods defined in the
> CategoryNode class.
>
> The QTreeView (TreeView) uses a QSortFilterProxyModel proxy model to
> maintain a sorted view of the data.  Here's how I maintain the sorted
> view (not sure this is correct, but it's what I gleaned from such
> documentation as I could find):  The proxy model overrides setData(), so
> when an item in the view is edited (either an existing one is changed, or a
> new one is added), the proxy's setData() gets called.  It first calls the
> source model's setData() to update the appropriate node in the underlying
> CategoryNode tree.  Then it calls sort() and invalidate() on itself to
> sort the view.
>
> All this seems to work pretty well.  I've ensured that the model is
> implemented correctly at least to this extent:
>
>    - I've run the model through the pytest qmodeltester and not gotten
>    any warnings.
>    - I've spent quite a bit of time going about adding, deleting and
>    changing the descriptions of the items in the view using the buttons in the
>    dialog, and they seem to work properly.
>
> The problem comes when I try to do this:  When you add either a main
> category or subcategory, it creates a new node in the tree with a blank
> value, then opens a QLineEdit delegate editor to enter the description.
> If the user hits *Escape*, or hits *Enter* without typing in a value, I
> want to just delete the newly-added node and throw it away.
>
> To that end, I override closeEditor() in the TreeView.  I get the view's
> currentIndex() (which should be an index in the proxy model, I think?).
> If the value is empty, I get a reference to the source model, map the
> current index to the corresponding index in the source model (
> mapToSource()), and then call the source model's removeRows() method to
> delete it (lines 277-282).
>
> This consistently crashes or produces a warning.
>
> On my machine, the following consistently crashes:
>
>    - Start the app
>    - Click on *Reimbursible* at the bottom of the list
>    - Click the Sub button to add a new empty subcategory
>    - Hit *Escape*
>
> This consistently produces the message *QSortFilterProxyModel:
> inconsistent changes reported by source model *(but doesn't crash):
>
>    - Start the app
>    - Click on *Healthcare*
>    - Click the Sub button to add a new empty subcategory
>    - Hit Escape
>
> I thought I was doing all this correctly (don't we usually?), but clearly
> I must misunderstand some part of it.  If you (or anyone) spots a problem,
> I'd be grateful to hear it.
>
> Thanks!
>
> /John
>
> On 5/17/2019 4:37:47 PM, Maurizio Berti <maurizio.berti at gmail.com> wrote:
> Since you're implementing your own model, implementing removeRows() in the
> source model should be enough, but you have to ensure that its
> implementation responds as expected: removeRows has to return a bool, and
> the parent *must* be checked, expecially if you have a tree structure. Also
> ensure that all basic model functions (index, parent, rowCount, columnCount
> and data) are correctly implemented.
>
> I'd suggest you to give us a minimal example anyway, you might even find
> out what is wrong in your case.
>
> Maurizio
>
> Il giorno mar 14 mag 2019 alle ore 21:38 John F Sturtz <john at sturtz.org>
> ha scritto:
>
>> Hi again.
>>
>> I'm the one who started the *QTreeView + sort + delete = crash* thread
>> on May 8th.  In response to assistance from Kyle and Florian, I've
>> re-implemented to use a QAbstractItemModel with associated
>> QSortFilterProxyModel.
>>
>> On the whole, that seems to be working pretty well, but there's one thing
>> (well, at least one) I haven't been clear on despite poring over what
>> documentation I can find.  I can post the test code again if it will help,
>> but I think this is more of a general question:
>>
>> If I have both a source model and also a proxy, and I'm modifying the
>> view in a way that changes the structure (deleting a row, in the current
>> case I'm working on), should I be overriding removeRows() for *both* the
>> source model and the proxy, and calling beginRemoveRows()/endRemoveRows()
>> in both cases?
>>
>> I guess that seems to make sense to me, and my initial testing suggests
>> it's so, as it seems to work (whereas if I *don't* do that, I either get
>> a crash, or a message something like QSortFilterProxyModel: inconsistent
>> changes reported by source model).
>>
>> Same for inserting rows?  Just checking to see if I'm thinking right here.
>>
>> Thanks!
>>
>> /John
>> _______________________________________________
>> PyQt mailing list    PyQt at riverbankcomputing.com
>> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>>
>
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net
>
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>


-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190520/d419830b/attachment.html>


More information about the PyQt mailing list