[Maya-Python] Qt Path serialistation/de-serialisation

267 views
Skip to first unread message

Marcus Ottosson

unread,
Jun 3, 2014, 10:19:02 AM6/3/14
to python_in...@googlegroups.com

Hi all,

I’ve mocked up a method for serialising paths of widgets within a hierarchy of widgets into a Unix-style path, that can then be de-serialised back into its original widget.

Motivation is to be able to reference widgets within deeply nested hierarchies, both for better understanding and debugging but also for undo/redo and messaging.

I’m calling it qtpath for the lack of a better name. Before I make a big deal out of it, I wanted to reach out to you guys in case you’ve encountered anything similar, have ever found the need or can think of alternative methods of achieving the same goal.

https://github.com/abstractfactory/labs/tree/master/python/pyqt/qtpath

>> qtpath.abspath(window, button)
'/Win.Demo/Body.QWidget/Button.QPushButton'

Let me know what you think.

Best,
Marcus

--
Marcus Ottosson
konstr...@gmail.com

Fredrik Averpil

unread,
Jun 3, 2014, 11:04:41 AM6/3/14
to python_in...@googlegroups.com
That's a great idea and I think it fills a need at least for me.

In all classes I set the parent into something that can be accessed from a global object, which I know is always available from all classes. So in the end I can reach UI elements in a similar manner. 
But this could of course sometimes become problematic if a class can have different parents.

// Fredrik






--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmOC8yntWFgKpaEXDs8f%2BCvSLxvQXtJ1ZLLJABoZs9N8swQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Marcus Ottosson

unread,
Jun 3, 2014, 11:43:19 AM6/3/14
to python_in...@googlegroups.com

Thanks Fredrik, I’ve also felt the need for something like this. Especially for debugging and CSS.

But this could of course sometimes become problematic if a class can have different parents.

Could you elaborate on this?




For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Fredrik Averpil

unread,
Jun 3, 2014, 12:20:16 PM6/3/14
to python_in...@googlegroups.com

Sure. But I was referring to what I usually do, and which could sometimes be problematic and where it looks like your qtpaths solves it (I think):

I set the parent from within a subclass with a parent like

self.mainName = parent

And then if this subclass is inherited I may set

self.mainName.subclassName = parent

And so on… and then I would make sure I can access these object names throughout my app. So from any class, I can access self.mainName.subclassName.widgetName

But in the case of e.g. an image viewer which loads the same widget n times (e.g. one per image), you can’t hard code names like that. That’s where I thought your solution seemed nice, cause then you could serialize on window or maybe parent widget.

On a slightly different note… if you load ui files into PySide vs PyQt the recommended ways of doing it – PySide/QUiLoader vs PyQt/uic.loadUi – this results in different ways of fetching the ui widgets. I solved this with by using PySide/pysideuic vs PyQT/uic, as shown in this boilerplate: https://github.com/fredrikaverpil/pyVFX-boilerplate
I wrote more about that in detail here: https://github.com/fredrikaverpil/pyVFX-boilerplate/wiki#why-pysideuic
Not sure if that is at all related to what you're doing but maybe worth taking into account.

// Fredrik

Marcus Ottosson

unread,
Jun 3, 2014, 2:12:44 PM6/3/14
to python_in...@googlegroups.com

Ah, we might be referring to separate issues.

Have a look at this:

class Demo(QtWidgets.QWidget):
    """
    Object hierarchy looks like this:
        Win (Demo)
        |-- Body (QWidget)
            |-- Button (QPushButton)

    Which translates into:
        /Win.Demo/Body.QWidget/Button.QPushButton

    """

    def __init__(self, parent=None):
        super(Demo, self).__init__(parent)

        body = QtWidgets.QWidget()

        demo_button = QtWidgets.QPushButton('Hello Demo')
        body_button = QtWidgets.QPushButton('Hello Body')

        layout = QtWidgets.QHBoxLayout(body)
        layout.addWidget(body_button)

        layout = QtWidgets.QHBoxLayout(self)
        layout.addWidget(demo_button)
        layout.addWidget(body)

        for widget_, name_ in {
                self: 'Win',
                body: 'Body',
                demo_button: 'Button',
                body_button: 'Button',
                }.iteritems():
            widget_.setObjectName(name_)

if __name__ == '__main__':
    import sys

    # Set-up PyQt application
    app = QtWidgets.QApplication(sys.argv)
    win = Demo()

    # How we would normally find `Button` within `Demo`
    find_button = win.findChild(QtWidgets.QPushButton, 'Button')

    # Get an instance from `Demo` by serialised path
    button = qtpath.instance(win, '/Body.QWidget/Button.QPushButton')
    button = qtpath.instance(win, '/Button.QPushButton')
    assert find_button == button

    # Get back the serialised path from instance.
    assert qtpath.abspath(win, button) == '/Win.Demo/Button.QPushButton'

    # A path may return nothing
    missing = qtpath.instance(win, '/Body.QWidget/Checkbox.QWidget')
    assert missing is None

    # findPath searches a hierarchy, regardless of proximity to root
    # The following will return `Button` closest to `Win`, there is no
    # way to directly reference the nested `Button`.
    button = win.findChild(QtWidgets.QPushButton, 'Button')
    assert button.parent() == win

    button = qtpath.instance(win, '/Body.QWidget/Button.QPushButton')
    assert button is not find_button

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 3, 2014, 4:11:44 PM6/3/14
to python_in...@googlegroups.com
Hey Marcus,

I can see the value in using this tool for debugging purposes, as a convenient way to list the absolute location of a given widget in a meaningful way. That is, as long as all of your widgets have meaningful names set on them.

But I am wondering, if used in non-debugging (normal production) circumstances, does this promote poor Qt design by encouraging people to break encapsulation between components of the Qt application? I've always been under the impression that it should be preferable to not have objects at higher levels reaching into subcomponents, or visa-versa child components knowing absolute paths outside locations. What would be some of the valid use-cases in non-debugging situations for providing this type of behavior? 

For instance with the Undo/Redo example you had given, my assumption is you would be using this to have the command entries be able to retain an absolute reference to teh widget for which it will want to operate on at a later date, should that command be activated in the history stack. But instead of storing absolute string paths based on object names and types, would it not be more consistent and safer to store weak references to the target widget? A weak reference will be the actual object, valid until the source object is garbage collected, and would withstand circumstances of the widget being reparented or deleted. It could be quite common for a widget to be moved into a different layout or under a different parent. 

Also that it is valid for two sibling objects to have the same objectName. So which one gets resolved when it is by objectName and parent hierarchy?
class Window(QtGui.QDialog):
    def __init__(self):
        super(Window, self).__init__()

        self.button1 = QtGui.QPushButton("Button1", self)
        self.button1.setObjectName("button")

        self.button2 = QtGui.QPushButton("Button2", self)
        self.button2.setObjectName("button")

        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)

        self.button1.clicked.connect(self.me)
        self.button2.clicked.connect(self.me)

    def me(self):
        print self.sender().objectName()
# button
# button
I'm just curious to know what you would consider to be valid production usages of this tool that warrant relying on absolute widget locations in deeply nested hierarchies. 

-- justin


 


Marcus Ottosson

unread,
Jun 3, 2014, 5:35:27 PM6/3/14
to python_in...@googlegroups.com

Ah, but I believe you’re missing the bigger picture.

Files and folders have absolute paths and we can reference them. But of course, coding anything to absolute paths is no good and I believe the same is true for object hierarchies. With files, we develop resolvers and expression to help decouple them from their roots; I believe the same could be true for object hierarchies.

The problem with directly referencing anything is the spaghetti of links you get between objects operating on other objects.

The need arose when working with many widgets composited within other widgets (think ItemViews) and where each item needed to signal an event up through a hierarchy. To keep everything perfectly decoupled, it made sense to not introduce a global variable or singleton and have each level instead receive a signal and forward it to its parent until eventually being handled by the topmost parent. Simple in theory.

In theory, theory and practice are the same. In practice, they are not. - Albert Einstein

What ends up happening is that whenever you introduce another widget in-between two widget, you’ll have to pick up those signals and forward them to the next, and so the story goes. Changing anything was a nightmare. To borrow terminology from Chad, it’s quite the PITA.

With qtpath, my thinking is that logical hierarchies can be decoupled from their physical hierarchy, in that widgets with no objectName are skipped during traversal. That way, programmers can design a hierarchy they wish to program against, regardless of any hierarchy Qt enforces upon you (e.g. QScrollArea having multiple unexpected children).

# Reference `button`, even though there may be multiple levels of unnamed parents inbetween.
$ /root.QWidget/button.QPushButton

As for your example, of two object names being identical, this is something I would consider poor programming effort and I’d entrust programmers to not get themselves in such a situation.

Thoughts?

Tony Barbieri

unread,
Jun 3, 2014, 5:53:54 PM6/3/14
to python_in...@googlegroups.com
Ah, but I believe you’re missing the bigger picture.

Honestly referencing UI this way seems to promote not using an established pattern.  For debugging purposes it may be useful, but for production code referencing UI elements like this should most likely be avoided.

What ends up happening is that whenever you introduce another widget in-between two widget, you’ll have to pick up those signals and forward them to the next, and so the story goes. Changing anything was a nightmare. To borrow terminology from Chad, it’s quite the PITA.

Perhaps there is another issue with the overall design if it's ending up becoming a tangled mess.  Are you using QAbstractItemModels or the Qt "MVC" framework?  Once I understood how to use or extend their built in classes my life became a lot simpler.

With qtpath, my thinking is that logical hierarchies can be decoupled from their physical hierarchy, in that widgets with no objectName are skipped during traversal. That way, programmers can design a hierarchy they wish to program against, regardless of any hierarchy Qt enforces upon you (e.g. QScrollArea having multiple unexpected children).

Using an established MVC design principle should allow you to design your hierarchies as you see fit and avoid this problem...I hate pulling out lingo like MVC but trying to use an established pattern can really help you design more modular/flexible code.

This is just from my experience so take it with a grain of salt.  I've typically found if everything starts to become a tangled mess or it's getting hard to maintain I'm doing it wrong.
 


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
-tony

Justin Israel

unread,
Jun 3, 2014, 6:11:01 PM6/3/14
to python_in...@googlegroups.com
On Wed, Jun 4, 2014 at 9:35 AM, Marcus Ottosson <konstr...@gmail.com> wrote:

Ah, but I believe you’re missing the bigger picture.

Files and folders have absolute paths and we can reference them. But of course, coding anything to absolute paths is no good and I believe the same is true for object hierarchies. With files, we develop resolvers and expression to help decouple them from their roots; I believe the same could be true for object hierarchies.

Ah but I am not really talking about trying to create an abstraction that is consistent with a filesystem. I am only talking about designs in Qt application, where as far as I know it can be a poor habit to maintain so much global knowledge across widgets about all of the hierarchies and composed children of widgets.
 

The problem with directly referencing anything is the spaghetti of links you get between objects operating on other objects.

The need arose when working with many widgets composited within other widgets (think ItemViews) and where each item needed to signal an event up through a hierarchy. To keep everything perfectly decoupled, it made sense to not introduce a global variable or singleton and have each level instead receive a signal and forward it to its parent until eventually being handled by the topmost parent. Simple in theory.

In theory, theory and practice are the same. In practice, they are not. - Albert Einstein

What ends up happening is that whenever you introduce another widget in-between two widget, you’ll have to pick up those signals and forward them to the next, and so the story goes. Changing anything was a nightmare. To borrow terminology from Chad, it’s quite the PITA.

Are you sure signal/slots are the right tool for the job in this case? If your focus is trying to create a deep connection of signal propagation all the way up, maybe there is a better way involving custom QEvents or using an event filters? There are examples online about how to get custom QEvents to automatically propagate up the parent hierarchy until someone handles it or it falls off. The same as built in QEvents. 
 

With qtpath, my thinking is that logical hierarchies can be decoupled from their physical hierarchy, in that widgets with no objectName are skipped during traversal. That way, programmers can design a hierarchy they wish to program against, regardless of any hierarchy Qt enforces upon you (e.g. QScrollArea having multiple unexpected children).

# Reference `button`, even though there may be multiple levels of unnamed parents inbetween.
$ /root.QWidget/button.QPushButton

As for your example, of two object names being identical, this is something I would consider poor programming effort and I’d entrust programmers to not get themselves in such a situation.

It is only poor programming if your qtpath depends on objectNames being unique and breaks because of that assumption that they should be unique at all times. It is apparently perfectly legal to name two QWidgets the same object name and apply a CSS style to the id. 
 

Thoughts?

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Jun 4, 2014, 2:25:48 AM6/4/14
to python_in...@googlegroups.com

Thanks guys, good thoughts.

I had initially worked with QAbstractItem* classes but found them to be working against me in this particular instance. Of course, this could also mean that I don’t understand it well enough to make it work for me, but I figure at one point or another I’ll have to take a beat, make an assessment and move on. Hard to tell whether or not there was something I missed, maybe I’ll put up another thread with specifics. As a side-note; I have built several UIs with that implementation and overall find it amazingly over-engineered, but that’s another topic altogether.

About MVC; as I originally worked with the QAbstractItem* family, this was unavoidable. But I felt part of what made those classes fail me was partly due to their separation of concerns. Again, I can’t be sure whether I understand it well enough, but from my experiences it wasn’t fit for this purpose. Suffice to say I have considered these alternatives.

QEvents on the other hand. Admittedly, it took me a while to wrap my head around the difference between signals and events in Qt. Events is what I’m using currently in place of signals for things such as this, but not QEvent in particular.

The reason for not using QEvent is that I have objects communicating that lie outside of the graphical domain; i.e. classes not using Qt. What I am looking at however is pypubsub which is a wxPython-inspired implementation of event-handling. It’s different from Qt in that it does introduce globally accessible names (called topics, like with messaging), but I’m too early in to make an educated guess about whether or not it promotes bad design. The idea is to study it, evaluate it, and ultimately port it to ZMQ and unify events across the system.

Finally, on the topic of qtpath, the reason I’m looking to distil paths into strings is so that I can send snapshots about the whereabouts of an item within a hierarchy and from their make use if it and its neighbours. Consider this.

/Win.QWidget/Body.QWidget/John.QWidget

From here, I can browse it’s members, similar to a folder on disk.

John.QWidget
    Name.QLineEdit
    Age.QSpinBox
    Address.QTextEdit

And with that, I can design hierarchies based on how I’d like to organise and access data. Like I would on a file-system.

Let me know what you think.

Best,
Marcus


For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 4, 2014, 3:56:39 AM6/4/14
to python_in...@googlegroups.com
There are examples online about how to get custom QEvents to automatically propagate up the parent hierarchy until someone handles it or it falls off. The same as built in QEvents. 

I'm looking to test this out, but it seems that custom events aren't actually propagated the same as built-in events;
--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 4, 2014, 3:58:00 AM6/4/14
to python_in...@googlegroups.com

Marcus Ottosson

unread,
Jun 4, 2014, 5:21:50 AM6/4/14
to python_in...@googlegroups.com

Ok, so I’ve mocked up an illustration of my requirements in terms of events into three flavours:

I had trouble with QEvent, maybe you guys have any ideas. The root of the problem seems to be that userdefined events are being accepted even though I’m not the one doing the accepting.

pypubsub is clearly the shortest, most concise and de-coupled variant, but then of course this is a minimal example. I suspect the potential issues are the same as those with any messaging workflow, where pypubsub in this case acts as the broker. As I’m dealing with these issues separately anyway, they aren’t as off-putting to me as they would otherwise be.

pyqtSignal, as discussed, is of course really bad and strongly-coupled.

--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 4, 2014, 10:16:01 AM6/4/14
to python_in...@googlegroups.com

Added an MVC example.

I’m storing an ID for each item in the model, similar to how I perceive QAbstractItemModel to be doing. Doing that made me realise that these ID’s (or “indexes“) are in fact absolute paths to the given item. The fact that they are obscured and binary does keep people from using me for anything other than temporary stuff, and the docs warn against doing anything persistent with them.

Do you think the same could be said about qtpaths? What if those ID’s actually looked like Unix-style paths? What would be the disadvantage, would it encourage developers to store them and create them manually? Is that bad?

--
Marcus Ottosson
konstr...@gmail.com

Tony Barbieri

unread,
Jun 4, 2014, 12:18:22 PM6/4/14
to python_in...@googlegroups.com
About MVC; as I originally worked with the QAbstractItem* family, this was unavoidable. But I felt part of what made those classes fail me was partly due to their separation of concerns. Again, I can’t be sure whether I understand it well enough, but from my experiences it wasn’t fit for this purpose. Suffice to say I have considered these alternatives.

The separation of the concerns is the important part and it should help you structure your code to be more modular and flexible.  Fighting against it could lead to necessitating having to manage a complex hierarchy of signals/events.  I've made that mistake a few times and only recently really set out to understand the Qt way of MVC.   Since I've taken the time to really understand it my Qt code has greatly improved and the speed of my tools has as well.

Finally, on the topic of qtpath, the reason I’m looking to distil paths into strings is so that I can send snapshots about the whereabouts of an item within a hierarchy and from their make use if it and its neighbours. Consider this.

This is the part that I feel isn't necessary though.  If structured appropriately, you shouldn't have to worry about where an item is in a hierarchy.  Perhaps I don't fully understand the problem though.

I’m storing an ID for each item in the model, similar to how I perceive QAbstractItemModel to be doing. Doing that made me realise that these ID’s (or “indexes“) are in fact absolute paths to the given item. The fact that they are obscured and binary does keep people from using me for anything other than temporary stuff, and the docs warn against doing anything persistent with them.

QModelIndex instances are meant to be loose pointers to the actual QStandardItem objects.  You should not store them persistently unless you are writing a custom ItemModel or ProxyModel.  Instead you should access them using the QAbstractItemModel methods.  Especially once you get into using proxy models to do more interesting things on the underlying source models themselves.  If the code is structured appropriately, you shouldn't need persistent access to the model indexes, and in fact should never think of the indexes as the actual items themselves.  The items live in their own hierarchy/stack and the indexes are the way you get access to them and their data from a view.

If you need finer grain control of how the item is presented to the user then you can use a QStyledItemDelegate.  There are lots of ways to modify how an item is drawn by using one of those, I've taken it pretty far.  For example I basically took the Maya Outliner view and redid it using QStyledItemDelegate, QStandardItemModel and a QTreeView:

Inline image 1

Selecting each item will fire off signals, etc.  It has search/filtering functionality by using a custom QSortFilterProxyModel subclass and it's really fast.  It can handle a lot of data.  Originally I had written my own QTreeWidget ignoring the built in Qt MVC stuff and doing things much like qtpath would.  It fell flat on it's face once a certain amount of data was thrown at it and it was pretty slow even with minimal data.  The data model driving the tree is from a QStandardItemModel subclass from this library written by Shotgun for the Toolkit framework (plus some pull requests I have pending in that repo):


Another example of using QStyledItemDelegate, QStandardItemModel, QListView (Had to blur out actual names of things, also this is an old WIP version of this tool :)):

Inline image 3

Same deal with this tool and signals.  Using the built in QListView/QStandardItemModel signals in combination with some subclass magic has allowed me to do quite a lot.   In this case I am using a straight up standard QStandardItemModel and populating it with data from Hiero.  It's still pretty flexible and it's fairly trivial to make updates to.

I just wanted to show some examples of what can be done using the stock Qt MVC stuff with some minimal enhancements added through subclassing.  These tools have all been built using PySide, no extra C++.

It would be helpful if you have concrete examples of situations where using the standard Qt functionality has led you to need something like qtpath.  It would help me more clearly understand the problem if I could look through the code examples and see if there are alternatives to how the code is structured that could alleviate this need.  It's hard to look at the theoretical examples and point out where restructuring could help with the issues.  Even if there aren't any code examples, perhaps a specification of a tool where you feel this would be necessary would help.





For more options, visit https://groups.google.com/d/optout.



--
-tony

Marcus Ottosson

unread,
Jun 4, 2014, 2:07:36 PM6/4/14
to python_in...@googlegroups.com
Thanks Tony, that's some great info, I appreciate your help.

I'll try and narrow down my requirements a bit and will be back shortly.

Best,
Marcus



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 4, 2014, 5:30:08 PM6/4/14
to python_in...@googlegroups.com

Top-down, here is roughly what I’m looking for in a final design, functionality-wise.

The navigational style is miller-columns; i.e. columns from left to right, like Finder on OSX. The central difference being that each item can potentially be drawn uniquely, based on metadata associated with what the item represents - which for the sake of argument is folders on disk.

A few priorities:

  • function over looks
  • control over performance
  • quality over quantity

Put another way, I’m not interested in performance nor quantity of items and I’m not getting into looks until I’ve got something that works.

Some specifications; each item is drawn, or not drawn, based on metadata derived from disk; each item potentially unique in shape and content.

# Based on openmetadata
$ /home/marcus/.meta/hidden.bool 
$ /home/marcus/.meta/life.float

With that out of the way, the method I’m currently using is to push/pull into objects from/to disk via a separate i/o module; it works something like this.

In that objects aren’t capable of reaching outside of themselves, in terms of access to network or file-system, but are instead fed (pushed) with data and data is further put (pushed) back out by a separate library.

The reason I’m in this signal-mess to begin with is due to this design. Works well in general coding, not so much embedded into graphics.

Thoughts so far?

Best,
Marcus

Tony Barbieri

unread,
Jun 4, 2014, 6:34:30 PM6/4/14
to python_in...@googlegroups.com
Looks like a neat prototype!

I'm still not sure where the issue is with decoupling these objects from the view.  So this object model needs to notify their visual representation when new data is has been acquired correct?  When one of these items change, their view needs to update itself to account for that change?  I'm still not sure where the necessity for accessing the Widgets comes from, the view could still be driven by the item model it's representing.

The data model could be wrapped up in a QStandardItemModel (or a subclass of QStandardItemModel) which would represent your hierarchy of objects.  You'd most likely also want to subclass QStandardItem so you can add your own data properties based on the data coming in.

This widget could be useful for representing the various properties on your data items although I haven't had to use it yet: http://qt-project.org/doc/qt-4.8/qdatawidgetmapper.html

As far as determining if the item should be in the view or not, a QProxyModel would be great for that.  You basically write you're own filtering method by overriding the filterAcceptsRow method.

I'm not sure if any of the above is useful, but it's probably how I would start to attack the problem vs. referring to static paths to widgets.

  


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Tony

Justin Israel

unread,
Jun 4, 2014, 8:21:44 PM6/4/14
to python_in...@googlegroups.com
On Thu, Jun 5, 2014 at 2:15 AM, Marcus Ottosson <konstr...@gmail.com> wrote:

Added an MVC example.

I’m storing an ID for each item in the model, similar to how I perceive QAbstractItemModel to be doing. Doing that made me realise that these ID’s (or “indexes“) are in fact absolute paths to the given item. The fact that they are obscured and binary does keep people from using me for anything other than temporary stuff, and the docs warn against doing anything persistent with them.

Do you think the same could be said about qtpaths? What if those ID’s actually looked like Unix-style paths? What would be the disadvantage, would it encourage developers to store them and create them manually? Is that bad?

QModelIndex is a reference to a row/column within a model, but you still have to have a reference to the model to access the data through its interface. The indexes are not global application references to get you right to the location, so I wouldn't equate them to the qtpath concept that encodes the full absolute widget hierarchy. They are valid for a point in time by something that is directly interfacing with the view/model interface. 

 

Marcus Ottosson

unread,
Jun 5, 2014, 2:19:56 AM6/5/14
to python_in...@googlegroups.com
Thanks guys.

I've spent quite a while constructing this object model and am a bit reluctant to step back, but I honestly can't find anything off about what you guys are saying, so I will give this a go.

Back in a bit.

Marcus Ottosson

unread,
Jun 5, 2014, 2:21:28 AM6/5/14
to python_in...@googlegroups.com

One thing though

Are you using QAbstractItemModels or the Qt “MVC” framework?

Could you clarify this? Is QAbstractItemModel not part of their MVC framework?

--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 5, 2014, 4:09:49 AM6/5/14
to python_in...@googlegroups.com
Hey guys,

I've decided that the work involved in transitioning to QAbstractItem* is overwhelming and might cause me to miss my deadlines. It's possibly something for a 2.0 (assuming QAbstractItem* it is a better suited solution).

For reference, here are some of the things consuming time.

I couldn't figure out how to get QAbstractItemModel to work without involving QModelIndexes, which is ok. However, QAbstractItemView is also dependent on QModelIndex, which means deriving anything custom would involve adapting QModelIndex here as well, not to mention its separation between selection models and delegates. Overall, it is my impression that the QAbstractItem* family is designed to enable very large data models, which isn't what I'm looking for.

As I've built my views and have a working prototype, I can either get with it or tear it down and start over, which like I said would put my schedule at risk.

Not sure what you guys would do, but to me it seems a perfectionist issue (again, assuming QAbstractItemModel is the perfect candidate)

Thoughts?

Justin Israel

unread,
Jun 5, 2014, 5:54:31 AM6/5/14
to python_in...@googlegroups.com
Hey,

The QAbstractItemModel speaks in terms of QModelIndex as a way to communicate between any implementations of QAbstractItemView, regardless if the view is a single column, a table, a tree, or some other abstract representation. You can't really avoid it as it is part of the interface. But that doesn't really impact your data. The difference between something like QStandardItemModel (or even QTableWidget for that matter) is as you said, performance and control. You can do perfectly fine with a QTableView (or the like) to a certain extend. But there are a few different circumstances I have run into that make the abstract model a better choice:

* You have a ton of data and it becomes to slow to show it in a higher level widget
* You have lots of updates happening in your model/data and the update frequency is slow in performance
* You have a completely custom data source that you want to represent without having to deal with the item-based approach

So when you make an Abstract model subclass, you can store your actual data however you want (or not store it and just source it from where ever) and you are obligated to implement a few methods if it is read only, or a few more if it is a writable model, in order to make it compliant with the qt views that are available. You are just telling it how to resolve back and forth from a QModelIndex, and how to resolve various types of data for different roles. 

I recently just had a view in my app that was originally written quickly with a QStandardItemModel and a QTableView. The process of putting data into the model and updating it meant creating QStandardItem types, and populating it with possibly duplicate data, and putting it in and out of the model. What you don't get with this approach is the granularity of controlling how and when the model notifies the view about updates. You get some, but not as much. So once I had over about 500-600 items in this view, doing the things it did, it became ridiculously slow. Like unusable. Updates on the view would take easily over 5 seconds. I finally got the time and rewrote it using a QAbstractItemModel subclass, where my data was all stored internally and I no longer had to deal with creating many QStandardItems for each cell. My update times went down into 50-150ms when my data was around 750 items (which is actually quite a lot for the particular use and is more of an edge case). But for those people that were using it with that much data it is now useable and really quick. 

The downside is that it is more complicated to use the abstract models. They are prone to getting wrong. I have found that using the PySide port of ModelTest works really well to help validate that you have written the model correctly. If you get some stuff wrong, you end up with funky behavior. 
Anyways, I am still perfectly happy to use the higher level widgets when the data set is reasonable, or the widget is transient. But when I know it has to deal with a ton of data, or data that is changing very frequently, I get more control of updating the abstract model subclass in batches so the view ends up doing a lot less redundant updating and responding. 

-- justin




--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Jun 5, 2014, 7:45:19 AM6/5/14
to python_in...@googlegroups.com
Thanks Justin, that makes sense.

However like I said, I'm not interested in performance, nor do I have that many objects in a view at any point in time. For such things, I would certainly go for QAbstractItem*.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 5, 2014, 9:03:13 AM6/5/14
to python_in...@googlegroups.com
If you could help me understand how using QAbstractItem* and c/o is different from handling widgets manually, in terms of signalling, and without concerning performance, that would help me a lot.

As far as I can tell, as each of my items are composed of multiple widgets there might still be a hierarchy to think of that would somehow have to be signalled up to each individual item in the list. Only then could QAbstractItem* come into play and do it's part. But really, that part isn't what I'm struggling with. It's the multiple levels leading up to that point.

Thoughts?
--
Marcus Ottosson
konstr...@gmail.com

Tony Barbieri

unread,
Jun 5, 2014, 9:04:45 AM6/5/14
to python_in...@googlegroups.com
Are you using QAbstractItemModels or the Qt “MVC” framework?
 
Could you clarify this? Is QAbstractItemModel not part of their MVC framework?

Yes it is part of the MVC framework, sorry about the confusion :).

I couldn't figure out how to get QAbstractItemModel to work without involving QModelIndexes, which is ok.

You won't be able to use QAbstractItemModel without using QModelIndexes.  QModelIndexes are important when working with the Qt MVC objects.

Justin's summary of when/why to use the MVC framework is great.  From what I can tell about the tool you're writing, looking to port it to using the MVC framework in the future may be worth it as it seems like you are using project data which can end up growing quite large.  I had done a similar approach to what you are doing (using the high level widget objects) on some of our project tools in the beginning but once a few projects started up that had higher data requirements (hundreds of entities) it fell flat on it's face and I had to scramble to convert it over to using Qt MVC so we could get usable performance.

I also still use the higher level widget's, but it depends on the tool I'm writing.  Some things are better off using the MVC framework, although the barrier to entry with using it is a lot higher.  Once you wrap your head around a few of the concepts though, it becomes a lot easier to manage.  I recommend looking into it when you have some time, some of your tools may benefit from it.

In the end if you have it working and it meets your requirements, take everything I say with a grain of salt :).



For more options, visit https://groups.google.com/d/optout.



--
Tony

Marcus Ottosson

unread,
Jun 5, 2014, 9:32:42 AM6/5/14
to python_in...@googlegroups.com

Thanks Tony, and I’m sorry for sounding like a broken record here, but performance is of no concern to me. It isn’t that I don’t think performance is less important, but rather that now is not the time. And, again, the number of items in the mock-up I posted above is the mid-range of items ever visible to a user at any point in time, and regular widgets have proven more than capable of handling such low counts.

Yes, it is working, but like I said, it’s difficult to maintain and so I’m looking for alternatives - in design, not necessarily in vendor-specific implementations.

Example time

For the sake of argument, let’s consider the mockup above and have a look at how the first item in the list, “Snake”, expands into another list containing 3 main items; each of which is drawn differently. The top one consists of additional items, each of which is also drawn differently.

For me to click “run” and have that QPushButton signal to me that it is “snake” signalling “run” from his “stats”, say, wouldn’t I have to propagate a signal up through this hierarchy?

/MillerView/Column1/snake/stats/run

*Each of which has a corresponding path on disk.

If “run” were to signal the model directly, what would it tell the model in order to communicate this information?

Best,
Marcus




For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Tony Barbieri

unread,
Jun 5, 2014, 10:29:00 AM6/5/14
to python_in...@googlegroups.com
Hey Marcus,

I understand about the lack of concern for performance.

Off the top of my head, the way I would potentially deal with your scenario is I would have a single hierarchical data model then connect a single signal to the model that's triggered whenever the "run" command is requested.  When the signal is fired I would get the currently selected index and then use the data the index refers to to get the required data that's necessary to react to the run command request.  If you are using a single consistent hierarchical data model you shouldn't have to "bubble" an event all the way up, you'd have a "model object" that abstracts away the details of the internally stored data and allows the "controller" to handle any item type.

Now for the view.  This is going to be confusing, but the first "view column" would consist of the root rows of the data model then each "child view column" would be made up of the child rows of the parent row all the way down until you hit a leaf node.

The view could also use the details of the internal data to decide how it should draw itself and present the data to the user.

Right now it seems as if you are treating each item autonomously rather than considering all of the data as part of a single model which abstracts out the internal details. 

Not sure if that's useful at all...It's potentially how I would deal with it to avoid signal/event hell.




For more options, visit https://groups.google.com/d/optout.



--
Tony

Marcus Ottosson

unread,
Jun 5, 2014, 11:11:36 AM6/5/14
to python_in...@googlegroups.com
The issue is that each item is unique.

Treating all identically is perfect for situations like in your examples, where each item fulfils identical tasks with varying data. Some items have buttons, others have sliders, others 3d views.

The issue relates to traversing a signal from an item with functionality through an object without this functionality. Do you see what I mean? For it to accept and forward the signal, it must know about it, which lies outside of its responsibilities and breaks encapsulation.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Tony Barbieri

unread,
Jun 5, 2014, 11:17:20 AM6/5/14
to python_in...@googlegroups.com
I guess I don't see what you mean...I don't want to sidetrack you though.  If you have a way that is working for you and fulfills all of your requirements then ignore me!





For more options, visit https://groups.google.com/d/optout.



--
Tony

Marcus Ottosson

unread,
Jun 5, 2014, 11:38:20 AM6/5/14
to python_in...@googlegroups.com
Aw. :'( Ok, thanks again for sticking with me this long!

Marcus Ottosson

unread,
Jun 5, 2014, 11:40:21 AM6/5/14
to python_in...@googlegroups.com


On 5 June 2014 16:38, Marcus Ottosson <konstr...@gmail.com> wrote:
Aw. :'( Ok, thanks again for sticking with me this long!



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 5, 2014, 3:40:42 PM6/5/14
to python_in...@googlegroups.com
I've got something that I'd be interested in hearing your thoughts about, maybe you can spot dangers or sense benefits.




In a nutshell, I'm doing what Qt should be doing with my custom events - i.e. propagating them upwards through a custom QWidget called PWidget.

Let me know what you think.

Best,
Marcus
--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 5, 2014, 3:44:02 PM6/5/14
to python_in...@googlegroups.com

Justin Israel

unread,
Jun 5, 2014, 3:44:29 PM6/5/14
to python_in...@googlegroups.com

Yea sorry. Apparently I don't get it either. I was following Tony's reply and it made sense to me but I suppose was not applicable to you? I also saw it as a situation where child items in a model know their own context and their parent item. So when representing the "run" item, it knows the context of it being a "run command for snake within the stats location" because it all shares the same underlying data to know that. The fact that it is a button with a signal is part of the view/delegate aspect. A custom data role could give you back the "context" object that you need for the view or delegate to perform the action in response to the click.
Again,  like Tony, I apologize if this sounds complicated or abstract. It still doesn't click for me that it needs to be a massive signal passing situation. Only so if you are purely working with widgets that are nested and don't know about each others logic as opposed to a model that already knows all the data in one place.
The performance and data aspects of the model aren't just about what is currently visible. It is also about all the data that is know but not visible. Like if you are modeling a filesystem, you may not be in a location viewing a ton of files and directories, but that doesn't mean the model couldn't resolve sibling or child directory listing ahead of time and have extra data available. Or that you could resolve info about parent locations that may not be displaying the data in a view, but have the data available in the model (like the listing of a directory for which you had just browsed through while navigating down).
I can see why in this situation you would need to pass a lot of dynamic signals, when widgets are completely autonomous. If you are sticking with that approach then it might be good to keep trying that customEvent propagation technique that people list online,  and seeing if you can get it to work. Your custom widgets would probably have to have a customEvent method implemented to handle the event if they want. The manual propagation method you found gets around that need by continuing to drive it up the chain until someone handles it. I'm not sure off hand but maybe the customEvent default implementation accepts the event.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Jun 5, 2014, 3:51:44 PM6/5/14
to python_in...@googlegroups.com
Well, the general issue I see with the QAbstractItem* family is its complexity and that it seems better suited for massive datasets, for which I suspect it was designed.

I believe it can be simpler if datasets aren't as large. (less than hundreds of items)

If you have a look at the example I just posted, can you see where such a model would fail and where a QAbstractItem* approach would make it easier to maintain? Even if we disregard the low count in items, and disregard performance, can you see anywhere where this model would stop making sense?

I'm trying hard to KISS, QAbstractItem* isn't simple enough. I really don't think it's as much of a silver bullet as it you're making it out to be.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 5, 2014, 4:54:21 PM6/5/14
to python_in...@googlegroups.com
I wouldn't call it a magic bullet either. They are more complicated to set up for sure. But they do work well in situations where you have multiple views on the same data. I've done the Miller Column thing both using the built in QColumnView, and also setups that use the vertical layout with custom widgets, like you are doing. The QColumnView is pretty much a bunch of list views in a horizontal scroll that have their root item set to different levels of the same model. So multiple views share the same data. In the case of the custom widgets in vertical layouts, when I have done stuff like that, I have usually given the "run" button equivalent the context it needs to use when the click happens. Like giving it a prewrapped callback that it does not have to know about. But you obviously know at the time of its creation that it has a context. 

But ya lets just leave the whole model thing aside because it is a drastic mental shift than what you are already doing. Always something that can be played with later. I can try and take a more focused look at your code example tonight, but it does seem like something could be done with an event filter or customEvents. Ultimately as long as you get some sort of mechanism that pushes events up the chain, you would be good. I wasn't clear on the part where you said you didn't want to overload the event() method since you weren't sure of its logic. But I would think you could still do that and perform save operations, and then call the original event handler at the end. 






Marcus Ottosson

unread,
Jun 5, 2014, 5:49:01 PM6/5/14
to python_in...@googlegroups.com
Thanks Justin. The code example above is using custom events, and I think it should do what I'm looking for, but I won't know for sure until tomorrow once i've integrated it.

As for event filters, don't have much experience with those, but do you think they would allow for the same thing? Without or with custom events?

And finally, multiple views is fancy but are not important in this situation. If that was a requirement, I would definitely go for separating the model.

Ultimately, I believe that my requirements are low, that there is a straightforward solution, and that throwing pre-packaged widgets or QAbstractItem* at the problem is only escalating things.

Looking forward to your thoughts on the example, I find it nimble and complete, more sophisticated than what I've got going on currently and mainly simple and easy to communicate to others with minimal knowledge of Python.

Best,
Marcus


On Thursday, June 5, 2014, Justin Israel <justin...@gmail.com> wrote:
I wouldn't call it a magic bullet either. They are more complicated to set up for sure. But they do work well in situations where you have multiple views on the same data. I've done the Miller Column thing both using the built in QColumnView, and also setups that use the vertical layout with custom widgets, like you are doing. The QColumnView is pretty much a bunch of list views in a horizontal scroll that have their root item set to different levels of the same model. So multiple views share the same data. In the case of the custom widgets in vertical layouts, when I have done stuff like that, I have usually given the "run" button equivalent the context it needs to use when the click happens. Like giving it a prewrapped callback that it does not have to know about. But you obviously know at the time of its creation that it has a context. 

But ya lets just leave the whole model thing aside because it is a drastic mental shift than what you are already doing. Always something that can be played with later. I can try and take a more focused look at your code example tonight, but it does seem like something could be done with an event filter or customEvents. Ultimately as long as you get some sort of mechanism that pushes events up the chain, you would be good. I wasn't clear on the part where you said you didn't want to overload the event() method since you weren't sure of its logic. But I would think you could still do that and perform save operations, and then call the original event handler at the end. 




On Fri, Jun 6, 2014 at 7:51 AM, Marcus Ottosson <konstr...@gmail.com> wrote:
Well, the general issue I see with the QAbstractItem* family is its complexity and that it seems better suited for massive datasets, for which I suspect it was designed.

I believe it can be simpler if datasets aren't as large. (less than hundreds of items)

If you have a look at the example I just posted, can you see where such a model would fail and where a QAbstractItem* approach would make it easier to maintain? Even if we disregard the low count in items, and disregard performance, can you see anywhere where this model would stop making sense?

I'm trying hard to KISS, QAbstractItem* isn't simple enough. I really don't think it's as much of a silver bullet as it you're making it out to be.


On 5 June 2014 20:44, Justin Israel <justin...@gmail.com> wrote:

Yea sorry. Apparently I don't get it either. I was following Tony's reply and it made sense to me but I suppose was not applicable to you? I also saw it as a situation where child items in a model know their own context and their parent item. So when representing the "run" item, it knows the context of it being a "run command for snake within the stats location" because it all shares the same underlying data to know that. The fact that it is a button with a signal is part of the view/delegate aspect. A custom data role could give you back the "context" object that you need for the view or delegate to perform the action in response to the click.
Again,  like Tony, I apologize if this sounds complicated or abstract. It still doesn't click for me that it needs to be a massive signal passing situation. Only so if you are purely working with widgets that are nested and don't know about each others logic as opposed to a model that already knows all the data in one place.
The performance and data aspects of the model aren't just about what is currently visible. It is also about all the data that is know but not visible. Like if you are modeling a filesystem, you may not be in a location viewing a ton of files and directories, but that doesn't mean the model couldn't resolve sibling or child directory listing ahead of time and have extra data available. Or that you could resolve info about parent locations that may not be displaying the data in a view, but have the data available in the model (like the listing of a directory for which you had just browsed through while navigating down).
I can see why in this situation you would need to pass a lot of dynamic signals, when widgets are completely autonomous. If you are sticking with that approach then it might be good to keep trying that customEvent propagation technique that people list online,  and seeing if you can get it to work. Your custom widgets would probably have to have a customEvent method implemented to handle the event if they want. The manual propagation method you found gets around that need by continuing to drive it up the chain until someone handles it. I'm not sure off hand but maybe the customEvent default implementation accepts the event.

On Jun 6, 2014 3:40 AM, "Marcus Ottosson" <konstr...@gmail.com> wrote:


On 5 June 2014 16:38, Marcus Ottosson <konstr...@gmail.com> wrote:
Aw. :'( Ok, thanks again for sticking with me this long!



--
Marcus Ottosson
konstr...@gmail.com

--
You received this message because you are subscribed to the Google Groups "Python Programmi

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--
Marcus Ottosson
konstr...@gmail.com


Justin Israel

unread,
Jun 5, 2014, 6:12:11 PM6/5/14
to python_in...@googlegroups.com

If you are doing Miller columns then that should be equivalent to multiple views of the same data. Presumably you are modeling a path hierarchy and each column is a view onto a different level of the same data model (presumably).  Doesn't really matter but I just thought to mention it.

Event filtering means you can tell one object to receive all events first for a given QObject subclass. It can choose to do something based on the event and/or decide whether the event should continue to reach the original target. That means you could have logic all in one class that chooses to do things for other objects like when the mouse is pressed.

Marcus Ottosson

unread,
Jun 6, 2014, 1:42:40 AM6/6/14
to python_in...@googlegroups.com

If you are doing Miller columns then that should be equivalent to multiple views of the same data. Presumably you are modeling a path hierarchy and each column is a view onto a different level of the same data model (presumably). Doesn’t really matter but I just thought to mention it.

Not sure I’m following you here. Are you saying that:

data = ['item1', 'item2', 'item3']

model = MyModel()
model.setup(data)

view1 = MyView()
view1.setModel(model)

view2 = MyView()
view2.setModel(model)

Is the same as..

data = ['item1', 'item2', 'item3']

model1 = MyModel()
model1.setup(data)

model2 = MyModel()
model2.setup(data)

view1 = MyView()
view1.setModel(model1)

view2 = MyView()
view2.setModel(model2)

..due to both of them using the same set of data? I assumed what you mean with multiple views onto the same set of data involved using the same model, and having them both update according to it, rather than meaning that the file-system is some sort of model.

Event filtering means you can tell one object to receive all events first for a given QObject subclass. It can choose to do something based on the event and/or decide whether the event should continue to reach the original target. That means you could have logic all in one class that chooses to do things for other objects like when the mouse is pressed.

Yes, in my example this is what is happening, but without event filters. My question is, what would event filters do differently?




For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 6, 2014, 3:15:53 AM6/6/14
to python_in...@googlegroups.com


On Jun 6, 2014 5:42 PM, "Marcus Ottosson" <konstr...@gmail.com> wrote:
>>
>> If you are doing Miller columns then that should be equivalent to multiple views of the same data. Presumably you are modeling a path hierarchy and each column is a view onto a different level of the same data model (presumably). Doesn’t really matter but I just thought to mention it.
>

> Not sure I’m following you here. Are you saying that:
>
> data = ['item1', 'item2', 'item3']
>
> model = MyModel()
> model.setup(data)
>
> view1 = MyView()
> view1.setModel(model)
>
> view2 = MyView()
> view2.setModel(model)
>
> Is the same as..
>
> data = ['item1', 'item2', 'item3']
>
> model1 = MyModel()
> model1.setup(data)
>
> model2 = MyModel()
> model2.setup(data)
>
> view1 = MyView()
> view1.setModel(model1)
>
> view2 = MyView()
> view2.setModel(model2)
>
> ..due to both of them using the same set of data? I assumed what you mean with multiple views onto the same set of data involved using the same model, and having them both update according to it, rather than meaning that the file-system is some sort of model.
>>

No those are two different views using two different models. I am talking about the first one, where a single model represents the state of things and different views can root at different levels of it and respond to the same changes in one place.  This would be opposed to loading two models with duplicate data. In a Miller column I figured you were showing the hierarchy of a filesystem or file content meaning it is all the same data source which could use the same model, but with different list views showing different parts of the model

>> Event filtering means you can tell one object to receive all events first for a given QObject subclass. It can choose to do something based on the event and/or decide whether the event should continue to reach the original target. That means you could have logic all in one class that chooses to do things for other objects like when the mouse is pressed.
>
> Yes, in my example this is what is happening, but without event filters. My question is, what would event filters do differently?
>
>

In the event filtering approach you would need a custom subclass to use as a baseclass for all your widgets. You would have one class that can look at an event and decide what to do with the object and then install it as an event handler on any widget that needs it.

> To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmOC4mxs67k6HMYGJ5AOPKORo4C1jDbfofgLFQbcXnFoY2Q%40mail.gmail.com.

Marcus Ottosson

unread,
Jun 6, 2014, 3:47:09 AM6/6/14
to python_in...@googlegroups.com
Ok, before we go any further, I suggest you have a look at my example. I believe what you are suggesting is what has already been done.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 6, 2014, 4:44:53 AM6/6/14
to python_in...@googlegroups.com
I did already look at your example earlier. I just didn't get a chance to run it and examine it in detail. It doesn't really have anything to do with the other side of the discussion with models and what not, so obviously lets completely forget that part.

I wrote a variation for you that is using an event filter approach:

In this version, all of the logic is moved into a "handler" or controller. Whichever you want to call it. But you would install the event filter on the target widgets and it can do whatever centralized logic that you want. Maybe this is of interest or maybe it is completely off from your goal. But either way, I thought it might be nice for the discussion to introduce the example that illustrates the event filter approach. Always an option. 




Justin Israel

unread,
Jun 6, 2014, 4:47:39 AM6/6/14
to python_in...@googlegroups.com
BTW, sorry but I converted your example to PySide since I didn't have Qt5 handy. It was a minimal change. Just some imports and a type convert for the event types. 

Marcus Ottosson

unread,
Jun 6, 2014, 4:52:19 AM6/6/14
to python_in...@googlegroups.com
That looks great, Justin. Thanks for that. I'll play around with this and see if it fits.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 6, 2014, 4:54:20 AM6/6/14
to python_in...@googlegroups.com
One thing, what about widgets in the path leading up to the global handler, what if they want to do something with the event before passing it along?
--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 6, 2014, 5:38:01 AM6/6/14
to python_in...@googlegroups.com
As an example scenario, clicking "run" in one of the columns should trigger an event globally (e.g. running an application), but also highlight the button, highlight the column, and potentially show or hide relevant buttons on the main window related to "run".

--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 6, 2014, 5:42:31 AM6/6/14
to python_in...@googlegroups.com
Ah yea, I suppose my example of using an event filter doesn't really cover the entire case since it doesn't pass things up a chain, but rather allows centralized logic to handle common actions. But this might be a case where you still do have signals, but you don't have to quite rely on all of them being a huge chain of signal passing. Your button can still emit a clicked signal, which its parent can handle, since it knows about all its buttons. Is it possible for you to make use of both in combination, where each fits?
For instance, in this particular example code, the List knows about all its child items and can watch for a clicked button. 


Marcus Ottosson

unread,
Jun 6, 2014, 5:56:07 AM6/6/14
to python_in...@googlegroups.com
Well actually, in the previous example, events are being propagated up the chain and does allow for this. Although I'm not sure I'd refer to it as a huge chain, doesn't Qt do this for all of its events anyway? They are quite a few I suspect.

In this case however, only objects using PWidget are propagating signals so you still end up with control over where events come and from where they propagate.

The eventFilter approach smells a bit like a global object, as you are passing events to the QApplication singleton. Would you use something like this yourself?

I think I've found what I was looking for in terms of solution and requirements with this example, if you can't find any obvious disadvantages then I'm happy to move forwards with this.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 6, 2014, 5:57:21 AM6/6/14
to python_in...@googlegroups.com
Does my use-case make sense at this point though? Do you still feel I'm making it difficult for myself by not using QAbstractItem*?
--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 6, 2014, 6:19:15 AM6/6/14
to python_in...@googlegroups.com

The event filter uses the exact same mechanism that Qt is already using. It puts an event into the event loop. But ya custom events are not propagated,  while built in events are.

Justin Israel

unread,
Jun 6, 2014, 6:21:53 AM6/6/14
to python_in...@googlegroups.com

And I wouldn't say it is a code smell since it is using documented and public mechanisms offered by Qt. The docs outline how to do event filtering and posting events.

Marcus Ottosson

unread,
Jun 6, 2014, 6:31:31 AM6/6/14
to python_in...@googlegroups.com
Ok.

Do you still think I'd be better off with QAbstractItem*?

Justin Israel

unread,
Jun 6, 2014, 6:42:12 AM6/6/14
to python_in...@googlegroups.com

To be perfectly honest,  I don't know.  I'd say keep the course and evaluate your available tools. If your aren't working against the grain and the framework is doing what you need in a clean and easy to reason about manner,  then keep on keepin' on. It's hard to say if one tool is better than the other.  I'm sure you are much better suited to evaluate your options than I as they apply to your application. The best we can do is present the options and our experiences with them.

On Jun 6, 2014 10:31 PM, "Marcus Ottosson" <konstr...@gmail.com> wrote:
Ok.

Do you still think I'd be better off with QAbstractItem*?

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Jun 6, 2014, 6:48:25 AM6/6/14
to python_in...@googlegroups.com
Cool. I only ask because at first it seemed QAbstractItem* was the clear choice, and I wanted to make sure I wasn't missing something about what you guys were suggesting or that you felt I was resisting for no other reason than plain stubbornness.

I'll keep at it and might be back with more. Thanks for your insights so far.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Jun 6, 2014, 8:51:02 AM6/6/14
to python_in...@googlegroups.com
Unrelated to the problem at hand, but related to eventFilter, I did already find a good use for them.

When sizing things via CSS, widgets aren't resized immediately but are delayed towards the point where the widget is about to be shown. So asking a widget for it's size when running the application would yield incorrect results.

The way I dealt with it previously was to run QWidget.ensurePolished(), but that only worked on a per-widget occasion, meaning I'd have to cascade the call to each child widget for accurate results.

Now, instead of calling upon the method querying the sizes directly, I posted an event, picked up in an eventFilter during QEvent.Show and fired a call from there to the method making the queries, and the sizes are correct.

I've been missing out. :)

Thanks for the tip Justin, I've had such a hard time with this particular issue for a long time.

Justin Israel

unread,
Jun 6, 2014, 9:17:34 AM6/6/14
to python_in...@googlegroups.com

Glad it was helpful to solve something! There are so many facets to Qt that it is hard to know them all. I haven't actually sized widgets much through CSS so I will keep that in mind. I use CSS for all the other look related stuff. 

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Jun 6, 2014, 9:45:11 AM6/6/14
to python_in...@googlegroups.com
Yeah, sizing via CSS is great. I use Python for structure only, all look-related things go via CSS, including min, max, fixed sizes. Keeps a clean separation, and resembles HTML with CSS if your familiar with that, and facilitates having multiple themes too!

In fact I was going to put up a new thread about SCSS, to make CSS more manageable and pretty. I recommend having a look.



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 6, 2014, 4:49:01 PM6/6/14
to python_in...@googlegroups.com
Does that mean when wanting to change size constraints dynamically, you have to rewrite and assign new css strings? Like keeping a bunch of template snippets that you recompose? Like if I wanted to adjust the min height constraint on a widget in response to certain situation. 


Marcus Ottosson

unread,
Jun 7, 2014, 5:36:51 AM6/7/14
to python_in...@googlegroups.com

Like keeping a bunch of template snippets that you recompose?

Not sure if you’re speaking from experience or just winging it, but this sounds like a really good idea.

I was going to say that no, css and dynamic properties don’t mix. Anything that has to change at run-time, I change via Python and in some cases by re-setting stylesheets via in-line css on particular widgets; generally avoiding re-setting stylesheets on the entire application due to performance concerns. Having “css snippets” sounds really powerful and aligns well with another methodology I use. I’m mocking up a new thread on CSS as we speak, let’s continue our discussions in there.




For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jun 7, 2014, 6:07:00 AM6/7/14
to python_in...@googlegroups.com

I will save my reply for that thread. Looking forward to it. Welcoming the chance to improve the CSS + Qt workflow

Marcus Ottosson

unread,
Jun 13, 2014, 10:11:10 AM6/13/14
to python_in...@googlegroups.com
An update on this, heading over to using MVC as opposed to dancing around with deep object hierarchies solved the main issue giving birth to QtPath. The other issue was solved by QEvent and it's glory.

Thanks guys for your input, my code is sparkly clean now. :)

QtPath is a now solution looking for a problem, so if you can think of any, let me know. :)



For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Marcus Ottosson

unread,
Mar 15, 2015, 8:02:44 AM3/15/15
to python_in...@googlegroups.com

8 months later, and I stumble across this.

import shiboken
from maya import OpenMayaUI as omui

channel_box_ptr = omui.MQtUtil.findControl("mainChannelBox")
print omui.MQtUtil.fullName(long(channel_box_ptr))
# MayaWindow|MainChannelsLayersLayout|ChannelsLayersPaneLayout|ChannelBoxForm|menuBarLayout1|frameLayout1|mainChannelBox

​- http://download.autodesk.com/us/maya/2011help/API/class_m_qt_util.html#099521e61229f53ee417087e2795ddf1

Got a little deja-vu there.

It’s possibly implemented for backwards compatibility and not really solving a real problem, as we established earlier in this thread. Just thought I’d share in case someone was thinking of heading down the same qt path. (pun!)

Pacifique Nzitonda

unread,
Sep 23, 2022, 5:37:48 AM9/23/22
to Python Programming for Autodesk Maya
Hi, I have a question about PySide2 undo/redo in Maya. I read a discussion here in group about using  undoInfo command but what if my GUI has to interact with many methods?  How can I create an undo/redo for all of them at once?

On Tuesday, June 3, 2014 at 4:19:02 PM UTC+2 Marcus Ottosson wrote:

Hi all,

I’ve mocked up a method for serialising paths of widgets within a hierarchy of widgets into a Unix-style path, that can then be de-serialised back into its original widget.

Motivation is to be able to reference widgets within deeply nested hierarchies, both for better understanding and debugging but also for undo/redo and messaging.

I’m calling it qtpath for the lack of a better name. Before I make a big deal out of it, I wanted to reach out to you guys in case you’ve encountered anything similar, have ever found the need or can think of alternative methods of achieving the same goal.

https://github.com/abstractfactory/labs/tree/master/python/pyqt/qtpath

>> qtpath.abspath(window, button)
'/Win.Demo/Body.QWidget/Button.QPushButton'

Let me know what you think.

Best,
Marcus

--
Marcus Ottosson
konstr...@gmail.com

Reply all
Reply to author
Forward
0 new messages