Skocz do zawartości

Maya UI - Python - "Dynamiczne" ładowanie klasy.


KrzyM

Rekomendowane odpowiedzi

Hej,

Dopiero zaczynam uczyć się pythona i utknąłem w punkcie.

 

Mam plik toolsUI.py który przeszukuje folder Modules i dla każdego tworzy przycisk - problem jest że chciałbym żeby każdy przycisk wywoływał odpowiednie okno.

Udało mi się już zaimportować każdy moduł do skryptu. np. ToolboxUI.py, jeśli w przycisku wywołam UI = mod.ToolboxUI() to bez problemu otworzy mi się Toolbox. Jednak nie mogę znaleźć sposobu jak automatycznie wywoływać wszystkie skrypty

np. coś w stylu

plugin = "ToolboxUI()"
UI = mod.plugin

 

Mam nadzieje że ktoś jest w stanie mi pomóc ;)

Pozdro,

Krzysiek

 

Poniżej kod:

 

kTools.py

import maya.cmds as cmds
import os
import System.utils as utils
reload(utils)
import sys
from functools import partial

class Ktools_UI:
   def __init__(self):
       #uiElements dict
       self.UIElements = {}
       if cmds.window("Ktools_UI_Window", exists = True):
           cmds.deleteUI("Ktools_UI_Window")    

       windowWidth = 200
       #Main Window
       self.UIElements["window"] = cmds.window(
       "Ktools_UI_Window", menuBar=False, title="KTools", mnb=False, mxb=False
       )

       self.UIElements["columnLayout"] = cmds.columnLayout (adjustableColumn = True, columnAlign="center")

       self.createPluginsButtons()

       cmds.showWindow(self.UIElements["window"])
       cmds.window(self.UIElements["window"], edit=True, w = windowWidth, sizeable=True)

   def createPluginsButtons(self):
       windowHeight = 0
        #Plugin folder path
        systemPath = "System"
        pluginPath = os.environ["RIGGING_TOOL_ROOT"] + "/modules/"
        plugins = os.listdir(pluginPath)
        plugin_list = []            
        #find modules
        for plugin in plugins:
            if ((plugin != "__init__.py") and (plugin != systemPath)):
                plugin_list.append(plugin)            
        #create buttons
        for plugin_name in plugin_list:
           plugin_UI = plugin_name + "UI"

       #check for UI file
           for module in utils.findAllModules("Modules/"+ plugin_name):
               if (module == plugin_UI):
                   #print "UI file found: " + module

                   self.UIElements[(plugin_name + "_button")] = cmds.button(
                   label = plugin_name,
                   h = 64,
                   parent = self.UIElements["columnLayout"],
                   bgc=utils.randomBGC(),
                   c = partial(self.runPlugin, plugin_name)
                   )
                   windowHeight = windowHeight + 64
       cmds.window(self.UIElements["window"], edit=True, h = windowHeight, sizeable=True)

   def runPlugin(self, plugin, *args):
       plugin_UI = plugin + "UI"

       mod = __import__(plugin+"."+plugin_UI, {},{},[plugin])
       #btw. class_name is the same as plugin_UI
       #just testing
       class_name = mod.CLASS_NAME

       plugin_UI = plugin + "UI"

       mod = __import__(plugin+"."+plugin_UI, {},{},[plugin])
       reload(mod)
       class_name = mod.CLASS_NAME

       #this works
       UI = mod.ToolboxUI()

       #e.g.  pluginUI == ToolboxUI()
       #how to run 
       #UI = mod.pluginUI()    

toolboxUI.py

import maya.cmds as cmds
import os
import maya.mel as mel
import toolbox_utils as tU
reload(tU)
from functools import partial
import System.utils as utils
reload(utils)

CLASS_NAME="ToolboxUI"
class ToolboxUI:
   def __init__(self):
       self.UIElements = {}
       windowHeight = 450
       windowWidth = 212
       if cmds.window("Toolbox", exists = True):
           cmds.deleteUI("Toolbox")
       self.UIElements["window"] = cmds.window("Toolbox", mnb=False, mxb=False)
       self.UIElements["scrollLayout"] = cmds.scrollLayout(hst=0)
       self.UIElements["mainLayout"] = cmds.columnLayout(adj = True, parent=self.UIElements["scrollLayout"])

       cmds.showWindow(self.UIElements["window"])
       cmds.window(self.UIElements["window"], edit = True, w=windowWidth, h=windowHeight, sizeable=False)
       windowHeight3 = self.populateIcons()

Odnośnik do komentarza
Udostępnij na innych stronach

  • Odpowiedzi 24
  • Created
  • Ostatniej odpowiedzi

Top Posters In This Topic

Mam problem żeby to zrobić.

Załóżmy że mamy moduły: Toolbox, PoseSaver, AutoRig - każdy z nich znajduje się w folderze o tej samej nazwie np. Modules/Toolbox

w każdym z tych folderów niezależnie jaki to będzie skrypt, przyjąłem że będzie plik główny nazwaModułu_UI.py i klasą o nazwie modułu

 

teraz skrypt KTools.py tworzy poprostu przycisk dla każdego z tych modułów i wywołuje funkcje runPlugin

 

udało mi się "dynamicznie" zaimportować pluginy w pętli

#np dla import Toolbox/Toolbox as mod; reload(mod)

mod = __import__(plugin+"."+plugin_UI, {},{},[plugin])
	reload(mod)

- i tutaj zaczyna się problem.

 

żeby np. odpalić Toolbox.py muszę napisać

mod.Toolbox()

i analogicznie do innych pluginów.

nazwę pluginu mam w zmiennej, ale szukam sposobu jak sprawić żeby zadziałało

mod.Plugin_UI()

 

Coś jak shelf - przycisk uruchamiający dany skrypt.

Ale przy założeniu że mamy N skryptów.

 

 

Próbowałem coś z exec, partial ale bez skutku.

 

Sory że tak bez składnie to piszę, ale wynika to raczej z mojej niewiedzy o Pythonie - zacząłem się bawić kilka dni temu i jeszcze nie ogarniam wielu elementów.

Odnośnik do komentarza
Udostępnij na innych stronach

Reanimator, dzięki - działa super. Muszę przestudiować funkcje wbudowane w Pythona ;)

Podrzucisz mi jakieś hasło pod którym znajdę jakieś wytłumaczenie dla tych nawiasów: mod.{0}() Szczerze to nie do końca rozumiem.

 

Praetorian - Reanimator rozwiązał problem. Nie bardzo rozumiem twój kod, ale domyślam się że chodzi o ścieżkę?

Ja stworzyłem sobie zmienną w env i przez shelfa główny skrypt wywołuje tak:

import os

try:
   riggingToolRoot = os.environ["RIGGING_TOOL_ROOT"]
except:
   print "RIGGING_TOOL_ROOT environment variable not correctly configured"
else:
   import sys
   print "Running: " + riggingToolRoot
   path = riggingToolRoot + "/Modules"

   if not path in sys.path:
       sys.path.append(path)

   import System.ktoolsUI as kUI
   reload(kUI)

   UI = kUI.Ktools_UI()

 

może to jakoś uzupełni moje poprzednio 2 wklejony kody.

Odnośnik do komentarza
Udostępnij na innych stronach

poszukaj string.format :)

 

uzywasz numerow w klamrach, a pozniej podmieniasz je wartosciami

 

zmienna = "cos innego"
polaczone = "Lorem {0}, albo {1}".format("Ipsum", zmienna)

 

print polaczone da: "Lorem Ipsum, albo cos innego"

 

 

W Twoim przypadku zebralem nazwy funkcji z modolow (stringi) i pozniej uzylem ich zeby wywolac kazda z nich za pomoca eval w loopie.

Odnośnik do komentarza
Udostępnij na innych stronach

Praetorian - Reanimator rozwiązał problem. Nie bardzo rozumiem twój kod, ale domyślam się że chodzi o ścieżkę?

 

Nie o ścieżkę. To samo inaczej (może jaśniej):

 

ty napisałeś:

plugin = "ToolboxUI()"

UI = mod.plugin

 

ja piszę:

plugin = "ToolboxUI()"

UI = getattr(mod, plugin)

Odnośnik do komentarza
Udostępnij na innych stronach

a nie lepiej jeszcze tak?

 

plugins.py

class PluginBase(object):
   def generate_ui(self):
       # ui creation
       pass

class RiggingTool(PluginBase):
   def generate_ui(self):
       # override this here

 

__init__.py



import plugins
from plugins import PluginBase

def plugin_factory(plugin_name):
   result = getattr(plugins, plugin_name)
   if issubclass(result, PluginBase):
       return result

plugin = plugin_factory("RiggingTool")

 

PS. Polecam Ci jednak robić takie rzeczy w PySide a nie w standardowym majkowym UI

Odnośnik do komentarza
Udostępnij na innych stronach

Dziękuje wam ;) PySide mam na liście ;)

Moje rozwiązanie z góry było skazane na porażkę bo to pierwszy skrypt i tylko forma nauki.

 

Znacie jakieś dobre źródła wiedzy? Obecnie przeglądam tylko manual i czytam "Maya Python for games and film"

Odnośnik do komentarza
Udostępnij na innych stronach

PS. Polecam Ci jednak robić takie rzeczy w PySide a nie w standardowym majkowym UI

 

Ogólnie robić całe UI w PySide? Nie używać Maykowego?

A co z PyQT? Jeszcze nie bardzo widzę różnicę między PySide a PyQt.

Odnośnik do komentarza
Udostępnij na innych stronach

Znacie jakieś dobre źródła wiedzy? Obecnie przeglądam tylko manual i czytam "Maya Python for games and film"

 

"Python od podstaw" - fajna książka i jeszcze o pythonie 2.x (Python 3 nie jest na razie nigdzie implementowany oprócz Blendera chyba).

 

Ogólnie robić całe UI w PySide? Nie używać Maykowego?

 

Tak.

 

PySide to open source PyQt. Ma kilka ograniczeń ale jest wpychane wszędzie ponieważ nie trzeba za niego płacić.

Oba wrappery tak naprawdę robią to samo - wywołują kod z bibliotek Qt.

Odnośnik do komentarza
Udostępnij na innych stronach

Hej,

odgrzebuje jeszcze ten temat - zmieniłem UI na pySide i nie mogę ogarnąć tego samego ;)

 

W skrócie sytuacja: Mam skrypt "_shelf", który tworzy przyciski dla wszystkich skryptów które spełniają kryteria (odpowiednie nazwy itp).

Kliknięcie przycisku przekazuje Nazwę pluginu do funkcji _pluginFactory i ten importuje UI.

http://pastebin.com/UpEupcEj

 

W sumie to mi obojętne jak uruchomić te skrypty, byle poprawnie.

Zakładam wstępnie że tak chciałbym żeby wyglądał każdy główny plik danego plugina.

http://pastebin.com/eXThzDnY

 

I teraz jeśli uruchamiam ten skrypt z majkowego shelfa to robię to tak:

http://pastebin.com/4hH5RYnX

 

Dlatego próbuje coś wykąbinować na podstawie wpisu kroopsona, i stworzyłem plik pluginFactory do którego ręcznie będę dodawał classy dla każdego plugina? (No chyba że nie potrzebuje, bo zakładam że uruchamiać je będę tylko poprzez _shelf)

http://pastebin.com/u7gjvjJA

 

Próbowałem poprzez getattr, exec ale dostaję wtedy jedynie wynik w stylu:


natomiast jeśli uruchomię skrypt tak jak przez majkowy shelf to otrzymuję bardzo podobny wynik


 
Nie znalazłem jeszcze na to rozwiązania, niby wywołuję tą funkcję z powodzeniem ale nie udaje mi się wywołać UI.
Napotykam się np na:  [code]TypeError: descriptor 'show' of 'PySide.QtGui.QWidget' object needs an argument
Odnośnik do komentarza
Udostępnij na innych stronach

O ile dobrze rozumiem twoj problem to potrzebujesz dwoch funkcji.

1) zaimportuj moduly do slownika.

2) ze slownika stworz panel z guzikami

 

Polomorfizm zastosuj na poziomie modulu i zasadniczo to tyle. Niech kazdy modul ma funkcje rejestrujaca, przekaz do niej uchwyt/obiekt glownego okna i v'oila. Nie potrzeba tutaj jakichs cudow na kiju. To nie java, ludzie :-)

Odnośnik do komentarza
Udostępnij na innych stronach

Ja już wczytałem wszystkie moduły i zrobiłem z nich przycisk. Każdy przycisk wywołuje funkcje _pluginFactory i przekazuje jej nazwe modułu.

Chciałbym żeby ta funkcja wywołała mi okno pySide z moim modułem czyli modul_UI.py

 

http://pastebin.com/UpEupcEj

Na dole zakomentowane jak ręcznie zrobie import modulu, i pozniej modul.show() to dziala, ale jak juz zrobię coś jak:

__import__(folder+"."+plugin, {},{},[plugin])

To a następnie eval, exec lub getattr to średnio rusza.

 

Nadal szukam jakiś info na ten temat, jeszcze nie do końca rozumiem różnicy między tym jak udało się wywołać te moduły (strona 1), a teraz po przejściu na pySide.

 

Może problem leży w samym uruchomianiu pySide, ale to poruszyłem w tym temacie: http://max3d.pl/forum/threads/98755-PySide-pytania

I szukam info dot. rozwiązania Kroopsona.

 

v32l9h.png

Odnośnik do komentarza
Udostępnij na innych stronach

Kiedy wywolujesz import z tymi klamrami, usuwasz caly kontekst dla importowanego modulu.

Sprobuj tak: __import__(folder+"."+plugin).

Napisz prosze co zwraca ta funkcja po imporcie.

Dlaczego nie dziala automatyczny import ? Jakie sa objawy ? I ne kombinuj z getattr itp.. na zaimportowanym module wywowal funkcje polimorficzna i to powinno dzialac. Mozesz.ewemtualnie sprawdzic czy modul ma te funkcje. Pousuwaj wszystkie "__" to niepotrzebne.

Odnośnik do komentarza
Udostępnij na innych stronach

Wydaje mi się że własnie import jest w miarę ok. Teoretycznie jestem wstanie wywołać skrypt z tego importu jak ręcznie podam import.nazwa() przy UI. (komentarze w kodzie)

Jak wywołać tą funkcję? Czytałem o tym już i rozumiem koncept, ale w praktyce?

 

Sory za nie ogarniecie ;)

#plugin factory
def _pluginFactory(self, plugin, *args):
	self.UIPlugins = {}
	folder = "__"+plugin.strip('_UI')

	##Co mysle ze musze napisac dla plugin = toolBox_UI
	## i to otwiera okno poprawnie
	# import __toolBox.toolBox_UI as tb
	# reload(tb)
	# self.UIPlugins["toolBox_UI"] = tb.toolBox_UI()
	# self.UIPlugins["toolBox_UI"].show()	
	##tb = 

	##import
	importPlugin = __import__(folder+"."+plugin)
	print "import metoda 1:" + str(importPlugin)

	importPlugin2 = __import__(folder+"."+plugin, {},{},[plugin])
	print "import metoda 2:" + str(importPlugin2)	
	##import metoda 1:
	##import metoda 2:
	##teoretycznie metoda 2 zdaje rezultat

	result = getattr(pFactory, plugin)
	##get attr result: 


	##To czego mi brakuje to wstawienia zmiennej plugin zamiast toolBox_UI()	
	# self.UIPlugins[plugin] = importPlugin2.toolBox_UI()
	# self.UIPlugins[plugin].show()
	##^ teraz tez dziala

	self.UIPlugins[plugin] = importPlugin.toolBox_UI()
	self.UIPlugins[plugin].show()
	## TypeError: 'module' object is not callable


	# # # if __name__ == "__main__":
		# # # try:
			# # # self.UIPlugins[plugin+"_UI"].close()
		# # # except:
			# # # pass

Odnośnik do komentarza
Udostępnij na innych stronach

Czytałem to i próbowałem różnych opcji jak importowałem to na samym początku, możesz mi wytłumaczyć w czym tkwi różnica i czemu lepiej importować __init__.py i jak wtedy dobrać się do tego pliku? Mam w init.py dodać funkcję która to uruchomi?

 

konkrednie dla zmiennej plugin = "toolBox_UI" wygląda to tak i uruchamia się:

	import __toolBox.toolBox_UI as tb
	reload(tb)
	self.UIPlugins["toolBox_UI"] = tb.toolBox_UI()
	self.UIPlugins["toolBox_UI"].show()

I import daje mi wynik:


 

Dlatego ja importowałem to tak:

importPlugin2 = __import__(folder+"."+plugin, {},{},[plugin])

i dawało to taki sam wynik:


Dlatego też próbuję wywołać okno przez:

Tylko nie wiem jak to wywołać żeby podać za XXXXXX np. plugin15_UI()

	self.UIPlugins[plugin] = importPlugin2.XXXXXX
	self.UIPlugins[plugin].show()

 

 

Natomiast jak importuje w sposób który podałeś

importPlugin = __import__(folder+"."+plugin)

dostaje wynik:


Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się



×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Wykorzystujemy cookies. Przeczytaj więcej Polityka prywatności