Hello.

I am making a program that interacts with MySQL database/table. I ran into 2 problems. The first one is about saving data which user entered into cell/or edited existing data in cell. The second problem is about inserting new row. Row is inserted, but it still shows error in background.

Problem number 1 error:
TypeError: OnCellChange() takes exactly 3 arguments (2 given)

Problem number 2 error:
self.data.append((str(row), '', '', '', '', '', '', '', ''))
NameError: global name 'row' is not defined

Here is the code:

import wx
import wx.grid as gridlib
import MySQLdb
import datetime

#Main Grid Class
class MyGrid(gridlib.Grid):
    def __init__(self, parent):
        gridlib.Grid.__init__(self, parent, )

        #-----------------------------------MySQLdb---------------------------------------------------------------------------------------------------------------
        # Get data
        def getData():
            db = MySQLdb.connect("127.0.0.1", "user", "password", "database")
            cursor = db.cursor()
            query = "SELECT * FROM setup"
            cursor.execute(query)
            data = []
            res = cursor.fetchall()
            for i in res:
                data.append(i)
            return data

        #Update table
        def updateTable(idSetup, colname, value):
            db = MySQLdb.connect("127.0.0.1", "user", "password", "database")
            cursor = db.cursor()
            # sql upit
            sql = "UPDATE setup SET " + colname + " = '" + str(value) + "' WHERE idSetup = " + str(idSetup) + ";"
            # izvrsavanje upita
            cursor.execute(sql)
            db.commit()
            db.disconnect()

        #Insert data
        def insert(data):
            db = MySQLdb.connect("127.0.0.1", "user", "password", "database")
            cursor = db.cursor()
            # sql upit
            sql = "INSERT INTO setup(idKomitent, Drzava, Prg, Provajder, ServerName, DataBaseName, Sifarnici, Promena) VALUES (%s, %s, %s, %s, %s, %s, %s, %s);"
            # izvrsavanje upita
            cursor.execute(sql, data)
            db.commit()
            sql = "SELECT LAST_INSERT_ID()"
            cursor.execute(sql)
            result = cursor.fetchall()[0][0]
            db.disconnect()
            return result

        #Delete data
        def delete(idSetup):
            db = MySQLdb.connect("127.0.0.1", "user", "password", "database")
            cursor = db.cursor()
            # sql upit
            sql = "DELETE FROM setup WHERE idSetup = " + str(idSetup) + ";"
            # izvrsavanje upita
            cursor.execute(sql)
            db.commit()
            db.disconnect()

        # -----------------------------------MySQLdb---------------------------------------------------------------------------------------------------------------

        #Column names
        colnames = ["idSetup", "idKomitent", "Drzava", "Prg", "Provajder", "ServerName", "DataBaseName", "Sifarnici",
                    "Promena"]

        #Setup
        data = getData()
        plugins = None
        self.data = data
        self.colnames = colnames
        self.plugins = plugins or {}

        #Number of row
        def GetNumberRed(self):
            return int(len(self.data))

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

        #Number of columns
        def GetNumberCols(self):
            return int(len(self.colnames))

        #Grid setup
        col = GetNumberCols(self)
        row = GetNumberRed(self)
        self.CreateGrid(row, col)
        self.ChangedValue = False
        self.EnableEditing(True)
        self.EnableGridLines(True)
        self.EnableDragGridSize(False)
        self.SetMargins(0, 0)
        self.inner_sizer = wx.BoxSizer(wx.VERTICAL)
        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()

        #Column names
        self.SetColLabelValue(0, "idSetup")
        self.SetColLabelValue(1, "idKomitent")
        self.SetColLabelValue(2, "Drzava")
        self.SetColLabelValue(3, "Prg")
        self.SetColLabelValue(4, "Provajder")
        self.SetColLabelValue(5, "ServerName")
        self.SetColLabelValue(6, "DataBaseName")
        self.SetColLabelValue(7, "Sifarnici")
        self.SetColLabelValue(8, "Promena")

        # Columns
        self.EnableDragColMove(False)
        self.EnableDragColSize(True)
        self.SetColLabelSize(30)
        self.SetColLabelAlignment(wx.ALIGN_CENTER, wx.ALIGN_CENTER)

        # Cell Defaults
        self.SetDefaultCellAlignment(wx.ALIGN_LEFT, wx.ALIGN_TOP)
        self.inner_sizer.Add(self, 1, wx.ALL | wx.EXPAND, 5)

        #Resize of table
        self.SetSizer(self.inner_sizer)
        self.Layout()
        self.inner_sizer.Fit(self)
        self.Bind(wx.EVT_SIZE, self.OnSize)

        #Populating grid whit data from MySQL DB
        for i, seq in enumerate(data):
            for j, v in enumerate(seq):
                if isinstance(v, (int, long,)):
                    v = str(v)
                elif isinstance(v, datetime.datetime):
                    v = v.strftime('%d-%m-%Y')
                try:
                    self.SetCellValue(i, j, v)

                except TypeError:

                    raise RuntimeError(('SetCellValue failed with TypeError', i, j, v))

        def GetValue(self, row, col):
            return str(self.data[row][1].get(self.GetColLabelValue(col), ""))

        def GetRawValue(self, row, col):
            return self.data[row][1].get(self.GetColLabelValue(col), "")

        def SetValue(self, row, col, value):
            self.data[row][1][self.GetColLabelValue(col)] = value

        #Events
        self.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
        self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.OnCellChange)

    # Problem number 1 ---------#---------#---------#---------
    #Here I want to save user imput from cells, which is achieved either by editing cell or entering new data in a new row
    def OnCellChange(self, evt, data):
        if (evt.GetRow() == self.GetNumberRows() - 2) and (evt.GetCol() == 1):
            self.ChangedValue = True
        else:
            evt.Skip()
    #---------#---------#---------#---------
    #Enter key event
    def onKeyDown(self, evt):
        if evt.GetKeyCode() != wx.WXK_RETURN:
            evt.Skip()
            return

        if evt.ControlDown():  # the edit control needs this key
            evt.Skip()
            return

        self.DisableCellEditControl()
        success = self.MoveCursorRight(evt.ShiftDown())

        if not success:
            newRow = self.GetGridCursorRow() + 1

            if newRow < self.GetTable().GetNumberRows():
                self.SetGridCursor(newRow, 0)
                self.MakeCellVisible(newRow, 0)
            else:
                newRow = self.GetGridCursorRow() + 1
                self.appendRow()
                self.SetGridCursor(newRow, 0)
                self.MakeCellVisible(newRow, 0)
                self.ChangedValue = False

    #Adding new row
    def Reset(self):
        """reset the view based on the data in the table.  Call
        this when rows are added or destroyed"""
        self.ResetView(self)
        self.ro_attr = gridlib.GridCellAttr()
        self.ro_attr.SetReadOnly(True)
        self.SetRowAttr(self.GetNumberRows() - 1,self.ro_attr)
        self.ro_attr = gridlib.GridCellAttr()
        self.ro_attr.SetReadOnly(False)
        self.SetRowAttr(self.GetNumberRows() - 2,self.ro_attr)

    def ResetView(self, grid):
        """
        (Grid) -> Reset the grid view.   Call this to
        update the grid if rows and columns have been added or deleted
        """
        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 column rendering plugins
        self._updateColAttrs(grid)

        # 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 = gridlib.GridTableMessage(self, gridlib.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
        grid.ProcessTableMessage(msg)

    def _updateColAttrs(self, grid):
        """
        wx.Grid -> update the column attributes to add the
        appropriate renderer given the column name.  (renderers
        are stored in the self.plugins dictionary)

        Otherwise default to the default renderer.
        """
        col = 0

        for colname in self.colnames:
            attr = gridlib.GridCellAttr()
            if colname in self.plugins:
                renderer = self.plugins[colname](self)

                if renderer.colSize:
                    grid.SetColSize(col, renderer.colSize)

                if renderer.rowSize:
                    grid.SetDefaultRowSize(renderer.rowSize)

                # attr.SetReadOnly(True)
                attr.SetRenderer(renderer)

            grid.SetColAttr(col, attr)
            col += 1

    # Problem number 2 ---------#---------#---------#---------
    # PyCharm repot that there is "Unresolved referenc 'row'"
    def appendRow(self):
        self.AppendRows(1)
        self.data.append((str(row), '', '', '', '', '', '', '', ''))
        self.Reset()
    # ---------#---------#---------

    #Resize grid
    def OnSize(self, event):
        width, height = self.GetClientSizeTuple()
        for col in range (9):
                self.SetColSize(col, width/(9 + 1))
#-----------------------------------------------------------------------------------------------------------------------
#Main Window class
class GlavniProzor(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, parent=None, title = "Editor", size = (500, 1000))
        self.Show()
        self.CenterOnScreen()

        #Panel
        panel = wx.Panel(self)
        mygrid = MyGrid(panel)

        #Box
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(mygrid, 1, wx.EXPAND|wx.ALL)
        panel.SetSizer(sizer)
        sizer.Fit(self)

#Run
if __name__ == "__main__":
    app = wx.App()
    frame = GlavniProzor()
    app.MainLoop()

Anyone have any idea how to solve this.
Thank you.

For problem 1, I think you could remove the 'data' argument in

def OnCellChange(self, evt, data):
    ...

For problem 2, you need to compute the row value that you want to insert, for exemple

    def appendRow(self):
        row = self.GetNumberRows() # + 1 perhaps ?
        self.AppendRows(1)
        self.data.append((str(row), '', '', '', '', '', '', '', ''))
        self.Reset()

Thank you.

As for first problem, its more complex than I thout it is. So I will need to start from scratch.

For second problem, i try to add row = self.GetNumberRows() +1 but got error:

_grid.GridTableMessage_swiginit(self,_grid.new_GridTableMessage(*args, *kwargs))
TypeError: in method 'new_GridTableMessage', expected argument 1 of type 'wxGridTableBase
'

The error message won't suffice, can you post the whole exception traceback printed by python ?

Sure.

Traceback (most recent call last):
  File "C:/Users/******/PycharmProjects/MySQL Setup TE/backpu.py", line 183, in onKeyDown
    self.appendRow()
  File "C:/Users/******/PycharmProjects/MySQL Setup TE/backpu.py", line 273, in appendRow
    self.Reset()
  File "C:/Users/******/PycharmProjects/MySQL Setup TE/backpu.py", line 192, in Reset
    self.ResetView(self)
  File "C:/Users/******/PycharmProjects/MySQL Setup TE/backpu.py", line 218, in ResetView
    msg = gridlib.GridTableMessage(self, addmsg, new - current)
  File "C:\Python27\lib\site-packages\wx-3.0-msw\wx\grid.py", line 1072, in __init__
    _grid.GridTableMessage_swiginit(self,_grid.new_GridTableMessage(*args, **kwargs))
TypeError: in method 'new_GridTableMessage', expected argument 1 of type 'wxGridTableBase *'

Try self.GetTable() instead of self as first argument when you call gridlib.GridTableMessage().

Thx.

I try that, but now add 2 rows, not 1, but do not show any error.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.