PygridTableBase: Not Updating

Hello,

  I'm following the demo code for the Grid_MegaExample and I'm trying to
update the table with new data based on an event. What I want to happen
is for my keyword argument "_file" to change and then for the table to
update based on that new .txt file.

  I get errors when I try to do an event-based change. The program
initializes fine. My big concern is to be able to dynamically change
the name of the text file, query MySQL, then see the new information.
I'm under the assumption that I only need to change my "_file" keyword
argument in the __init__ of my grid, which would then go back up to the
PyGridTableBase. What am I missing? Am I putting the event in the
wrong object (the Frame instead of the Grid)?
  
  I put ALL of the code below so that there wouldn't be any confusion if
I omitted anything. Thanks in advance. ~Telly

···

____________________________________________________________________________

import wx
import wx.grid as gridlib

import MySQLdb

#---------------------------------------------------------------------------

class HugeTable(gridlib.PyGridTableBase):

    def __init__(self, _host='localhost', _user='root',
_passwd='Shellie2', _port=3306, _db='music', _file='1hrdata.txt'):
        gridlib.PyGridTableBase.__init__(self)

        self.odd=gridlib.GridCellAttr()
        self.odd.SetBackgroundColour("sky blue")
        self.even=gridlib.GridCellAttr()
        self.even.SetBackgroundColour("sea green")

        self.db = MySQLdb.connect(host=_host, user=_user,
passwd=_passwd, port=_port, db=_db)
        self.cursor = self.db.cursor()

        self.data = _file
        self.f = open(self.data, "r")
        self.msg = self.f.read()
        self.f.close()

        self.cursor.execute(self.msg)
        #data
        self.sql = self.cursor.fetchall()
        #column data
        self.sql_columns = self.cursor.description

        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()

    def GetAttr(self, row, col, kind):
        attr = [self.even, self.odd][row % 2]
        attr.IncRef()
        return attr

    # This is all it takes to make a custom data table to plug into a
    # wxGrid. There are many more methods that can be overridden, but
    # the ones shown below are the required ones. This table simply
    # provides strings containing the row and column values.

    def GetNumberRows(self):
        return len(self.sql)

    def GetNumberCols(self):
        return len(self.sql_columns[0])

    def IsEmptyCell(self, row, col):
        return False

    def GetValue(self, row, col):
        return self.sql[row][col]

    def SetValue(self, row, col, value):
        self.sql[row][col] = value

    def GetColLabelValue(self, col):
        return str(self.sql_columns[col][0])

    def ResetView(self, grid):

        grid.BeginBatch()

        for current, new, delmsg, addmsg in [
            (self._rows, self.GetNumberRows(),
gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED,
gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
            (self._cols, self.GetNumberCols(),
gridlib.GRIDTABLE_NOTIFY_COLS_DELETED,
gridlib.GRIDTABLE_NOTIFY_COLS_APPENDED),
        ]:

            if new < current:
                msg = gridlib.GridTableMessage(self, delmsg, new,
current-new)
                grid.ProcessTableMessage(msg)
            elif new > current:
                msg = gridlib.GridTableMessage(self, addmsg, new-current)
                grid.ProcessTableMessage(msg)
                self.UpdateValues(grid)

        grid.EndBatch()

        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()

        #update the scrollbars and the displayed part of the grid
        grid.AdjustScrollbars()
        grid.ForceRefresh()

    def UpdateValues(self, grid):
        """Update all displayed values"""
        #This sends an event to the grid table to update all of the values
        msg = Grid.GridTableMessage(self,
Grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
        grid.ProcessTableMessage(msg)

#---------------------------------------------------------------------------

class HugeTableGrid(gridlib.Grid):
    def __init__(self, parent, _host='localhost', _user='root',
_passwd='Shellie2', _port=3306, _db='music',
                 _file='1hrdata.txt'):
        gridlib.Grid.__init__(self, parent, -1)

        self.table = HugeTable(_host, _user, _passwd, _port, _db, _file)

        # The second parameter means that the grid is to take ownership
of the
        # table and will destroy it when done. Otherwise you would need
to keep
        # a reference to it and call it's Destroy method later.
        self.SetTable(self.table, True)
        self.AutoSize()

    def Reset(self):
        """reset the view based on the data in the table. Call
        this when rows are added or destroyed"""
        self.table.ResetView(self)

#---------------------------------------------------------------------------

class TestFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition,
                          wx.Size(750, 500))

        self.Centre()

        menubar = wx.MenuBar()

        menufile = wx.Menu()
        edit = wx.Menu()
        help = wx.Menu()
        menufile.Append(101, "&Refresh", "Refresh the grid.")
        menufile.AppendSeparator()

        quit = wx.MenuItem(menufile, 102, "&Quit", "Quit the program.")
        quit.SetBitmap(wx.Image('stock_exit-16.png',
wx.BITMAP_TYPE_PNG).ConvertToBitmap())
        menufile.AppendItem(quit)

        wx.EVT_MENU(self, 102, self.OnQuit)

        edit.Append(201, 'check test', '', wx.ITEM_RADIO)
        edit.Append(202, 'check test', '', kind = wx.ITEM_CHECK)

        submenu = wx.Menu()
        submenu.Append(301, 'radio test', kind=wx.ITEM_RADIO)

        edit.AppendMenu(203, 'submenu', submenu)

        menubar.Append(menufile, "&File")
        menubar.Append(edit, "&Edit")
        menubar.Append(help, "&Help")

        self.SetMenuBar(menubar)

        self.statusbar = wx.StatusBar(self)
        self.statusbar.SetFieldsCount(2)
        widths = [-2, -1]
        self.statusbar.SetStatusWidths(widths)
        self.SetStatusBar(self.statusbar)

        self.statusbar.SetStatusText("10 Songs", 1)

        splitter1 = wx.SplitterWindow(self, style = wx.SUNKEN_BORDER |
wx.CLIP_CHILDREN)
        self.splitter2 = wx.SplitterWindow(splitter1, style =
wx.SUNKEN_BORDER | wx.CLIP_CHILDREN)

        panel = wx.Panel(self.splitter2, -1, style = wx.NO_BORDER)

        self.treectrl = wx.TreeCtrl(splitter1, 1)
        root = self.treectrl.AddRoot('Sets')
        one_hr = self.treectrl.AppendItem(root, '1 Hour Set')
        two_hr = self.treectrl.AppendItem(root, '2 Hour Set')
        self.treectrl.AppendItem(one_hr, 'A')
        self.treectrl.AppendItem(one_hr, 'B')
        self.treectrl.AppendItem(two_hr, 'A')
        self.treectrl.AppendItem(two_hr, 'B')
        self.treectrl.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=1)

        self.grid = HugeTableGrid(self.splitter2)
        self.grid.Reset()

        self.splitter2.SplitHorizontally(panel, self.grid, -300)
        splitter1.SplitVertically(self.treectrl, self.splitter2, 120)
        splitter1.SetMinimumPaneSize(20)
        self.splitter2.SetMinimumPaneSize(20)

        self.SetIcon(wx.Icon('tipi.ico', wx.BITMAP_TYPE_ICO))

    def OnQuit(self, event):
        self.Close()

    def OnSelChanged(self, event):
        self.grid = HugeTable(self, _file='2hrdataa.txt')
        self.grid.Reset()

#---------------------------------------------------------------------------

if __name__ == '__main__':
    app = wx.App()
    frame = TestFrame(None, -1, 'DJ Suite')
    frame.Show(True)
    app.MainLoop()

Hi Telly,

Telly Williams wrote:

Hello,

  I'm following the demo code for the Grid_MegaExample and I'm trying to
update the table with new data based on an event. What I want to happen
is for my keyword argument "_file" to change and then for the table to
update based on that new .txt file.

  I get errors when I try to do an event-based change. The program
initializes fine. My big concern is to be able to dynamically change
the name of the text file, query MySQL, then see the new information.
I'm under the assumption that I only need to change my "_file" keyword
argument in the __init__ of my grid, which would then go back up to the
PyGridTableBase. What am I missing? Am I putting the event in the
wrong object (the Frame instead of the Grid)?
  

In OnSelChanged you instantiate every time a new instance of HugeTable. I don't think that works, you should just refresh the data in _file (actually in self.data) and then call ResetView.

I don't use MySQL I use Firebird with kinterbasdb and in my equivalent to your HugeTable class I have a method LoadData which quires the database, it then clears self.data and fills it with the new data from the database and then calls ResetView.

Hope this helps
Werner

Werner F. Bruhin wrote:

>In OnSelChanged you instantiate every time a new instance of HugeTable. I don't think that works, ...

Well I always do that in my code, see also the addition to the wiki page "wxPyGridTableBase" that I'll paste here:
  I'm repeatedly setting SetTable(severalDifferentTables) on a wx.grid.Grid, followed by a ForceRefresh(), and it works great for me.
  Is this a limitation that has been removed?

As for Telly Williams code, try calling SetTable() on the grid after reinstantiating HugeTable.

This is the excerpt from the wiki I was pasting:
begin paste:
    I'm repeatedly setting SetTable(severalDifferentTables) on a wx.grid.Grid, followed by a ForceRefresh(), and it works great for me.
    Is this a limitation that has been removed?
end paste

Werner F. Bruhin wrote:

What does one gain by instantiating HugeTable again and again?

I always just refresh the content of myTable (on which I did one SetTable(myTable) during init) and call RefreshView?

You're right on this, I didn't wanted to say that it's wrong, that's perhaps the best way but I have a lot of code where I do the same thing the wiki editor does and I'd like to know the answer to that question.