View RSS Feed

The Mad Wizard

Traipse – Code Structure [Part 1]

Rate this Entry
This is a repost of my blog post found here:http://weblog.madmathlabs.com/?p=448

Since the next milestone is a near complete rewrite, for the UI it is a complete rewrite, I am given an opportunity to restructure the software and reduce a problem that I felt plagued development in the Ornery Orc. Fragmentation.

I would rather not give any examples of the fragmentation that has occurred in the previous versions of OpenRPG, since it will likely lead to confusion; the fact of the matter is, fragmentation in the code development and structure occurred. Development became more difficult because it was hard to trace down linked objects and when ironing out bugs I would have to open a good number of files, at times five or more, to try and find the object that was causing the break.

Instead I want to focus on the next milestone and how I have worked out a code structure and naming convention that should make the code easy to read and easy to develop. The new conventions create a foundation that will carry forward in future development, and should showcase the ease and speed at which a developer can learn and create. In this multi part blog post I will explain the code structure and naming convention of objects in the next milestone, and how they make development a cinch.

Basic Structure

I have created a basic structure for creating widgets and laying them out inside other widgets. Eventually all of the code will try and follow this format closely, but I anticipate some widgets will simply not be able too. It’s really quite simple. When creating a widget that we plan to add to another widget we simply create it inside a defined method and then return the widget. Here is an example snippet of code using the Blank GUI plugin (currently in OpenWorld as of this posting)
Code:
class BlankGUI(QDialog):
    ## Using QDialog is *not* required, it is used as a convience. QDialog *inherits* QWidget.
    ## To connect your buttons to the Plugin class above us, call them using self.plugin.FunctionName
    def __init__(self, plugin):
        QDialog.__init__(self, plugin.topWindow)
        self.setWindowTitle('Blank GUI Plugin')
        self.plugin = plugin
        self.menuBar = MenuBar(self)
        layout = self.buildLayout()
        self.setLayout(layout)

    def buildLayout(self):
        # This is a simple GridLayout to enter in new widgets.
        # GridLayout's are a favorite becuase they provide more control over the widget layout.
        layout = QGridLayout()
        layout.addWidget(self.menuBar, 0,0)
        return layout## Returning the layout maximizes organization.

    def closeEvent(self, event, exit=False):
        # This captures the close event of the GUI, hiding it instead of removing it from memory.
        if exit:
            super(BlankGUI, self).close() ## use super to call the unmodified closeEvent
        self.plugin.showToggle(None, False)
        self.hide()
In this snippet I am deriving from QDialog to create a widget that we can lay more widgets into. This class is the basis for future GUI based plugins. The key aspect I am placing into all future code is the way I build the layout in the buildLayout method. While this example is not exact, it does point us in the right direction. When I build a widget inside that buildLayout method I will code something similar. Example: self.exampleWidget = self.exampleWidget(). The exampleWidget method might then look like this:
Code:
    def exampleWidget(self):
        widget = QWidget()
        layout = QHBoxLayout()
        buttonClose = QPushButton('Close')
        layout.addWidget(buttonClose)
        self.connect(buttonClose, SIGNAL('clicked()'), self.doClose)
        widget.setLayout(layout)
        return widget
First it creates a widget and uses the variable name ‘widget’, then it creates a layout and uses the variable name ‘layout’. Only the button has a unique name. This naming convention should organize and expedite coding. It may sound a little lazy, but developers can copy and paste a lot more, and let’s face it, that saves time. Especially if it is code that you are going be retyping over and over. The structure is fairly organized as well allowing the developer to focus on the portion they are editing, instead of a stream code that is in the general area of where he/she is working.

While it’s not mandatory that new developers continue the same method, the entire software will be coded this way and it may be hard to escape at times. This shouldn’t really be a problem though since it’s design is to ease developers worries and make their life easier.

Setting Parents

One of the things I despised the most in the last milestone was objects that were difficult to find. Especially the ones that cross pollinated various classes. I’ve made things a bit different by using less pointers and reaching directly for the object that was first created. I do this by reaching through the parents. I actually recommend this instead of using pointers because we should be able to find all objects that have been created from the very first class, which is called MainWindow. This doesn’t mean they are all inside the MainWindow class; what I mean is the MainWindow class can reach into it’s children and even their children to find an object.

In the previous milestone when a class was created we passed the parent and set the self.parent object as the parent. This naming convention becomes confusing when using my linking method. We eventually have objects that look like self.parent.parent.object(). That’s just mind numbing. Instead I set my parents according to the name of the parent class. Here is a living example:
Code:
        if treeType == 'Layers':
            self.mainWindow.mapDock.mapView.mapPage.buildMapLayers(self.tree_root, self.tree)
            self.connect(self, SIGNAL("currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem * )"),
                                self.mainWindow.mapDock.mapView.mapPage.layerChange)
This is part of the GrowTree method for the Map Tool Box. Even though the Map Tool Box is a secular file and class it still has the MainWindow class, the very first class, as it’s parent. As seen here in it’s __init__ method:
Code:
    def __init__(self, mainWindow, treeType):
        QTreeWidget.__init__(self, mainWindow)
        self.mainWindow = mainWindow
And you can see I named it self.mainWindow. This naming convention is then a human readable path from MainWindow to the MapDock class (the object that becomes the complete map) all the way down to the MapPage class (our QGraphicsScene). This convention will allow me to reduce confusing pointers and grab the original object with objects that are already created. It’s not just a path to easier coding, it also reduces the amount of variable names being created … and should reduce resource consumption a well.

End Part 1

Part 1 should bring to light some of the basics in the next code structure. The aim is for the future. I want the next generation of developers to be left with a software that reads like a book, not a labyrinth.

Submit "Traipse – Code Structure [Part 1]" to Digg Submit "Traipse – Code Structure [Part 1]" to del.icio.us Submit "Traipse – Code Structure [Part 1]" to StumbleUpon Submit "Traipse – Code Structure [Part 1]" to Google

Updated 01-14-2011 at 07:05 AM by adamx20

Tags: traipse Add / Edit Tags
Categories
//root: , //Traipse:

Comments