5
\$\begingroup\$

I am writing a wrapper around the GeUserArea class of Cinema 4D's Python API to enable creating user interfaces using an object orientated interface.

I've already written 2 prototypes, but I am not satisfied with my class-design. They do work very well, but I decided to start over to make it even more efficient, more clean and better commented, etc.

The GeUserArea class provides drawing on it as it was a field of pixels, so it's a highly dynamic class to enable almost any type of interface you want, when you have the skills.

The baseclass for all objects being rendered is the Renderable class. Two of the subclasses are View and Lable. The difference between these is, that View does hold a frame attribute that defines a rectangular area while Lable does only hold a position attribute that defines the position of the text being rendered.

The Renderable class implements a tree-like design, so you can add a Renderable instance below another, etc. When an input event (mouse/keyboard) appears, a chain starts that tells the full tree that this event occured. Any Renderable instance should be able to react on an input event. But the view-subclass should also call a method when the mouse clicked into it's area.

(Theese methods are to let the user override them while subclassing, enabling to react on those input events.)

The event itself comes from GeUserArea.InputEvent(self, msg). From the msg parameter, I can read out if and where a mouse event took place. After doing so, the event chain starts.

class Renderable:
    def InputEvent(self, msg):
        pass

class View(Renderable):
    def MouseEvent(self, msg, mouse):
        pass

Using the above layout, I'd need to implement a method that manages calling of theese methods, like this:

class Renderable:
    # ..
    def _private_ManageInput(self, msg):
        self.InputEvent(msg)
        for sub in self.subs:
            sub._private_ManageInput(msg)

class View(Renderable):
    # ..
    def _private_ManageInput(self, msg):
        if IsMouseEvent(msg):
            mouse = GetMouse(msg)
            if mouse in self.frame:
                self.MouseEvent(self, msg, mouse)
        Renderable._private_ManageInput(self, msg)

This does already seem a bit dirty to me.

As the mouse position doesn't change within the recursive chain, it makes more sense to give the mouse position as an argument to the Renderable._private_ManageInput() method, which gives a speedup of about 30%.

class Renderable:
    # ..
    def _private_ManageInput(self, msg, mouse):
        self.InputEvent(msg)
        for sub in self.subs:
            sub._private_ManageInput(msg)

class View(Renderable):
    # ..
    def _private_ManageInput(self, msg, mouse):
        if mouse is not None:
            if mouse in self.frame:
                self.MouseEvent(msg, mouse)
        Renderable._private_ManageInput(self, msg, mouse)

The Renderable class does not implement reacting on MouseEvents (as it does not define any area where the mouse could "hit" it), but a method does need arguments for this purpose? It seems quite dirty to me.

Can you tell me how I can improve this design?

\$\endgroup\$

migrated from stackoverflow.com Sep 9 '11 at 14:04

This question came from our site for professional and enthusiast programmers.

3
\$\begingroup\$

One thing you could do is ensure that events only reach those who are interested in that particular type of event. Right now you seem to be sending out a generic events that you then check to see what type they are.

I wrote a similar answer some time ago to another question on Stack Overflow. You can read it here:
https://stackoverflow.com/questions/7249388/7294148#7294148

\$\endgroup\$
  • \$\begingroup\$ The idea with the EventManager is a pretty good one and I think is easy to implement in this case. I will try it out, thank you so far ! \$\endgroup\$ – Niklas R Sep 17 '11 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.