wxPython and Maya 8.5


#1

Has anyone tried importing wx or Tkinter yet under Maya 8.5 and using them to build user interfaces with Maya 8.5’s python integration? If so what was your experience? Did it work? Are there any issues to be aware of? So far I’ve only converted some of my existing MEL scripts to Python using the Maya/Python UI calls. This works fine but I’m interested if the wxpython modules might also work.

–Randy Stebbing


#2

I would like to know if anyone has had any success with this as well.

Any examples of working scripts would be great.


#3

mhovland,

Are you asking for specific WX Python examples working under Maya or just examples of converted Mel scripts re-written to work using the Python calls?

My initial question was asking about the possiblity of wxPython integration. And I’m still hoping that someone can report flawless integration with wxPython as this could really open up the types of userinterface toolset available for Maya.

For those wondering about the more general Python/Maya integration I can report that Autodesk has done a great job at providing Python specific documentation to each command. All the Mel documentation examples have been converted to give corresponding Python/Maya examples.
–Randy Stebbing


#4

I was asking about UI integration using wxWidgets.


#5

I’m really wondering if this could work too. Building UI’s in Maya as we all now really sucks. However both Tkinker and wxPython would really step it up with having some really robust applications inside of maya.

Here is some help from Autodesk with regards to this. Haven’t tried it yet. Hoping someone would give this a go and let us know if they had any success.

Issue

When I try this in the Script Editor in Python Mode:

from Tkinter import *

I get this error:

File “C:\Program Files\Autodesk\Maya8.5\Python\lib\lib-tk\Tkinter.py”, line 38, in ?

import _tkinter # If this fails your Python may not be configured for Tk

ImportError: No module named _tkinter

[b]Solution[/b]

You need to find the _tkinter.so or .pyd in a separate installation of Python and put that into your PYTHONPATH for Maya to find it. _tkinter is not included with the Python distribution in Maya itself. You can look in the Python/DLLs directory to see which compiled modules are being distributed with Maya.

Note: Tkinter is not support within Maya at this current time.

If this would work, I’ve been dying to make a component editor that works. Having looked at some of the gridLayouts used in wxPython I was blown away by simple it is to create.

-Sean


#6

Keep us informed. I’m really eager to find out if this works too. It would really make gui creation for tools so much easier.


#7

It would be especially nice if a wxPython solution could be found. Then we could use the same GUI setup for both Maya and XSI. This would greatly help integration between the two.

-James


#8

this would be indeed neat!! so wxPython works with XSI as well?


#9

http://www.xsi-blog.com/archives/138

apparently so. I haven’t had time to experiment with it yet. Looks like you have to do a little work and write your own frame subclass. But it appears that you can make it think it’s a child of the main XSI window.

I was trying to do the same thing with Tkinter but ran up against roadblocks. When you have the Tk window open it steals focus from the main XSI window and you can’t do anything in the main XSI window until you close the Tk window. I suppose it might be possible to do the integration trick with a subclassed frame in Tk the same way it’s being done in wx.

I REALLY need to find some time to experiment.

-James


#10

Gets the same result here with Maya. Tk works but it freezes Maya until you quit the Tk UI.
Will digg deeper into this.

/Smaragden


#11

The reason this is happening is because the gui is stuck in a loop and never give control back to maya. One way to get around this would be to send the interface call to a thread. This would free maya back up to do what it needs to do while the interface loop is doing its thing in a thread. One of the problems i can see with doing this is that maya commands themself are not thread safe, meaning that you will have to use the “executeInMainThreadWithResult” command in order to use them. maya.utils.executeInMainThreadWithResult( command, arg1, arg2 )Seems like a huge pain though.


#12

Hmm I don’t know about Tkinter but after several hours of struggling I was able to launch wxPython inside Maya 8.5 by modifying Aloys Baillets files for XSI. No focus problem or freezing stuff what so ever. At least I haven’t noticed any such behaivor yet.
The only bad news is that I wasn’t able to run it inside 7 using cgkit’s Python-plugin. Anyone had luck with that?

Edit: Ops! I forgot to change title name of the application it tries to find (since Maya 7 is called “Maya 7” and Maya 8.5 is called “Autodesk Maya…”. So there is no bad news! It works on 7 as well :slight_smile: (as long as you use Windows, otherwise this entire hack won’t work at all)

Regards,
Pedalen


#13

Rock on! I don’t suppose you’d mind posting your solution?

Can’t wait until my studio upgrades to 8.5 and I can start applying some of this stuff.

-James


#14

Here’s the Aloys Baillet’s code stripped down and functioning in Maya.

    To use:
    1. save code to a file called WxMaya.py (or whatever you want to call it) and place in scripts directory
    2. in Maya type:
    
    import WxMaya
    WxMaya.createMayaFrame()
import os
        import wx
        import traceback
        import win32gui, win32process
        
        class MayaSubFrame(wx.Frame):
        	_topLvlMayaWinHandle = None
        	
        	@classmethod
        	def create(cls,*args,**kw):
        		app = wx.GetApp()
        		
        		if app is None:
        			app = wx.App(redirect=False)
        			
        		topHandle = MayaSubFrame._getMayaTopWindow()
        		top = wx.PreFrame()
        		print topHandle
        		top.AssociateHandle(topHandle)
        		top.PostCreate(top)
        		app.SetTopWindow(top)
        		
        		try:
        			frame = cls(top,app,*args,**kw)
        			frame.Show(True)
        			
        		except:
        			print cls.__name__
        			print traceback.format_exc()
        			frame = None
        			
        		top.DissociateHandle()
        		return frame
        	
        	
        	@staticmethod
        	def _getMayaTopWindow():
        		
        		if MayaSubFrame._topLvlMayaWinHandle is not None:
        			return MayaSubFrame._topLvlMayaWinHandle
        		
        		def callback(handle,winList):
        			winList.append(handle)
        			return True
        		
        		wins = []
        		
        		win32gui.EnumWindows(callback, wins)
        		currentId = os.getpid()
        		
        		for handle in wins:
        			tpid,pid = win32process.GetWindowThreadProcessId(handle)
        			if pid == currentId:
        				title = win32gui.GetWindowText(handle)
        				if title.startswith("Autodesk Maya"):
        					MayaSubFrame._topLvlMayaWinHandle = handle
        					return handle
        		return None
        	
        	def __init__(self,parent,app,id,title,pos=(150,150),size=(320,240),style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_NO_TASKBAR):
        		wx.Frame.__init__(self,parent,id,title,pos,size,style)
        		self.app = app
        		self.panel = None
        		self.Bind(wx.EVT_CLOSE,self.OnClose)
        		
        	def OnClose(self,event):
        		self.Show(False)
        		self.Destroy()
        		win32gui.DestroyWindow(self.GetHandle())
        		win32gui.SetFocus(MayaSubFrame._topLvlMayaWinHandle)
        		
        class MayaFrame(MayaSubFrame):
        	def __init__(self,parent,app):
        		MayaSubFrame.__init__(self,parent,app,-1,"Maya WxFrame",size=(320,240))
        		
        def createMayaFrame():
        	MayaFrame.create()
        	return True
    Note: Do not copy/paste this to the script editor and try to run it there. The script looks for a process id that returns "Autodesk Maya" and running from the script editor actually returns the id of "Output Window" which will cause the script to fail.
    
    The script is totally stripped down and is only a blank wxFrame. I appologize for the total lack of comments. 
   
   I hope that this works as well for everyone else. If you have any sort of issues with this script, please post your results here.

#15

Awesome, that’s a lot more striped down than I was able to do. Will be using this instead of my noobish code :slight_smile:


#16

Ok, I’ve been racking my brain on this. I’m getting so many errors. I realized that I had to copy the site-packages from Python24 dir to Maya’s site-packages dir. It’s still telling me that it can’t find the wx module. Also I needed the win32 site-package as well? Plus the formating got whacked when you added it to this thread. I’m not bitching, I’m totally stoked that this works for someone. Just a few details were left out to make this work. I’m just want to get this work on my end. Can you lend any help with what you had to do for Maya to recognize the wx, win32GUI and any other module needed to get this to work?

This is the current error I get:

# Error: line 0: No module named wx
  # Traceback (most recent call last):
  #   File "<maya console>", line 1, in ?
  # ImportError: No module named wx # 
  

Thanks,
-Sean


#17

doh, double post…rrr.


#18

You have to change your PYTHONPATH to something like this:


   PYTHONPATH = C:\Python24\Lib\site-packages;C:\Python24\Lib\site-packages\wx-2.8-msw-unicode;C:\Python24\Lib\site-packages\win32
  

I think it’s better to put python modules in default locations and change PYTHONPATH accordingly.


#19

What you need to run wx in Maya 8.5:
wxPython
http://sourceforge.net/project/downloading.php?groupname=wxpython&filename=wxPython2.8-win32-ansi-2.8.1.1-py24.exe&use_mirror=internap
Python Extensions for Windows
https://sourceforge.net/projects/pywin32/

Installing these modules will place them in your python site-packages folder(C:\Python24\Lib\site-packages). From there you SHOULD be able to update your PYTHONPATH environment variable like marcinm said. However, I have had poor luck so far getting maya to use PYTHONPATH even though the docs say it should. I have been manually copying modules over to the maya site-packages folder(C:\Program Files\Autodesk\Maya8.5\Python\lib\site-packages). I'm not sure why this didn't work for you NolanSW. Make sure you get all the files that are floating loose in site packages. Failing to copy over wx.pth or pywin32.pth will cause maya to not find the modules.

Sorry about the jacked-up formatting in my post. I will try to post again. If the indenting is still too messed up when you paste it, I can send you the source file if you message me with your email.

 import os
 import wx
 import traceback
 import win32gui, win32process
 
 class MayaSubFrame(wx.Frame):
 	"""
 	CLASS: MayaSubFrame
 	EXTENDS: wx.Frame
 	PURPOSE: Inherit from this class to create a wx frame in maya. See example MayaFrame below.
 	"""
 	_topLvlMayaWinHandle = None
 	
 	@classmethod
 	def create(cls,*args,**kw):
 		app = wx.GetApp()
 		
 		if app is None:
 			app = wx.App(redirect=False)
 			
 		topHandle = MayaSubFrame._getMayaTopWindow()
 		top = wx.PreFrame()
 		top.AssociateHandle(topHandle)
 		top.PostCreate(top)
 		app.SetTopWindow(top)
 		
 		try:
 			frame = cls(top,app,*args,**kw)
 			frame.Show(True)
 			
 		except:
 			print cls.__name__
 			print traceback.format_exc()
 			frame = None
 			
 		top.DissociateHandle()
 		return frame
 	
 	
 	@staticmethod
 	def _getMayaTopWindow():
 		
 		if MayaSubFrame._topLvlMayaWinHandle is not None:
 			return MayaSubFrame._topLvlMayaWinHandle
 		
 		def callback(handle,winList):
 			winList.append(handle)
 			return True
 		
 		wins = []
 		
 		win32gui.EnumWindows(callback, wins)
 		currentId = os.getpid()
 		
 		for handle in wins:
 			tpid,pid = win32process.GetWindowThreadProcessId(handle)
 			if pid == currentId:
 				title = win32gui.GetWindowText(handle)
 				if title.startswith("Autodesk Maya"):
 					MayaSubFrame._topLvlMayaWinHandle = handle
 					return handle
 		return None
 	
 	def __init__(self,parent,app,id, title, pos=(150,150), size=(640,480), style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR):
 		wx.Frame.__init__(self, parent, id, title, pos, size, style)
 		self.app = app
 		self.panel = None
 		self.Bind(wx.EVT_CLOSE,self.OnClose)
 		
 	def OnClose(self,event):
 		self.Show(False)
 		self.Destroy()
 		win32gui.DestroyWindow(self.GetHandle())
 		win32gui.SetFocus( MayaSubFrame._topLvlMayaWinHandle )
 		
 class MayaFrame(MayaSubFrame):
 	def __init__(self,parent,app):
 		MayaSubFrame.__init__(self,parent,app,-1,"Maya WxFrame",size=(320,240))
 		
 def createMayaFrame():
 	MayaFrame.create()
 	return True
 

#20

At the begining I had problem with PYTHONPATH too. PYTHONPATH variable must contain detailed paths to module (not only one directory, but all one by one). So PYTHONPATH have to include not ony \Lib\site-packages, but also \Lib, \Lib\site-packages,\Lib\site-packages\wx-2.8-msw-unicode and so on. It’s strange, but when I change PYTHONPATH to \Lib\site-packages it doesn’t work.When I changed it to detailed locations it worked.

I hope my instructions are readable, because my English isn’t that good :slight_smile: