DirectGUI subclassing

As work progresses on my game, I’ve added a decent amount of controls (buttons, frames, option menus, etc).

As I’m learning Panda and Python at the same time, I’ve implemented certain things in a quick and dirty fashion to get parts of the game working, knowing I’d come back to fix them later. It may be slow, but I find it helps me learn why some ways to code things are better than others.

I created a simple global def function for my gui controls.

Basically

def myGUI (type, pos, parent, etc...)
 if type = "menubutton":
   return DirectButton(pos=pos, etc...)

I have a few types that I call from my screens and it’s a big help - if I decide to make all buttons have blue letters, I can change it in 1 place.

I realize this is not very OOP, so Im thinking of making it a class. My question is, what are the advantages of the class over my initial function approach? Any gotchas I have to look for as I convert it to a class?

Advantages of OOP are explained widely, so you can find many information about this subject. Entire chapters are dedicated to this subject on every book that talks about OOP. To stay near your example, for example, OOP simplifies the argument passing. If you have a class menubutton (and other analogous classes) you can omit the parameter type. If you have some common behaviours you can define them in some “abstract” (this term is misused here) class and you can inherit from them (this shrinks your code and is more robust). If you have some common mechanisms (for example every control must provide mechanisms to show it and hide it) that are different for every “kind of control” (for example you could want a fade when you hide a menubutton but you could want to hide instantly a label) you can invoke the same method hide on every control and it behaves in the right way (polymorphism).

So, the advice is to adopt OOP, even if you don’t see instantly the advantages. In the short-term, as the size of your code increases, you’ll see these. For now, simplification of your code (removing useless parameters and dividing the code in smaller and simpler classes) could be a sufficient advantage to “early” adopt OOP. Anyway, I repeat, if you want an exhaustive answer look for it in a book that covers OOP.

To be more practical, with OOP you can remove this kind of code (this is managed “automatically” by the paradigm):

def ...( type, ... ):
  if type == value1:
    ...
  elif type == value2:
    ...

and surely if you’ve less code you’ll be happier. :slight_smile:

Hi, thanks for your response.

No need to sell me on OOP, I have slowly but surely been converting my original code to OOP. And it has definitely led to less code (always a plus ! :slight_smile: )

My question, for this particular example of the myGUI, was around:

  1. Advantages. You mention less code and that’s true . But is the “If type=” check the only real change? I will still do it, but may wait if tha’s the only gain.

  2. Froma design point of view - I very sloppily have all my controls in 1 function (myGUI) which checks the type of control I want and returns that. Is there an advantage (less code? memory use?) to subclassing each tyope of DirectGUI control (button, scolledlist, etc) separately or put them in master wrapper class (like my function)

  3. Are there any object gotchas about the way I’m doing it, i.e. the function returns an object that never goes out of scope, etc. So a class would be better becuase , etc. etc.

Just looking for thoughts on this. (There may be nothing else to say on it or I may be way off on what I’m thinking).

Thx!

It depends on your code. If the code you showed is the only code involved, I think you’ll have no other improvements with OOP (obviously, if you’re sure that you aren’t going to extend it). If you’ve other behaviours (for your controls) to code, you’ll have other gains (because for example you can write common code only once).

It depends on your needs. If you’ve efficiency-related needs (memory and CPU consumption, …) you’ll have no significant differences. Ok, theoretically your code could be a bit slower than the “OOP version” (because you’re coding your “version” of dynamic binding, and surely Python does it in an optimized way), but this is not a perceivable slowing down (this kind of considerations are important mainly in C++, where you can decide if a method is virtual or not, and this is important if the method considered is called thousands of times during a frame… But you’re not in C++ and your method is called few times).

The real gain is from a designer point-of-view. If your code will grow, with the OOP paradigm you can delegate to Python the choice of the “right” methods to invoke, so you can remove every if type== clause from your code. For now you’ve only creational code, but suppose you need to customize not only creational code, but also showing, hiding, onClick, changeLabel, changeSound, … You’ve to multiply the if type== clause times the behaviours you need. And you’re only in a “flat” hierarchy… Suppose you’ve some behaviours shared by some controls but not among others… The if type== clauses will become more complex too.

So, the real gain is not “technical”, you’ll have no greater performances, but maybe more important gains. You delegate to Python the choice of the correct methods to bind, with no code, thus your code will be more robust and easier to maintain. And maybe this is more important than saving an instruction for each frame.

Hmm, no, I can’t see them. After all, there are many important projects that aren’t OOP (e.g. Linux kernel), so you can obtain wonderful things without OOP too.

Ok, to summarize, if you think you’re going to extend this GUI-related logic (i.e. you’ve to manage other behaviours, not only the creation of controls), setting up an “OO” hierarchy will lead you to simpler code.

But this is only to answer to your OO question. If, instead, the question was “how to well-engineer my controls creation?”, if you think that your code has to manage only the creation of controls, the answer could be different. Indeed, in this case, your code is very close to be an instance of the Factory design pattern, so you can evaluate to adopt this design pattern, and adapt your actual code to this. Maybe this could be that you’re searching (this is an example).