I'd like to point out a refresh issue when running a wxPython application from within Maya. Basically, anything you do in Maya after the wx app has entered the main loop, does not automatically refresh the screen. For example, please try running the following script from within Maya:
from maya.mel import *
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, (-1,-1), wx.Size(250,150))
panel = wx.Panel(self, -1)
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(wx.Button(panel, 105, "Create Sphere"), 1, wx.EXPAND)
self.Bind(wx.EVT_BUTTON, self.OnSphere, id=105)
def OnSphere(self, event):
frame = MyFrame(None, -1, "wxRefreshBug.py")
if __name__ == '__main__':
app = MyApp(0)
You will notice, that when you click on the button to create the sphere, it will not appear right away--you have to tumble the camera to make it visible. I know it is possible to use the refresh() command, but that only works immediately after creating the sphere. Trying to delete the sphere (or anything else for that matter) still requires a tumble to refresh the screen.
I'm sure this has nothing to do with your plug in and has more to do with the wx event loop. However it is worth pointing out. Maybe there is something you can do to fix this in future versions of the plug in?
Obviously, the wx event handler runs in its own thread in which case you must not use the maya.mel module to invoke MEL commands. Those commands are executed using the MGlobal::executeCommand() function which is not thread-safe. Using the mel module in a separate thread may cause arbitrary misbehavior of Maya (including crashes).
Instead you could use the maya.remote.mel module which is a thread-safe way to invoke MEL commands. As an additional benefit you can also run your wx application outside Maya. The downside of using this module is that you have to start the MEL server inside Maya and that the remote.mel module is quite a bit slower than the regular mel module because there's a lot more overhead per function call.
Another alternative would be to construct and execute the MEL command yourself using the MGlobal::executeCommandOnIdle() function which is thread-safe (this is what the remote.mel module is doing).
By the way, did you start your script directly using pySource? This has the disadvantage that pySource won't return until you close your application. This means, you will partially block Maya. So you would either have to run your application in a separate thread or outside Maya anyway.
- Matthias -
Yes, I'm afraid I *did* start my application using the pySource command. This must be why Maya was not refreshing.
It's unfortunate that I will have to run wxPython applications externally, using the openPort method. However, I have done it that way before and found that writing the MEL commands to a file and then sending a source commmand to Maya is much faster than sending each MEL command via the port individually. It's just that I was hoping to be able to run everything from within Maya!
Thank you for your help and your great plugin!
I think pySource alone was not responsible for the refresh problem but rather the command being executed from a separate thread. I observed exactly the same behavior as you described when I was invoking the sphere command from another thread.
By the way, while the remote functionality is similar in functionality than a command port, it does not use Maya's command port facility. Currently, the communication is done via xmlrpc. But I don't expect that it is faster than the command port.
If speed is a concern you could keep your application within Maya (by executing it in a separate thread) and use the MGlobal.executeCommandOnIdle() function to invoke MEL commands:
from maya.api import *
MGlobal.executeCommandOnIdle("sphere -radius 1.5")
Compared to using the remote.mel module this will save you from the communication overhead doing a remote procedure call. As a drawback you have to construct the MEL command strings yourself, but this might again increase the performance a bit.
Oleg has asked me to look into this a bit more, and I have found that in some situations wxPython will relinquish control back to Maya. For example if the window is created as a dialog and iconized after the sphere has been drawn, the sphere will appear. So this seems promising.
To look at this further I was hoping to build a debug .mll in Developer Studio, but when I do that and invoke the pySource command within Maya I get a link error where _core.py cannot find _core_.pyd. This seems odd when the files are in the same directory. I have added the wx directory to my PATH environment variable but this makes no difference. If I run Oleg's script as a stand-alone script I don't get the problem. Have you any ideas what the problem is and how I can get round it?
Are you still running the wxPython application right within Maya without creating a separate thread? I'm afraid you will not get a stable application with this setup.
As to the missing _core.pyd: This module is from the cgkit package which is independent of the Maya/Python stuff (so I take it you're using cgkit as well, right?). There is also a file _core.py but this one is only used in the 'light' version of cgkit and this module does not import _core.pyd, so it seems like something got mixed up with your installation. Could you post more details on what you were trying to do and what the exact error message has been?
(Maybe the error you were seeing was the result of mixing the debug and release version of Boost.Python....?)
I built a debug sourcepy.mll (using Developer Studio) and I get an error when I run the py or pysource command. The errors seem to be happening in wxPython - they are
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "D:\Python 2.5\Lib\site-packages\maya\initmaya\__init__.py", line 35, in <module>
from maya import api
File "D:\Python 2.5\Lib\site-packages\maya\api\__init__.py", line 26, in <module>
from maya._api import *
ImportError: No module named _api
File "<string>", line 14, in <module>
File "wxSphereDialog.py", line 5, in <module>
File "D:\Python 2.5\lib\site-packages\wx-2.7.2-msw-unicode\wx\__init__.py", line 44, in <module>
from wx._core import *
File "D:\Python 2.5\lib\site-packages\wx-2.7.2-msw-unicode\wx\_core.py", line 4, in <module>
ImportError: No module named _core_
I have built a debug version of the python library (lib and dll) and linked sourcepy against the debug lib. It did seem as if the mll was linking to the python release dll at run time, so I removed that from my path, but this made no difference.
When I use the pre-built release version of sourcepy (sourcepy-py2.5m7.0.mll) I do not get the problem.
I am not using cgkit. Do I need it to build sourcepy correctly? It does seem as if I have got something missing. I am new to Python and wxPython so any help you can give me would be much appreciated. Thanks
It could be that Windows just doesn't find a DLL that it would need (probably a debug DLL) or there's a conflict between a release and a debug DLL.
You can use 'dumpbin' to find out what other DLLs a particular DLL depends on. This is a command line utility that comes with Visual Studio (you might have to set your PATH to the MSVC bin directory). For example, if you run it on the sourcepy plugin like this
> dumpbin /dependents sourcepy-py2.5-m8.0.mll
then you'll see an output that contains the following lines:
Image has the following dependencies:
These are the DLLs that the plugin requires. You can do the same with Python extension modules (*.pyd files). Please check the file _api.pyd in the Python package "maya" (in your case this is located in D:\Python 2.5\lib\site-packages\maya) and also the file _core_.pyd in the wx directory (D:\Python 2.5\lib\site-packages\wx-2.7.2-msw-unicode\wx). Hopefully this will reveal why the modules don't load.
You can also try to import the maya.api module or some wx module in a Python shell outside Maya. This might actually display a Window that mentions which DLL cannot be found (if this is the cause of the problem). In case of the maya package you might have to add the Maya bin directory to your path so that the Maya DLLs can be found.
Thanks. This is a useful technique I wasn't aware of. I can see that both _api.pyd and _core_.pyd are dependent on the release version of the python lib, whereas my debug build of sourcepy uses the debug version. Presumably I need to build a debug version of wxPython as well too.