Search code examples
python-3.xwxpythonwxgrid

wxpython do action before closing wx.EVT_CLOSE


I have a frame which contains a grid which its rows are filled with data from my api so the user edit the data from grid and I want it to be saved when user close the click the X to close the frame so i'm doing this

title = "Datos"

    def __init__(self,title,parent=None):
        wx.Frame.__init__(self, parent=parent, title=title)
        user=self.get_ser()
        self.Show()
        panel=wx.Panel(self, -1)
        myGrid = gridlib.Grid(panel)
        user_data = json.loads(self.decrypt(self.get_data(user)))
        print(user_data)
        myGrid.CreateGrid(len(user_data), 3)
        
        myGrid.SetColLabelValue(0, "WEB")
        myGrid.SetColLabelValue(1, "USERNAME")
        myGrid.SetColLabelValue(2, "PASSWORD")
        for i in range(0,len(user_data)):
            myGrid.SetCellValue(i, 0, user_data[i]["web"])
            myGrid.SetCellValue(i, 1, user_data[i]["username"])
            myGrid.SetCellValue(i, 2, user_data[i]["password"])
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(myGrid, 1, wx.EXPAND)
        panel.SetSizer(sizer)
        self.SetBackgroundColour(wx.Colour(100,100,100))
        self.Centre()
        self.Show()
        self.Bind(wx.EVT_CLOSE, self.OnClose(myGrid,user_data))
    def OnClose(self, myGrid,user_data):
        dlg = wx.MessageDialog(self, 
            "Do you really want to close this application?",
            "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
        result = dlg.ShowModal()
        dlg.Destroy()
        if result == wx.ID_OK:
            self.savedata(myGrid,user_data)
            self.Destroy()
    def savedata(self, myGrid,user_data):
        for i in range(0,(len(user_data))):
            print(myGrid.GetCellValue(i,0)+" "+myGrid.GetCellValue(i,1)+" "+myGrid.GetCellValue(i,2))

my problem is that the pop up dialog appears when opening the frame and I'm passing myGrid to can read the content of each row when the user close the frame so I can save the data currently i'm printing the data on the console to test it

pop up dialog


now my question is how can I save the data when the user click the X I mean I know how to save the data but I want it when the user close the frame the other question how can I make the grid expand when opening the frame? when it's open I have to resize the frame so the grid expands

opened frame


Solution

    1. You have an errant self.Show at the start of your code.
    2. The EVENT_CLOSE sends an event, so you can't just add stuff to the parameters of the called subroutine (without using lambda)
    3. If you make myGrid a member of the class instance i.e. by declaring it self.myGrid, it is available to query and alter. By declaring it as myGrid it is just a local variable.

    If we put that together, with a mocked up and modified version of your code, we get this:

    import wx
    import wx.grid as gridlib
    
    
    class MainFrame(wx.Frame): 
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title)
            #user=self.get_ser()
            panel=wx.Panel(self, -1)
            self.myGrid = gridlib.Grid(panel)
            #user_data = json.loads(self.decrypt(self.get_data(user)))
            user_data = [["web1","user1","password1"],["web1","user2","password2"],["web3","user3","password3"]]
            print(user_data)
            self.myGrid.CreateGrid(len(user_data), 3)
            
            self.myGrid.SetColLabelValue(0, "WEB")
            self.myGrid.SetColLabelValue(1, "USERNAME")
            self.myGrid.SetColLabelValue(2, "PASSWORD")
            for i in range(0,len(user_data)):
                self.myGrid.SetCellValue(i, 0, user_data[i][0])
                self.myGrid.SetCellValue(i, 1, user_data[i][1])
                self.myGrid.SetCellValue(i, 2, user_data[i][2])
            
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.myGrid, 1, wx.EXPAND)
            panel.SetSizer(sizer)
            self.Bind(wx.EVT_CLOSE, self.OnClose)
            self.SetBackgroundColour(wx.Colour(100,100,100))
            self.Centre()
            self.Show()
    
        def OnClose(self, event):
            dlg = wx.MessageDialog(self, 
                "Do you really want to close this application?",
                "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
            result = dlg.ShowModal()
            dlg.Destroy()
            if result == wx.ID_OK:
                self.savedata()
                self.Destroy()
    
        def savedata(self):
            gr = self.myGrid.GetNumberRows()
            for i in range(0,(gr)):
                print(self.myGrid.GetCellValue(i,0)+" "+self.myGrid.GetCellValue(i,1)+" "+self.myGrid.GetCellValue(i,2))
    
    app = wx.App()
    MainFrame(None, "Data")
    app.MainLoop()
    

    As you can see OnClose accepts an event, the point here is that in this instance, you know where the event is coming from and that it's a Close event.

    The savedata routine, also in this instance, doesn't need to know what to save, there's only myGrid. However, we could have sent the event object if there was any doubt, or called different save routines, for different objects.

    We aren't interested in the original userdata passed to the grid, as it has almost certainly changed, so we query the grid, to know how many rows to check.
    Finally, we can access the data in the grid and save it, or in this case print it out.

    N.B. You might want to consider an option where you abandon the edit and exit. As it stands, it's Save or you are doomed to edit the data for ever.

    enter image description here

    The result of saving:

    web1 user1 password1
    Stackoverflow.com Rodrigo xXx
    web3 user3 password3