(Real) Time update/ actions between Gui and Maya

73 views
Skip to first unread message

likage

unread,
Jul 3, 2019, 2:00:39 PM7/3/19
to Python Programming for Autodesk Maya
Hi everyone, I am trying to make a real-time update, eg. a renaming between maya scene and my tool. Previously I made a thread about it, but seeing that it is a bit confusing, I have decided to make a new thread and repost it with coding on what I am trying to achieve.

Currently I am able to effect changes from my tool and modify the naming in the scene. But in the event if I perform an undo in the maya scene itself, the undo changes are not effected back into the tool.

Here is my code:

class Example(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Example, self).__init__()
        self.initUI()
        self.setup_connections()

    def initUI(self):         
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Rename')

        self.list_widget = QtGui.QListWidget()
        self.add_loc_btn = QtGui.QPushButton("Add new Locator")

        vlayout = QtGui.QVBoxLayout()
        vlayout.addWidget(self.list_widget)
        vlayout.addWidget(self.add_loc_btn)
        vlayout.addStretch(1)
        self.setLayout(vlayout)

    def setup_connections(self):
        self.add_loc_btn.clicked.connect(self.add_locator)
        self.list_widget.itemDoubleClicked.connect(self.list_item_dbl_click)
        self.list_widget.itemChanged.connect(self.list_item_click)

    def add_locator(self):
        new_loc = cmds.spaceLocator()
        loc_fp = cmds.ls(new_loc[0], long=True)
        loc_item = QtGui.QListWidgetItem(str(new_loc[0]))
        loc_item.setData(32, loc_fp[0])
        loc_item.setFlags(
            loc_item.flags() |
            QtCore.Qt.ItemIsUserCheckable |
            QtCore.Qt.ItemIsEditable
        )
        self.list_widget.addItem(loc_item)

    def list_item_dbl_click(self):
        current_item = self.list_widget.currentItem()
        self.prev_name = current_item.text()
        self.rename_counter = 1

    def list_item_click(self, test):
        success = False
        current_item = self.list_widget.currentItem()
        list_item_row = self.list_widget.currentRow()
        new_name = current_item.text()

        if self.validate_naming(new_name):
            locator = current_item.data(32)
            if cmds.objExists(locator) and self.rename_counter == 1:
                cmds.select(locator)
                cmds.rename(new_name)

                # reset counter back to 0
                self.rename_counter = 0
                success = True

        else:
            # Set back to its initial naming before rename
            current_item.setText(self.prev_name)

        if success:
            list_item = self.list_widget.item(list_item_row)
            self.list_widget.setCurrentItem(list_item)

    def validate_naming(self, name_input):
        if re.search("^\s*[0-9]", name_input):
            LOG.warning("Input naming cannot be started off with numbers!")
            return False
        return True


myWin = Example()
myWin.show()

Here are some steps to reproduce:
  • Click on the ‘Add new Locator’ button
  • It will creates a locator1 in the scene and populated in the list widget
  • Double click on the locator1 in the list widget and input in a new name. Eg. ‘myLocator’
  • Go back to Maya and tried pressing ‘Ctrl+Z’ (undo)
  • While it does changes the name ‘myLocator’ back to ‘locator1’ in Maya context, I would also like it to be ‘updated’ in my Gui.
How should I go about doing this?
P.S: I was also trying to find a way to peform undoing in the Gui which will also in turns effects the changes in the Maya scene if possible.

Justin Israel

unread,
Jul 3, 2019, 5:20:17 PM7/3/19
to python_in...@googlegroups.com
Have you tried using a MEventMessage or a scriptJob to listen for the "Undo" Maya events and then performing the undo in your own GUI?

--
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/63af8ecf-5d67-4004-a076-34fc68019d9f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

likage

unread,
Jul 3, 2019, 6:17:57 PM7/3/19
to Python Programming for Autodesk Maya
Hi, I have not. I was not aware of the above 2 you have mentioned. This may sounds very noobish of me - but how do I use them?

Additionally, I could be wrong on this but while I was googling around, trying to find a way, I chanced upon Model View Controller (something that I was not aware of too).
It seems that this case of MVC may or may not be applicable in my cause, but what is the best scenario to use MVC then?

Justin Israel

unread,
Jul 3, 2019, 6:37:42 PM7/3/19
to python_in...@googlegroups.com
On Thu, Jul 4, 2019 at 10:18 AM likage <dissid...@gmail.com> wrote:
Hi, I have not. I was not aware of the above 2 you have mentioned. This may sounds very noobish of me - but how do I use them?

You could likely search the mailing list for the previous conversations on MEventMessage / MMessage / scriptJob

With  MEventMessage   , that is the Maya API, where you register a callback against a named event,
scriptJob is commands a wrapper around the API that does a similar thing, giving you back an id that can be used to unregistered your callback later.


Additionally, I could be wrong on this but while I was googling around, trying to find a way, I chanced upon Model View Controller (something that I was not aware of too).
It seems that this case of MVC may or may not be applicable in my cause, but what is the best scenario to use MVC then?

That is a pretty general term for structuring an application that may or may not apply to your own project, but may not have specific relevance to your current problem. It deals with encapsulating the source of your data, the presentation layer, and the business logic that glues together the data model and the views. It leads to the effect of having many different types of views onto the same data, and a business logic layer that is not tied to the dependencies of your UI. 
Your current problem is in wiring together 2 different 'applications'. While your UI is running within Maya, it is not Maya itself and Maya is only hosting it. You could consider Maya your data model and then use MMessages/scriptJobs as your business logic to connect and drive your views. 
 

--
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.
Message has been deleted

Justin Israel

unread,
Jul 4, 2019, 5:56:19 PM7/4/19
to python_in...@googlegroups.com


On Fri, Jul 5, 2019 at 6:21 AM likage <dissid...@gmail.com> wrote:
Got it, thanks!

Is there a way in which I can also use script job to detects when my custom tool is closed?
I am using `MayaQWidgetDockableMixin` in which the `closeEvent` is not calling (`dockCloseEventTriggered` does gets called and executed if the tool is docked) and it is not removing the scriptjobs that I have created..

MayaQWidgetDockableMixin isn't exactly the same as using a normal QDockWidget set with your own widget. This custom maya mixin does its own configuration and wiring of signals. If you run help(MayaQWidgetDockableMixin) in your Script Editor you will see the functionality that it provides. You will find that it gives you a hook for when the dock widget is closed. Note though that closing the widget doesn't neccessarily mean it was deleted. It is likely just hidden unless you choose to delete on close.
So you can use something like this:

  1. from PySide import QtCore, QtGui
  2. from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
  3.  
  4. # help(MayaQWidgetDockableMixin)
  5.  
  6. class DockWidget(MayaQWidgetDockableMixin, QtGui.QDialog):
  7.  
  8. def __init__(self, parent=None):
  9. super(DockWidget, self).__init__(parent=parent)
  10. self.resize(400,400)
  11. self._has_init = False
  12.  
  13. def dockCloseEventTriggered(self):
  14. print "dockClose"
  15. self._has_init = False
  16.  
  17. def showEvent(self, e):
  18. print "show"
  19. if not self._has_init:
  20. print " do setup stuff"
  21. self._has_init = False
  22. super(DockWidget, self).showEvent(e)
 
This gives you a hook into when the dock is closed and when it is shown, tracking when it has actually been shown for the first time again rather than how the show event is going to be triggered constantly when you re-dock the widget around Maya.

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.

Michael Boon

unread,
Jul 4, 2019, 6:03:06 PM7/4/19
to Python Programming for Autodesk Maya
Hey Justin, I'm guessing you meant to set self._has_init = True in showEvent()

On Friday, 5 July 2019 07:56:19 UTC+10, Justin Israel wrote:


To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Jul 4, 2019, 6:22:31 PM7/4/19
to python_in...@googlegroups.com
On Fri, Jul 5, 2019 at 10:03 AM Michael Boon <boon...@gmail.com> wrote:
Hey Justin, I'm guessing you meant to set self._has_init = True in showEvent()

Ah yep. Typo since I was transferring it from an internal network to an external :-) thanks
 
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
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/9cfa56fb-e524-4bb7-a667-0ab6a3430eb5%40googlegroups.com.

likage

unread,
Jul 5, 2019, 6:14:50 PM7/5/19
to Python Programming for Autodesk Maya
Thank you Justin. Will try out your method.
I have 2 questions here:

1. For the approach I have adopted - 'using scriptJob to track tool closure' , is that still applicable/advisable?

2. And one more question - For the `undo` that I have implemented, eg. perform an un-renaming process, I noticed that it takes me to press the 'undo' combination 7 times just to get the name of the node back to its initial naming, instead of the 1 time that I am expecting....

Any insights on this?

Justin Israel

unread,
Jul 5, 2019, 6:52:14 PM7/5/19
to python_in...@googlegroups.com


On Sat, Jul 6, 2019, 10:14 AM likage <dissid...@gmail.com> wrote:
Thank you Justin. Will try out your method.
I have 2 questions here:

1. For the approach I have adopted - 'using scriptJob to track tool closure' , is that still applicable/advisable?

If it works, it works. Generally when it's your own UI you have a more direct way of knowing it was closed than Maya telling you a UI element was closed. 


2. And one more question - For the `undo` that I have implemented, eg. perform an un-renaming process, I noticed that it takes me to press the 'undo' combination 7 times just to get the name of the node back to its initial naming, instead of the 1 time that I am expecting....

Any insights on this?

Could be that the operation that did the rename wasn't wrapped in an Undo group which would flatten all the operations into one undo step. 

--
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.

likage

unread,
Jul 5, 2019, 8:26:05 PM7/5/19
to Python Programming for Autodesk Maya
Could you kindly elaborate more on `rename wasn't wrapped in an Undo group`? I am not quite understanding here...
I did not create any 'groups' (cmds.undoInfo) if you are referring to that...

And unfortunately, there seems to be another issue where - when trying to select any keys in the Graph Editor (it did a super quick select and unselect action), seemingly caused by the scriptjobs I have created...

Justin Israel

unread,
Jul 5, 2019, 9:21:28 PM7/5/19
to python_in...@googlegroups.com


On Sat, Jul 6, 2019, 12:26 PM likage <dissid...@gmail.com> wrote:
Could you kindly elaborate more on `rename wasn't wrapped in an Undo group`? I am not quite understanding here...
I did not create any 'groups' (cmds.undoInfo) if you are referring to that...

Yes that is what I meant (or through the API as well) 

If you open an undo chunk, do operations, and close the chunk, it would get compressed into one undo action. 


And unfortunately, there seems to be another issue where - when trying to select any keys in the Graph Editor (it did a super quick select and unselect action), seemingly caused by the scriptjobs I have created...

Well. Be careful what events you wire up with :-) Maybe your UI will need to not act on the events if it does not have active focus. 

--
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.

likage

unread,
Jul 5, 2019, 9:21:54 PM7/5/19
to Python Programming for Autodesk Maya
Thought I placed my files here as I could not really figure out the undo or the graph editor selection...


Appreciate in advance if anyone could shed any lights on it.

Justin Israel

unread,
Jul 5, 2019, 9:33:52 PM7/5/19
to python_in...@googlegroups.com


On Sat, Jul 6, 2019, 1:21 PM likage <dissid...@gmail.com> wrote:
Thought I placed my files here as I could not really figure out the undo or the graph editor selection...


Your scriptJob that tracks selection changes ends up calling your plane_selected() function which contains a call to cmds.select() 
You have alot logic running on every selection change so you just need to be aware of whether you want to respond or not. Seems to me like a callback that responds to a selection should not go and make another selection call? 

One other point. I recommend not using a global variable to store the script job ids for any instance of your UI. It means multiple instances of a UI would share a list. You already have a class instance which can store a list so just track them in self._scriptJobs = [] 



Appreciate in advance if anyone could shed any lights on it.

--
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.

likage

unread,
Jul 8, 2019, 1:49:00 PM7/8/19
to Python Programming for Autodesk Maya
Hi Justin, thank you for getting back.

As for the DockWidget() class method you have provided, sadly it does not seems to be working for me. Getting the same issue (signal not getting called) as soon as `self.ui.setupUi(self)` is implemented.
-----

I tried using the following in my main.py for the `cmds.undoInfo` as follows:

def create_custom_script_jobs(self):
   
...
   
cmds.undoInfo(chunkName='MyTool_chunkName', openChunk=True)

def remove_custom_script_jobs(self):
    ...
    cmds.undoInfo(chunkName='MyTool_chunkName', closeChunk=True)


It seems that I am the undo actions are not getting compress into 1 action... Am I doing it wrong?
Also tried implementing the above code in my execution code, not seeing any diff...

-----
Noted on the global usage for script jobs tracking.

As for the selections, I made it that way because, I need to achieve 2 things.
1. Whatever that is selected in the Maya context (image planes in this case), if found in the tool context, selects the said item in the tool (which is under QListWidget).
2. Selection made in the tool context - QListWidget (again, only the image plane selection), will be selected in the Maya context if found.

Basically a bi-directional selection between my tool and Maya. As you have suggested, upon the removal of the `cmds.select` in the `plane_selected()` seems to have did the trick in the key selection in Graph Editor! Thank you.

Justin Israel

unread,
Jul 8, 2019, 3:48:58 PM7/8/19
to python_in...@googlegroups.com


On Tue, Jul 9, 2019, 5:49 AM likage <dissid...@gmail.com> wrote:
Hi Justin, thank you for getting back.

As for the DockWidget() class method you have provided, sadly it does not seems to be working for me. Getting the same issue (signal not getting called) as soon as `self.ui.setupUi(self)` is implemented.


-----

I tried using the following in my main.py for the `cmds.undoInfo` as follows:

def create_custom_script_jobs(self):
   
...
   
cmds.undoInfo(chunkName='MyTool_chunkName', openChunk=True)

def remove_custom_script_jobs(self):
    ...
    cmds.undoInfo(chunkName='MyTool_chunkName', closeChunk=True)


It seems that I am the undo actions are not getting compress into 1 action... Am I doing it wrong?
Also tried implementing the above code in my execution code, not seeing any diff...

Using it this way will break your entire Maya undo functionality. You only want to open a chunk right before you execute a series of Maya commands and then make sure to always close the chunk again even if your actions raise an exception. You wouldn't want to open it and close it and two unrelated points in time. 


-----
Noted on the global usage for script jobs tracking.

As for the selections, I made it that way because, I need to achieve 2 things.
1. Whatever that is selected in the Maya context (image planes in this case), if found in the tool context, selects the said item in the tool (which is under QListWidget).
2. Selection made in the tool context - QListWidget (again, only the image plane selection), will be selected in the Maya context if found.

Basically a bi-directional selection between my tool and Maya. As you have suggested, upon the removal of the `cmds.select` in the `plane_selected()` seems to have did the trick in the key selection in Graph Editor! Thank you.

--
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.

likage

unread,
Jul 8, 2019, 5:12:47 PM7/8/19
to Python Programming for Autodesk Maya
I tried to move the `cmds.undoInfo` into list_item_click() method where the chunk will be opened and closed upon the renaming (after the self.validate_naming) and before I perform any undo, I tried to print out the list of undo in the queue, in which it returns me as follows:

cmds.undoInfo(query=True, printQueue=True)

# Returns the following result:
...
# 39:  # 
# 40:  # 
# 41:  # 
# 42:  # 
# 43: MyTool_chunkName # 
# 44:  # 
# 45:  # 
# 46:  # 
# 47:  # 
# 48:  # 
# 49:  # 

At the very least I had thought I would be able to capture this process as 1 action. Is there a way to remove all these 'empty' undo actions?

likage

unread,
Jul 10, 2019, 4:00:55 PM7/10/19
to Python Programming for Autodesk Maya
I manged to get this figured out. Thank you all for the help :)
Reply all
Reply to author
Forward
0 new messages