Grab text of the selection in QMenu

342 views
Skip to first unread message

likage

unread,
Sep 30, 2014, 2:57:07 AM9/30/14
to python_in...@googlegroups.com
I am trying to get the selection that was listed in the qMenu and based on the user selection from the qMenu - camSelBtn, it will display the selection into a qLineEdit - currentCamTxt

However while I am able to get the menu working, the  grabbing of text of the selection is not working.


def camMenu(self):
    allCams
= cmds.ls(type='camera', visible = 1)
    camLs
= cmds.listRelatives(allCams, p=1)
    menu
= QMenu("menu", self.camSelBtn)
   
for n in camLs:
        menu
.addAction(QAction(n, menu))
   
self.camSelBtn.setMenu(menu)

def createConnections(self):
   
self.connect(self.setCameraBtn, SIGNAL('clicked()'), self.setCamera)

def setCamera(self):
   
for sel in self.camMenu.menu():
       
self.currentCamTxt.setText()



Justin Israel

unread,
Sep 30, 2014, 3:58:48 AM9/30/14
to python_in...@googlegroups.com
Hey there,

You want to get the camera that was selected from the QMenu? Then instead of connecting to the button click, you probably want to watch the signals on the actual QMenu, which will tell you exactly which action was selected. Here is a simplified version:
def camMenu(self):
    allCams = cmds.ls(type='camera', visible = 1)
    camLs = cmds.listRelatives(allCams, p=1)
    menu = QMenu("menu", self.camSelBtn)
    for n in
 camLs:
        menu.addAction(n)
    self.camSelBtn.setMenu(menu)
    menu.triggered.connect(self._camSelected)

def _camSelected(self, action):
    self.currentCamTxt.setText(action.text())



--
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/2c9cdcc9-9263-4b8b-a7ce-47fbe9004cff%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

likage

unread,
Sep 30, 2014, 4:20:54 AM9/30/14
to python_in...@googlegroups.com
Hey,

This is totally cool! Gets my stuff working!!

Just curious though, why couldn't I use connecting/connections, basically in a similar fashion that I did in my code? Thought it may be a good thing to standardized my code style?
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Sep 30, 2014, 4:31:56 AM9/30/14
to python_in...@googlegroups.com
There actually isn't anything wrong if you want to do that approach. It is just a stylistic thing I do, where I tend to keep the connections within the same block of code where the widgets are created, usually at the bottom, just for the association. I only did it here to write shorter code. 

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/9b8acefa-41f6-4895-bb37-1b3ad8a39dae%40googlegroups.com.

likage

unread,
Sep 30, 2014, 5:10:01 AM9/30/14
to python_in...@googlegroups.com
okay..

Just one more question then, rather than me spamming another thread again. Is it possible for have the QMenu to be 'live-updated'?

The reason I asked this was because, example, when I run the code the first time, there is only 1 camera, and while the UI is still not closed, I created  another camera but as I click on the setCameraBtn, instead of getting 2 cameras, I am still getting back the same camera.

Justin Israel

unread,
Sep 30, 2014, 5:55:31 AM9/30/14
to python_in...@googlegroups.com

You have complete freedom to clear the menu or add more items at any time, but there is no live binding between the number of cameras in the scene and the menu. You would need to update the menu instance based on some action or trigger

--
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,
Oct 2, 2014, 11:21:22 PM10/2/14
to python_in...@googlegroups.com
Hi Justin, thank you for the reply.
Based on what you have mentioned, can I actually placed the updating within the camMenu function? Or should I re-define it as another function?

Justin Israel

unread,
Oct 3, 2014, 1:34:42 AM10/3/14
to python_in...@googlegroups.com

You have a couple ways to go about it. Either your camMenu function gets called whenever you need to trigger an update, and it will replace the button menu with a new one. Or it can edit the same menu over and over. Or, you can create the menu once and connect it's aboutToShow signal to a function that will update it.

I actually would prefer the last one. You can just clear and repopulate the menu each time they click it, which means that you don't need to keep  the menu updated at any other time.

On 3/10/2014 4:21 PM, "likage" <dissid...@gmail.com> wrote:
Hi Justin, thank you for the reply.
Based on what you have mentioned, can I actually placed the updating within the camMenu function? Or should I re-define it as another function?

--
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,
Oct 7, 2014, 6:14:30 AM10/7/14
to python_in...@googlegroups.com
I think I may have done it wrong or what as the signal 'aboutToShow' does not seems to be generating any sorts of effects... Likewise if I tried to set the setCameraBtn to have a 'clicked' signal

But if I were to incorporate the following into my createConnections, the menu did managed to get updated but there is a laggy-ness in it, where I will need to press the button twice before I am getting the correct list of cameras.
self.connect(self.setCameraBtn, SIGNAL("pressed()"), self.camMenu)




On Friday, October 3, 2014 1:34:42 PM UTC+8, Justin Israel wrote:

You have a couple ways to go about it. Either your camMenu function gets called whenever you need to trigger an update, and it will replace the button menu with a new one. Or it can edit the same menu over and over. Or, you can create the menu once and connect it's aboutToShow signal to a function that will update it.

I actually would prefer the last one. You can just clear and repopulate the menu each time they click it, which means that you don't need to keep  the menu updated at any other time.

On 3/10/2014 4:21 PM, "likage" <dissid...@gmail.com> wrote:
Hi Justin, thank you for the reply.
Based on what you have mentioned, can I actually placed the updating within the camMenu function? Or should I re-define it as another function?

--
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_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Oct 7, 2014, 3:53:32 PM10/7/14
to python_in...@googlegroups.com
I'm not sure why the aboutToShow signal didn't work for you. It works just fine for me:
        ...
        menu = QtGui.QMenu(self)
        self.setMenu(menu)
        menu.aboutToShow.connect(self._updateMenu)

    def _updateMenu(self):
        menu = self.menu()
        menu.clear()
        allCams = cmds.ls(type='camera', visible=True)
        if not allCams:
            return
        camLs = cmds.listRelatives(allCams, p=True)
        for item in camLs:
            menu.addAction(item)

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/18628e12-5447-49a3-80ae-8fcf9383d730%40googlegroups.com.

likage

unread,
Oct 7, 2014, 10:29:12 PM10/7/14
to python_in...@googlegroups.com
It is not working for me initially.
I think I am still screwing up somewhere... Is this correct for me to do it in this way?

camLs = []

class orientCameraUI(QDialog):
   
def __init__(self, parent=None):
       
super(orientCameraUI, self).__init__(parent)
       
self.setMinimumWidth(300)
       
self.setMaximumHeight(80)
       
self.initUI()
       
self.camMenu()
       
self.createConnections()
       
   
def initUI(self):
       
...
   
   
def createConnections(self):
       
self.connect(self.setCameraBtn, SIGNAL('aboutToShow()'), self._updateMenu)
   
   
def camMenu(self):
        allCams
= [c for c in cmds.listRelatives(cmds.ls(cameras=1),parent=1) if not cmds.camera(c, q=True, startupCamera=True)]
       
        camLs
.extend(allCams)
       
        menu
= QMenu("menu", self.setCameraBtn)
       
       
for item in camLs:
            menu
.addAction(QAction(item, menu))
       
self.setCameraBtn.setMenu(menu)
       
        menu
.aboutToShow.connect(self._updateMenu)

        menu
.triggered.connect(self._camSelected)
       
   
def _camSelected(self, action):
       
self.currentCamTxt.setText(action.text())

       
   
def _updateMenu(self):
        menu
= QMenu("menu", self.setCameraBtn)
        menu
.clear()
       
        allCams
= [c for c in cmds.listRelatives(cmds.ls(cameras=1),parent=1) if not cmds.camera(c, q=True, startupCamera=True)]
       
if not allCams:
           
return
       
       
del camLs[:]
        camLs
.extend(allCams)

Justin Israel

unread,
Oct 7, 2014, 11:00:44 PM10/7/14
to python_in...@googlegroups.com
Yea there are a few problems in your code, so I can see why it wasn't working correctly.
Here is a modified version:
## No globals
# camLs = []


class orientCameraUI(QDialog):
    def __init__(self, parent=None):

        super(orientCameraUI, self).__init__(parent)

        # You have a class, so you should store state in the class
        self.__camLs = []

        self.setMinimumWidth(300)
        self.setMaximumHeight(80)
        self._initUI()
        self._camMenu()
        # self.createConnections()

    def _initUI(self):
        ...

    ## Get rid of this. The QPushButton doesn't have aboutToShow()    
    # def createConnections(self):
    #     self.connect(self.setCameraBtn, SIGNAL('aboutToShow()'), self._updateMenu)

    def _camMenu(self):
        menu = QMenu("menu", self.setCameraBtn)
        self.setCameraBtn.setMenu(menu)
        menu.aboutToShow.connect(self._updateMenu)
        menu.triggered.connect(self._camSelected)

    
def _camSelected(self, action):
        self.currentCamTxt.setText(action.text())

    def _updateMenu(self):

        ## You were creating a brand new menu and clearing it
        ## each time, instead of clearing the one already set
        ## on the QPushButton. So nothing was really changing.
        # menu = QMenu("menu", self.setCameraBtn)
        menu = self.setCameraBtn.menu()

        menu.clear()

        cams = cmds.listRelatives(cmds.ls(cameras=True), parent=True)
        if not cams:
            return

        allCams = [c for c in cams if not cmds.camera(c, q=True, startupCamera=True)]
        self.__camLs = allCams

        if not allCams:
            return


        for item in camLs:
            menu.addAction(item)
Some points about it:
  • Get rid of the global list. You can just use an instance attribute if you want to separately track the camera names
  • You were duplicating code and only updating a new temporary QMenu that you are actually leaking on every update. You never actually updated the menu set on the button
  • Just set up the empty menu once in your init. Then your aboutToShow() can rebuild that menu every single time.



--
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,
Oct 7, 2014, 11:32:43 PM10/7/14
to python_in...@googlegroups.com
I see and I do not think there is a need for me to define an instance attribute - self.__camLs seeing that I am not really using it anywhere...

By the way, may I ask if menu = QMenu("menu", self.setCameraBtn) is not equivalent to menu = self.setCameraBtn.menu()? Can I take it that the latter one creates a new menu while the former is attaching the QMenu onto the setCameraBtn?

Justin Israel

unread,
Oct 8, 2014, 1:19:23 AM10/8/14
to python_in...@googlegroups.com
They are not the same, and also not doing what you said...

menu = QMenu("menu", self.setCameraBtn)

This creates a brand new QMenu, with the setCameraBtn as its parent, and then simply leaks it (the object remains for the life of the application, but is never used). It is never set as the actual menu on the button. Nothing changes.

self.setCameraBtn.menu()

This method retrieves the currently set QMenu on the button. It does not create new menus when you call it.

If you want to actually set the menu on the button, use setMenu()



On Wed, Oct 8, 2014 at 4:32 PM, likage <dissid...@gmail.com> wrote:
I see and I do not think there is a need for me to define an instance attribute - self.__camLs seeing that I am not really using it anywhere...

By the way, may I ask if menu = QMenu("menu", self.setCameraBtn) is not equivalent to menu = self.setCameraBtn.menu()? Can I take it that the latter one creates a new menu while the former is attaching the QMenu onto the setCameraBtn?

--
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.
Reply all
Reply to author
Forward
0 new messages