interacting between modules / classes in wxPython

654 views Asked by At

I have a task of migrating a multi-userframe VBA project with a lot od database interaction into something different - as this must be something that cannot demand installing software (so JRE and .NET are out of the question) I believe this can be done with Python - wxPython covers frames and different controls (I'm using boa-constructor for it's frame designer), I also managed to connect via adodbapi with the current database VBA is using. I just suck at putting it all together properly. Consider this skeleton:

myApp.py

#!/usr/bin/env python
#Boa:App:BoaApp

import wx
import myFrame

modules ={u'myFrame': [1, 'Main frame of Application', u'myFrame.py']}

class BoaApp(wx.App):
    def OnInit(self):
        # here I think I'd see something like, say:
        # self.main.cnnObject = adodbapi.connect ( some proper connection string )
        self.main = myFrame.create(None)
        self.main.Show()
        self.SetTopWindow(self.main)
        return True

def main():
    application = BoaApp(0)
    application.MainLoop()

if __name__ == '__main__':
    main()

myFrame.py

#Boa:Frame:myFrame
import wx

def create(parent):
    return myFrame(parent)

[wxID_MYFRAME, wxID_MYFRAMEBUTTON1, 
] = [wx.NewId() for _init_ctrls in range(2)]

class myFrame(wx.Frame):
    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_MYFRAME, name='myFrame', parent=prnt,
              pos=wx.Point(710, 329), size=wx.Size(400, 250),
              style=wx.DEFAULT_FRAME_STYLE, title='MainFrame')
        self.SetClientSize(wx.Size(392, 223))

        self.button1 = wx.Button(id=wxID_MYFRAMEBUTTON1,
              label='FETCH cnnObject', name='button1', parent=self,
              pos=wx.Point(0, 144), size=wx.Size(392, 79), style=0)
        self.button1.Bind(wx.EVT_BUTTON, self.OnButton1,
              id=wxID_MYFRAMEBUTTON1)

    def __init__(self, parent):
        self._init_ctrls(parent)

    def OnButton1(self, event):
        event.Skip()
        # here and in other events in other frames I would like to retrieve 
        # that cnnObject to use for queries

Adding tons of controls, events, opening consecutive frames from this one and next to come seems to work. However to not have to copy/paste the whole database connection stuff over and over again I wanted to have it all in one place and just access that code from frames. My general idea is that since there's only one myApp object, it could contain the connection object, especially since the connection string will be available as sys.argv[1] Is this possible ? And if so, how would I reference the application object from inside the OnButton1 method ? There's also a chance I have this figured out all wrong, in which case I'd like to hear an outline of the 'right way'. What I feel I may be missing is maybe a proper class wrapper for those database operations, but even If I make one, I'd still like to have only one instance of that class available in all my future frames, yet I can't even manage to do that with the application instance - I import myApp inside myFrame (which itself seems weird as myApp already imports myFrame, so both ways ?) but no matter what type of assignment to a local variable I try, I mostly get a " 'module' object has no attribute " ... (which makes me think I probably don't get how scoping / modules work in Python)

1

There are 1 answers

1
Mike Driscoll On

I wrote a little about this, but I was using SQLAlchemy. This was my first attempt:

Then I received some comments and help from friend in the wxPython community and SQLAlchemy's devs and updated the app a bit:

This second article shows how to create a database session and pass it about. I think that's the approach you are looking for. I would do the database connection in your top level frame's init method:

def __init__(self):
    """Constructor"""
    wx.Frame.__init__(self, None, title="Databases!")

    self.data_connection = self.create_connection()

Then when you create your other frames, you can pass that connection to them:

def create_new_frame(self):
    """"""
    new_frame = MyOtherFrame(self.data_connection)
    new_frame.Show()

Here's one way you could set up your frame class:

########################################################################
class MyOtherFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, data_connection):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Other frame")
        self.data_connection = data_connection

Just make sure you do not close the data connection in your other frame as that will also close it in the original top level frame.

This solution also applies to your OnButton1 call. Just change it so it's like this:

def OnButton1(self, event):
    cursor = self.data_connection.cursor()

You'll notice that you can access self.data_connection anywhere in your main frame because it was defined as a class level variable.

You might also be interested in the Dabo project, which is a wrapper around wxPython that is supposed to make it easier to work with databases: http://www.dabodev.com/