How to set StatusBar() message when hover mouse over some widget ?

1,687 views
Skip to first unread message

san

unread,
Dec 7, 2012, 9:25:02 AM12/7/12
to python_in...@googlegroups.com
as a part of my learning PyQt4 I started making a gui(see attachment) where I implement all the examples I learn from video tuts or book I am referring,

however I count figure out how should I implement the method to show text message on the status bar when user hover mouse over a widget[link to pastebin ]

and secondly I dont understand how come this method to select Directory is not working?

    def showDirDialog(self):
        directory=os.path.expanduser('~')
        dirPath=QtGui.QFileDialog(self,"Select Render Directory",directory)
        dirPath.setFileMode(QtGui.QFileDialog.DirectoryOnly)

Kurian O.S

unread,
Dec 7, 2012, 12:56:46 PM12/7/12
to python_in...@googlegroups.com
For Directory you want to use exec so you need to change your code like this

    def showDirDialog(self):
        directory=os.path.expanduser('~')
        dirPath=QtGui.QFileDialog(self,"Select Render Directory",directory)
        dirPath.setFileMode(QtGui.QFileDialog.DirectoryOnly)
        if dirPath.exec_() == 1:
            fname_list = str(dirPath.selectedFiles()[0])
            print fname_list

For changing the statusBar text you need to implement focusIn and out Event and Justin already mention about that in reimplement QPlainText’s focusInEvent in another source file ,how to ? thread.





--
--:: Kurian ::--

Justin Israel

unread,
Dec 7, 2012, 2:00:38 PM12/7/12
to python_in...@googlegroups.com
If you are using your own custom status bar in a widget, then you have to connect focus or hover events to something that sets the message on the status bar. You can set the setStatusTip("") on each widget and then just read that.

When you use a QMainWindow, the status bar is already wired up for you so that any time you hover a widget, the statusBar will automatically read the widgets statusTip():

app = QtGui.QApplication([])

w = QtGui.QMainWindow()
button = QtGui.QPushButton("clicky", w)
button.setStatusTip("I am a clicky")
w.setCentralWidget(button)

status = w.statusBar()

w.show()
w.raise_()

status.showMessage("Welcome to the app!", 5000)

app.exec_()

For the file dialog, the way you are using it, there is a convenience static method you can call:

It will return an empty string if they cancel:

directory=os.path.expanduser('~')
selectedDir = QtGui.QFileDialog.getExistingDirectory(w, 
                "Select Render Directory", directory)

if selectedDir.isEmpty():
    print "No directory selected"
else:
    print selectedDir

šãñ

unread,
Dec 7, 2012, 4:10:08 PM12/7/12
to python_in...@googlegroups.com

thank you guys for pointing a solution but Now I really have a bunch of more questions these are pretty basic that i know ...

my first question is how do I keep the gridColumWidth fixed so that it should not change if the label text changes(see attached image)

my second question is how can i use a showFileDialog slot fill QLineEdit for scne file for selecting directory and similarly in second tab ..(as you can see in the attached screenshot I have so many browse buttons)
I remember seeing in the PyQt tutorial where you made use of partial but i guess that was for removeCallable from OM, but now how should i find QPushButton.objectName to be passed to slot so depending on what button is pressed i can perform some operation...

thirdly , so many people have recommended me not to use List comprehension but i find it convenient(at least here) to use while addWidget or addLayout...
like [p3_HBox2.addWidget(each) for each in [self.pylbl,self.pyEdt,self.pybrwBtn]] 

but I have a situation when I am using a combination of addWidget ,addStretch and addLayout

like in this case
 
          p1_vertical.addLayout(gridLayout)
          p1_vertical.addLayout(gridLayout2)
          p1_vertical.addLayout(hbox)
          p1_vertical.addWidget(hLine)
          p1_vertical.addLayout(nxtbtnbox)

in that case how should i after adding hbox in LC i can add addWidget(hLine) then again nxtbtnbox, i feel like i can use it with enumerate but is their any better option?

 

San's personal blog



progress.png

Justin Israel

unread,
Dec 7, 2012, 5:42:58 PM12/7/12
to python_in...@googlegroups.com
1) Just set your label to have a fixed with (setFixedWidth), or make your other widgets size policies "expanding" so they take up any new space. Probably the first one though.

2) If you want an asynchronous result from your filedialog, then instead of using my static getExistingDirectory() suggestion, just stick with creating the instance like you were. If you stay with calling the exec_() on the dialog, you are waiting for a response anyways so you can just set the value on to the text box. But for the async approach, you would show() instead of exec_() and maybe connect the accept() signal to a slot that will check the value and enter it into the textedit.
For more specific help, I would need to see an example of what you are trying.

3) Why would so many people recommend not using list comprehension? Just flat out not to use it? They are a great way to get more performance than a normal for loop. I can see there are misuses of them though.
For your specific example, you would usually not want to use a list comprehension for side effects. That is, you shouldn't use them to append or call some method in a loop. They are used to produce results that you intend to keep.
There really isn't much you can do to change your example. Qt would have needed to provide an  layout.addWidgets(aList) to accept a list of widgets. So you just need to call them in order like you are doing.

šãñ

unread,
Dec 8, 2012, 12:01:20 PM12/8/12
to python_in...@googlegroups.com
I have two browse button in the GUI as uprobably say in last image atachment

so instead of creating two different slot for each button click i implemented it this way !!
          # assign slots to buttons
          scnFile=partial(self.showFileDialog,"scnFile")
          self.browseBtn.clicked.connect(scnFile)
          rndPath=partial(self.showFileDialog,"rdPath")
          self.rdBtn.clicked.connect(rndPath)


and the showFileDialog() method as as under:
    def showFileDialog(self,*args):
        directory=os.path.expanduser('~')
        if args[0]=="scnFile":
            fname=QtGui.QFileDialog.getOpenFileName(self,'Open File',directory)
            if os.path.isfile(fname):
                self.scnFilePath.setText(fname)
        elif args[0]=="rdPath":
            selectedDir=QtGui.QFileDialog.getExistingDirectory(self,"Select Render Directory",directory)

            if selectedDir.isEmpty():
                print "No directory selected"
            else:
                self.renDir.setText(selectedDir)

also if i try to do self.scnFilePath.setText(os.path.normpath(fname))

i get error saying
Traceback (most recent call last):
  File "RenderUI.py", line 203, in showFileDialog
    if os.path.isfile(os.path.normpath(fname)):
  File "D:\Python26\lib\ntpath.py", line 417, in normpath
    if path.startswith("\\"):
AttributeError: 'QString' object has no attribute 'startswith'

ammu0608

unread,
Dec 8, 2012, 12:22:51 PM12/8/12
to Python_inside_maya

I am no so sure.  But try to add "str(fname)" in your QFileDialoge.  And check. In some cases it worked for me

Thanks and Regards,
Sudeepth Patinjarayi.

Justin Israel

unread,
Dec 8, 2012, 12:37:35 PM12/8/12
to python_in...@googlegroups.com
Unless you specifically change settings on SIP, a QString is returned for all Qt methods that return a "string" results. You have to convert it to a python string if you want to treat it as such:

self.scnFilePath.setText(os.path.normpath(str(fname)))

šãñ

unread,
Dec 8, 2012, 12:55:17 PM12/8/12
to python_in...@googlegroups.com
sorry i forgot to mention the question for my last post about slots..

I am calling same slots with different button by passing a value and checking what value it is and executing the relevant part in the showFileDialog method.. is it the right way to do becuase this does work but I guess their is a better way of doing it ?

Justin Israel

unread,
Dec 8, 2012, 2:40:57 PM12/8/12
to python_in...@googlegroups.com
The general idea of what you are doing is correct. You have a more generalized SLOT function that can receive arguments telling it how to operate on different targets or whatnot.
There are different ways, I am sure, of doing the actual conditional logic within that SLOT. It could delegate out to other private methods if you want, or simply do the action right there in the code as you are doing it. The optimal thing would be to make sure it is DRY (Dont Repeat Yourself), so that you don't have 10 conditions all performing duplicate functionality. Though you are not doing wrong now, since each condition has different things to call, with different checks to made, with different widgets to set result values on.

Anyways. What you are doing now is fine. One way of making it a bit cleaner is to use some constants for your action types instead of plain literal strings:

class MyClass(QWidget):
    SCENE_FILE_TYPE = "scnFile" # or just 0
    RENDER_DIR_TYPE = "rdPath  # or just 1

    ...
    def foo(self):
        scnFile = partial(self.showFileDialog, self.SCENE_FILE_TYPE)
        rndPath = partial(self.showFileDialog, self.RENDER_DIR_TYPE)
    ...
    def showFileDialog(self, typ, *args, **kwargs):
        if typ == self.SCENE_FILE_TYPE:
            ...
        elif typ == self.RENDER_DIR_TYPE:
            ...
 
It is not necessary to do this, but you were asking for extra tips.

šãñ

unread,
Dec 8, 2012, 2:58:45 PM12/8/12
to python_in...@googlegroups.com
well I must say thank you,

as per heading towards the goal I feel like I am stuck with desire to read cameras available from maya scene file without having to launch maya.

I made a python script like this

#file for mapay interprer to execute
import os
import maya.standalone
import maya.cmds as cmds
#fileToOpen="I:/scenes/san_telus_pan_v009.ma"
def getCams(phileToOpen):
    maya.standalone.initialize(name='python')
    cmds.file(phileToOpen, force=True,open=True)
    cams=cmds.ls(type="camera")
    return cams

the above file is called by a slot readFile(self) in my this GUI I already posted as link to pastebin
    def readFile(self):
        ## call to readMayaFile.py using mayapy.exe interpreter
        fileToOpen="I:/Vanarts Work/san_term3_project/3D/scenes/san_telus_pan_v009.ma"
        print "Opening: %s" %(os.path.basename(fileToOpen))
        import readMayaFile
        reload(readMayaFile)
        readMayaFile.getCams(fileToOpen)

but I do not understand How I shoudl use mayapy interpreter to run the readMayaFile.py and return list of cameras .. makes me in exquisite pain coz I coundt figure out trying different ways
this logic seems like useful to have coz otherwise someone who wants to do a batch render would have to open the maya  to see what camera/s needs to be rendered.

Should I use subproess.call()  to launch mayapy.exe and pass the readMayaFile.py but then how would i get the list of cameras ?

Justin Israel

unread,
Dec 8, 2012, 3:13:39 PM12/8/12
to python_in...@googlegroups.com
The docs explain using an external interpreter:

So you can either set up your python scripts to properly set the environment variables, similar to how mayapy does it, or you can start the script as you suggested with a subprocess:  mayapy <script>

šãñ

unread,
Dec 9, 2012, 12:00:08 AM12/9/12
to python_in...@googlegroups.com
well, I used the subprocess method and got somewhat closer to what I am looking for,

I modified and implemented the readFile() method to read san_telus_pan_v009.ma which gets read by readMayaFile.py via mayapy interpreter but the cams function in it doesnt return a value that i can capture by subprocss

        def readFile(self):
            ## call to readMayaFile.py using mayapy.exe interpreter
            fileToOpen="I:/scenes/san_telus_pan_v009.ma"
            code_str = \
    """
    import readMayaFile
    readMayaFile.getCams('"""+fileToOpen+"""')
    """
            # save the code
            phile=os.path.join(os.path.split(__file__)[0],"test.py")
            filename=phile
            fout = open(filename, "w")
            fout.write(code_str)
            fout.close()
            # execute the code with mayapy and pipe the result to a string
            #mayapy="D:/Program Files/Autodesk/Maya2013/bin/mayapy.exe"
            #the path D:/Program Files/Autodesk/Maya2013/bin/ must be added to sys path environment variables
            test = "mayapy " + filename
            process = subprocess.Popen(test, shell=True, stdout=subprocess.PIPE)
            process.wait()
            print process.returncode,"<" # 0 = success, optional check
            # read the result to a string
            strRead = process.stdout.read()
            print strRead

after I click QPushButton the above slot is executinf and i get the following result in Command prompt

E:\Dropbox\Rnd\myprojects\Batch>ipython RenderUI.py
File read in 0 seconds.
0 <
[u'frontShape', u'perspShape', u'sideShape', u'topShape']

but the above valuse got printed should also be returned by the getCams function in readMayaFile.py
#mapay interprer file

import os
import maya.standalone
import maya.cmds as cmds

def getCams(phileToOpen):
    maya.standalone.initialize(name='python')
    cmds.file(phileToOpen, force=True,open=True)
    cams=cmds.ls(type="camera")
    print cams
    return cams

do I have to change something in readMayaFile.py to return the value to subprocess or do I need to change some thing in the actual slot( readFile() ) ?

Justin Israel

unread,
Dec 9, 2012, 1:53:28 AM12/9/12
to python_in...@googlegroups.com
This is all getting pretty obscure. I honestly don't know if I am helping or hurting at this point, but I will simply comment on what I see.

You are both printing and returning values from your getCams()
Then you have some temporary intermediate file that is actually importing and running this function, but the only thing that happens is it indirectly triggers that print statement, even though the getCams() could just return the value, and you intermediate file could do what it needs to do with the results.

I guess I would say that getCams() should not print anything. Just return its values, and continue to act as a pure library function. What ever is calling it (your intermediate script) can do whatever is necessary with the results to get them back up to your parent process. This could be printing the results, which would require you to do an eval (not great, but it will work). I suppose there are other things you could do like writing or printing out pickle serialized format. 

At this point, it would definitely be a lot better if you could set up your environment to simply import and use the maya modules so that you do have to shell out to a subprocess. The subprocess is find if you just need to run operations, but when you are going to be doing it a lot just to make basic queries for return values, it is probably more complicated to need to have an intermediate serialization process. If you see yourself needing to do a lot of small maya operations and you want to keep it separate from your UI app, maybe you can just wrap the command line utility into something that returns results in JSON or pickle ascii so that you can call out and get results easily.

Not really sure where to do with it at this point. This thread has snow balled into something quite larger than the original question :-)

Any one else have some input?



On Dec 8, 2012, at 9:00 PM, šãñ wrote:

strRead

šãñ

unread,
Dec 9, 2012, 2:07:03 AM12/9/12
to python_in...@googlegroups.com
Justin, thanks for the idea of using pickle, i guess now I have got the direction, the process could be little time consuming for me but I am totally going to give it, yes you are right the getCams() function should not print but there i was experimenting to check if I can get correct result ,  and writing an intermediate py file that does the import  was little but if idiotic on my part when instead I could directly go "mayapy "+readMayaFile.py which will execute it from interpreter.

you weren't hurting at all, instead I thank you for hinting,

this did turned out to be snowball:/ I agree but now I have got a clear vision to proceed further.



Justin Israel

unread,
Dec 9, 2012, 10:46:20 AM12/9/12
to python_in...@googlegroups.com
Oh good. Glad my last reply was actually helpful to your goal. 
That is definitely the best route, I think, out of your options.. to just run your readMayaFile.py script directly with parameters, and get back results. Maybe like this:

mayapy readMayaFile.py --cameras </path/to/scene.ma>

You could even make it more generic as a utility and have different options as the return type:

mayapy readMayaFile.py --cameras --pickle </path/to/scene.ma>
mayapy readMayaFile.py --cameras --json -o out.json </path/to/scene.ma>

Then what you have is a general scene file parser.



šãñ

unread,
Dec 9, 2012, 10:55:10 AM12/9/12
to python_in...@googlegroups.com
yes I have done the first option and it works like charm... i fetched all render globals to my PyQt4 app except the imageFormat (i.e. jpg,iff,png bla bla) I dont know which mel file in the scripts folder of maya directory they all are otherwise i could have parsed and pulled it in my app. i dont know if its doable..

well for the 2nd and 3rd options do you mean it will be picked to disk or make json file of data returned by readMayaFile.getCams() ?


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To post to this group, send email to python_in...@googlegroups.com.
To unsubscribe from this group, send email to python_inside_m...@googlegroups.com.
 
 

Justin Israel

unread,
Dec 9, 2012, 11:21:54 AM12/9/12
to python_in...@googlegroups.com
That suggestion was just saying you have the option of writing to disk instead of stdout, but I supposed that could just be a redirect instead of something your script does. The idea being that your readMayaFile would not just be a custom script used only for your GUI, but rather a general purpose utilty script for dumping out various information from a maya file in a format that can be used in another program.

And I see the image formats defined here:
<maya install location>/scripts/others/createImageFormats.mel

šãñ

unread,
Dec 9, 2012, 3:16:12 PM12/9/12
to python_in...@googlegroups.com
alright thats exactly what I thought in the previous post, when you first mentioned., coz when u first mentioned pickle i thought i can write to disk and read back from diskand load items to my GUI though that would be long and indirect way for my purpose stdout fits better.
Reply all
Reply to author
Forward
0 new messages