Access Class B's function inside Class A?
-
Hi,
Is there a way I can access Class A's function inside Class B?
My case scenario is Class A is a treeview layout. Class B is the main GeDialog.
You can see it here: https://www.dropbox.com/s/zua8k8xi8zw05g6/c4d263_access_class_a_function_inside_class_b.jpg?dl=0I want Class B's
refresh_layout
function to trigger when I changed a variable in the treeview layout specifically the global variablefolder
. Is this possible?A mock code would be something like this
class A(c4d.gui.TreeViewFunction): def Select(self, root, userdata, obj, mode): if mode == c4d.SELECTION_NEW: for node in self.node_list : node.selected = False if node == obj: node.selected = True folder = obj.name # Trigger Class B's refresh layout() function class B (gui.GeDialog): def InitValues(): global folder def refresh_layout(): # refreshes Class B's layout
The other alternative would be to make the
refresh_layout
function live outside the class but since the function has already a lot of variables usingClass B
, I want it to be insideClass B
too.Is this possible?
-
Not in the way you may imagine it, but yes.
For a class function to be called, you need an object to call it on (
self
). Since many classes may have functions of the same name, it is necessary to know what class you're even addressing here.
For example,x.doSomething()
andy.doSomething()
may call totally different functionsdoSomething
because x and y belong to different classes, each with its own definition ofdoSomething
.
That means, to callrefresh_layout()
you need to have an object to invoke it on. Like,thatDialog.refresh_layout()
.So, what you need to do is to pass the dialog object of
class B
toclass A
in some way. Then, class A can invoke the refresh by just calling the function on that object. You normally pass such connecting objects in the init function of the class A (but that's really a design question that I can't answer for you).(To cover all cases: it is possible to define functions that do not have a self parameter; read up on your Python class definitions for that... it doesn't apply for your case here, since a refresh wll need the dialog object anyway.)
-
Hi,
everything is an object in Python, which is leaves you with many options to do what you want. Here are two of the more popular variants.
class Item(object): """A type to invoke some_function on. """ def __init__(self, name): self._name = name def __repr__(self): return self._name def some_function(self, *args, **kwargs): """ """ msg = "{} has been invoked with the args: {} and the kwargs: {}." print msg.format(self.some_function, args, kwargs) class Invoker(object): """Invokes an anonymous callable by binding that callable. """ def __init__(self, func): self._callable = func def invoke(self, *args, **kwargs): """Invoke the stuff we want to invoke. """ print "\nInvoking callable." # We are invoking an anonymous function that has been bound # to the class. We are not really aware that this is actually # a method. This could also be a function, a lambda, everything # that is callable. self._callable(*args, **kwargs) class AlsoInvoker(object): """Invokes a specific method by binding objects and calling the class implementation on them. """ def __init__(self, objects): self._objects = objects def invoke(self, *args, **kwargs): """Invoke the stuff we want to invoke. """ print "\nInvoking class implementation." for obj in self._objects: # We are calling the class object for a known method and # are just filling in the "self" part of the call (obj). Item.some_function(obj, *args, **kwargs) # Some Items with methods we want to invoke. a, b = Item("a"), Item("b") # Option A: bind the instance of a function object directly. invoker = Invoker(func=a.some_function) invoker.invoke(42, pi_equals_e=True) # Option B: bind instances of an object and then call the implementation of # a method on the class object with these objects. invoker = AlsoInvoker(objects=[a, b]) invoker.invoke("bob is your uncle", pi=3, e=3)
Invoking callable. <bound method Item.some_function of a> has been invoked with the args: (42,) and the kwargs: {'pi_equals_e': True}. Invoking class implementation. <bound method Item.some_function of a> has been invoked with the args: ('bob is your uncle',) and the kwargs: {'pi': 3, 'e': 3}. <bound method Item.some_function of b> has been invoked with the args: ('bob is your uncle',) and the kwargs: {'pi': 3, 'e': 3}. [Finished in 0.1s]
Cheers,
zipit -
Another solution, in your specific scenario, where you don't really need to access a method but want to trigger the
GeDialog
in some way, is to message the dialog as discussed here.In short: your treeview sends a message, and the dialog reacts to the message by performing the refresh layout.
-