Hello guys, I'm trying to make a program that will :
at startup it will give you login Dialog which will connect to database. Then it will bring Main window displaying tables. Then I have Another dialog to do some editing of Tables. Here are my two Questions:

Is it possible to connect to MySQL without specifying database parameter. I ask this because I want users to connect and create their own databases and change which database to work with.

When I call the editing GUI, I hide the main window. But I cannot re-Show the hidden GUI
Here is a code :

import wx
import MySQLdb
#to-do add database + adding window for adding, editing & removing data! + disconnect from database option

class AddData(wx.Dialog):
    def __init__(self, parent, id, title):
        wx.Dialog.__init__(self, parent, id, title, size=(200, 150))
        
        #Add widgets
        prodtext = wx.StaticText(self, -1, "Product")
        prod = wx.TextCtrl(self, -1)
        
        amounttext = wx.StaticText(self, -1, "Amount")
        amount = wx.SpinCtrl(self, -1)
        
        costtext = wx.StaticText(self, -1, "Cost")
        cost = wx.TextCtrl(self, -1)
        
        comit = wx.Button(self, -1, "Commit")
        self.cancel = wx.Button(self, -1, "Cancel")
        #Attach event
        self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.cancel.GetId() )
        
        #Add to sizer
        grids = wx.GridBagSizer(5,5)
        grids.AddMany([(prodtext, (0, 0), (1,1)),
                       (prod, (0,1), (1, 3)),
                       (amounttext, (1,0), (1, 1)),
                       (amount, (1,1), (1,1)),
                       (costtext, (2,0), (1, 1)),
                       (cost, (2,1), (1, 3))                       
        ])
        
        hboxer = wx.BoxSizer(wx.HORIZONTAL)
        hboxer.Add(comit, 0, wx.LEFT | wx.RIGHT, 8)
        hboxer.Add(self.cancel, 0, wx.LEFT | wx.RIGHT, 8)
        
        #Add to main sizer
        msizer = wx.BoxSizer(wx.VERTICAL)
        msizer.Add(grids, 1, wx.EXPAND | wx.ALL, 8)
        msizer.Add(hboxer, 0, wx.TOP | wx.BOTTOM, 8 )
        
        self.SetSizer(msizer)
        self.Layout()
        
        #Events belonging to class
    def OnCancel(self, event):
        self.Show(False)
        hide = True
        
        

class MainWindow(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size = (500, 350))
        
        #Make a panel
        MainPanel = wx.Panel(self, -1)
        #Add widgets to Panneled Frame
        #----------------------------------------
        #Select Database
        #Refresh
        self.refresh = wx.Button(MainPanel, -1, "Refresh")
        #Edit
        self.edit = wx.Button(MainPanel, -1, "Edit")
        #Bind events
        self.Bind(wx.EVT_BUTTON, self.OnEdit, id = self.edit.GetId())
        #Exit 
        self.exit = wx.Button(MainPanel, -1, "Exit")       
        #Caption
        self.dbtitle = wx.StaticText(MainPanel, -1, "Select Database")
        #Database selector
        self.dblist= ["Mtangoo", "Steve", '10'] # Database list
        self.dbselect = wx.ComboBox(MainPanel, -1,  choices=self.dblist)
        #select table
        self.tbtitle = wx.StaticText(MainPanel, -1, "Select Table")
        self.tblist= [] # Table list
        self.tbselect = wx.ComboBox(MainPanel, -1,  choices=self.tblist)        
        #Column titles
        self.col1 = wx.StaticText(MainPanel, -1, "Column 1", style=wx.ALIGN_CENTER)
        self.col2= wx.StaticText(MainPanel, -1, "Column 2", style=wx.ALIGN_CENTER)
        self.col3 = wx.StaticText(MainPanel, -1, "Column 3", style=wx.ALIGN_CENTER)
        #Cells, arranged by rows i.e 1st row cel1, cel2, cel3
        #Row 1
        self.cel1 = wx.TextCtrl(MainPanel, -1)
        self.cel2 = wx.TextCtrl(MainPanel, -1)
        self.cel3 = wx.TextCtrl(MainPanel, -1)
        #Row 2
        self.cel4 = wx.TextCtrl(MainPanel, -1)
        self.cel5 = wx.TextCtrl(MainPanel, -1)
        self.cel6 = wx.TextCtrl(MainPanel, -1)
        #Row 3
        self.cel7 = wx.TextCtrl(MainPanel, -1)
        self.cel8 = wx.TextCtrl(MainPanel, -1)
        self.cel9 = wx.TextCtrl(MainPanel, -1)
        #Row 4
        self.cel10 = wx.TextCtrl(MainPanel, -1)
        self.cel11 = wx.TextCtrl(MainPanel, -1)
        self.cel12 = wx.TextCtrl(MainPanel, -1)
        #-----------------------------------------
        
        #Add to the sizers
        vbox = wx.BoxSizer(wx.VERTICAL)
        #Database & Table selection section
        hboxselect = wx.BoxSizer()
        
        hboxselect.Add(self.dbtitle, 0, wx.LEFT , 10)
        hboxselect.Add(self.dbselect, 1, wx.EXPAND |wx.LEFT | wx.RIGHT, 10)
        hboxselect.Add(self.tbtitle, 0,wx.LEFT , 10)
        hboxselect.Add(self.tbselect, 1, wx.EXPAND |wx.LEFT | wx.RIGHT, 10)
        vbox.Add(hboxselect, 0, wx.ALL, 15)
        vbox.Add((0,15))
        
        #Table titles, depends on the selected table i.e, name of table chosen is displayed!
        self.apptitle = wx.StaticText(MainPanel, -1, "This is table name")
        vbox.Add(self.apptitle, 0,  wx.CENTER)
        vbox.Add((0,15))
        
        #Add to gridsizer (row, col, vgap, hgap)
        gsizer = wx.GridSizer(4, 3, 4, 4)
        gsizer.AddMany([(self.col1, 0, wx.EXPAND) , 
                        (self.col2, 0, wx.EXPAND) , 
                        (self.col3, 0, wx.EXPAND) , 
                        (self.cel1, 0, wx.EXPAND) , 
                        (self.cel2, 0, wx.EXPAND),
                        (self.cel3, 0, wx.EXPAND),
                        (self.cel4, 0, wx.EXPAND),
                        (self.cel5, 0, wx.EXPAND),
                        (self.cel6, 0, wx.EXPAND), 
                        (self.cel7, 0, wx.EXPAND), 
                        (self.cel8, 0, wx.EXPAND), 
                        (self.cel9, 0, wx.EXPAND), 
                        (self.cel10, 0, wx.EXPAND),
                        (self.cel11, 0, wx.EXPAND),
                        (self.cel12, 0, wx.EXPAND)
                        ])
        
        vbox.Add(gsizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 7)
        
        hbox1 = wx.BoxSizer()
        hbox1.Add(self.refresh, 0, wx.LEFT, 10)
        hbox1.Add(self.edit, 0,  wx.RIGHT | wx.LEFT, 10)
        hbox1.Add(self.exit, 0,  wx.RIGHT, 10)
        vbox.Add(hbox1, 0, wx.CENTER |wx.TOP, 15)

        
        #set up sizer
        MainPanel.SetSizer(vbox)
        MainPanel.Layout()
        
        #events for Data edit
    def OnEdit(self, event):
        call = AddData(None, -1, "Please Login for Authentication")
        call.Show(True)
        self.Show(False)
        
        
class Login(wx.Dialog):
    def __init__(self, parent, id, title):
        wx.Dialog.__init__(self, parent, id, title, size = (200, 200))
        #define widgets
        self.nametext = wx.StaticText(self, -1, "User Name")
        self.name = wx.TextCtrl(self, -1)
        
        self.password = wx.TextCtrl(self, -1, style = wx.TE_PASSWORD)
        self.passwordtext = wx.StaticText(self, -1, "Password")
        
        #host
        self.hosttext = wx.StaticText(self, -1, "Database Host")
        host = ["localhost"]
        self.host = wx.ComboBox(self,-1, choices = host)
        #Ok Button
        self.ok = wx.Button(self, -1, "Ok")
        #Bind to event
        self.ok.Bind(wx.EVT_BUTTON, self.OnConnect, id = self.ok.GetId())
        
        #Bind to event
        self.close= wx.Button(self, -1, "Exit")
        self.close.Bind(wx.EVT_BUTTON, self.OnClose, id = self.close.GetId())
        
        #Add to sizer        
        vsizer = wx.BoxSizer(wx.VERTICAL)
        
        vsizer.Add(self.hosttext, 0, wx.TOP | wx.LEFT, 10)        
        vsizer.Add(self.host, 0, wx.ALL, 10)
        
        grid = wx.FlexGridSizer(2, 2, 8, 8)        
        grid.AddMany([(self.nametext, 0, wx.EXPAND | wx.LEFT, 10),
                      (self.name, 0, wx.EXPAND),
                      (self.passwordtext, 0, wx.EXPAND | wx.LEFT, 10),
                      (self.password , 0,wx.EXPAND)
                      ])
                      
        vsizer.Add(grid, 0, wx.EXPAND, wx.ALL, 10)
        
       
        hbutton = wx.BoxSizer()
        hbutton.Add(self.ok, 0, wx.LEFT | wx.TOP, 10)
        hbutton.Add(self.close, 0, wx.LEFT | wx.TOP, 10)
        vsizer.Add(hbutton, 0, wx.EXPAND)
        
        self.SetSizer(vsizer)
        self.Layout()       
        
        
        
        self.Center() 
        self.Show(True)
        
        #Start  Handlers
    def OnConnect(self, event):
        host = self.host.GetValue()
        user = self.name.GetValue()
        passw = self.password.GetValue()
        db =MySQLdb.connect(host , user, passw, db = "sql_book" )# create database choice entry
        call = MainWindow(None, -1, "Elijah Database Manager")
        ret = call.Show()
        self.Destroy()#close the small window left big one to display tables
        
    def OnClose(self, event):
        self.Close()
        

        
#Create our App
app = wx.App(False)
#Instantiate MainWindow class
Login(None, -1, "Please Login for Authentication")
#AddData(None, -1, "Please Add or Edit data")
#Looping our main App
app.MainLoop()

Recommended Answers

All 10 Replies

I think a simple way to do it is give AddData objects a pointer to the main window like this

classAddData(...):
    def __init__(self, parent, id, title, main_window, size = (200, 150)):
        self.main_window = main_window
        ....
    def OnCancel(self):
        ...
        self.main_window.Show(True)

As a constructive criticism of your code, I think you should really define an array for the colums and the cells, and have an acces like self.col[i] and self.cell[i][j] so that many operations can be done with loops!

Do you mean Lists and Dictionaries? I was figuring out how to do it with them. This is the first time I seriously try to program something in python and I wanted to do simple program that will insert as many tables, rows and columns as the user will add but hit a wall on how to add those.

Anyway I'm know simple use of flow control statements (If, while and for ), and have simple knowledge of how to do simple manipulation of Arrays (Lists, tuples and dict.) but I don't know how to make them function in the way you have suggested. I Loved your criticism and would like to reformat code as you suggested. Help me please!

Thanks for help BTW
Steve

Here is how you could do this

class MainWindow(wx.Frame):
    def __init__(...):
        ...
        self.ncols = 3
        self.nrows = 4
        self.create_titles(MainPanel)
        self.create_cells(MainPanel)
        """
        #DROP THIS
        self.col1 = wx.StaticText(MainPanel, -1, "Column 1", style=wx.ALIGN_CENTER)
        self.col2= wx.StaticText(MainPanel, -1, "Column 2", style=wx.ALIGN_CENTER)
        self.col3 = wx.StaticText(MainPanel, -1, "Column 3", style=wx.ALIGN_CENTER)
        #Cells, arranged by rows i.e 1st row cel1, cel2, cel3
        #Row 1
        self.cel1 = wx.TextCtrl(MainPanel, -1)
        self.cel2 = wx.TextCtrl(MainPanel, -1)
        self.cel3 = wx.TextCtrl(MainPanel, -1)
        #Row 2
        self.cel4 = wx.TextCtrl(MainPanel, -1)
        self.cel5 = wx.TextCtrl(MainPanel, -1)
        self.cel6 = wx.TextCtrl(MainPanel, -1)
        #Row 3
        self.cel7 = wx.TextCtrl(MainPanel, -1)
        self.cel8 = wx.TextCtrl(MainPanel, -1)
        self.cel9 = wx.TextCtrl(MainPanel, -1)
        #Row 4
        self.cel10 = wx.TextCtrl(MainPanel, -1)
        self.cel11 = wx.TextCtrl(MainPanel, -1)
        self.cel12 = wx.TextCtrl(MainPanel, -1)
        #-----------------------------------------
        """
        #Add to gridsizer (row, col, vgap, hgap)
        gsizer = wx.GridSizer(self.nrows, self.ncols, 4, 4)
        items = list(self.title)
        for i in range(self.nrows):
            items.extend(self.cell[i])
        gsizer.AddMany([(item, 0, wx.EXPAND) for item in items])
        """
        #DROP THIS
        gsizer.AddMany([(self.col1, 0, wx.EXPAND) , 
                        (self.col2, 0, wx.EXPAND) , 
                        (self.col3, 0, wx.EXPAND) , 
                        (self.cel1, 0, wx.EXPAND) , 
                        (self.cel2, 0, wx.EXPAND),
                        (self.cel3, 0, wx.EXPAND),
                        (self.cel4, 0, wx.EXPAND),
                        (self.cel5, 0, wx.EXPAND),
                        (self.cel6, 0, wx.EXPAND), 
                        (self.cel7, 0, wx.EXPAND), 
                        (self.cel8, 0, wx.EXPAND), 
                        (self.cel9, 0, wx.EXPAND), 
                        (self.cel10, 0, wx.EXPAND),
                        (self.cel11, 0, wx.EXPAND),
                        (self.cel12, 0, wx.EXPAND)
                        ])
        """
    def create_titles(self, MainPanel):
        self.title = []
        for i in range(self.ncols):
            self.title.append(
                wx.StaticText(
                MainPanel, -1, "Column %d" % (i+1), style=wx.ALIGN_CENTER)
            )

    def create_cells(self, MainPanel):
        self.cell = []
        for i in range(self.nrows):
            self.cell.append([]) # add a row
            for j in range(self.ncols):
                self.cell[i].append(wx.TextCtrl(MainPanel, -1))

With this, you can now access the colum titles with self.title[i] where 0 <= i < self.ncols
and you can access the cells with self.cell[i][j] with 0 <=i < self.nrows and 0 <= j < self.ncols.

Thanks alot, the code works but I need to know how to it myself next time and here are my questions:

self.create_titles(MainPanel)
        self.create_cells(MainPanel)
#Why do you have to specify MainPanel in those functions/methods?
#where are arguments for our functions that we are to call?

#now the functions are 
    def create_titles(self, MainPanel):
        self.title = []
        for i in range(self.ncols):
            self.title.append(
                wx.StaticText(
                MainPanel, -1, "Column %d" % (i+1), style=wx.ALIGN_CENTER)
            )


    def create_cells(self, MainPanel):
        self.cell = []
        for i in range(self.nrows):
            self.cell.append([]) # add a row
            for j in range(self.ncols):
                self.cell[i].append(wx.TextCtrl(MainPanel, -1))
#Here you said we add a row, what about a column?
#How  do I bind methods to rows and columns

Back to Main Question of the thread, when I add the code you have provided,
I get this error at edit button click:

Traceback (most recent call last):
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 142, in OnEdit
call = AddData(None, -1, "Please Login for Authentication")
TypeError: __init__() takes at least 5 arguments (4 given)

here is the modified code of AddData class

class AddData(wx.Dialog):
    def __init__(self, parent, id, title, main_window, size = (200, 150)):
        self.main_window = main_window
        
        #Add widgets
        prodtext = wx.StaticText(self, -1, "Product")
        prod = wx.TextCtrl(self, -1)
        
        amounttext = wx.StaticText(self, -1, "Amount")
        amount = wx.SpinCtrl(self, -1)
        
        costtext = wx.StaticText(self, -1, "Cost")
        cost = wx.TextCtrl(self, -1)
        
        comit = wx.Button(self, -1, "Commit")
        self.cancel = wx.Button(self, -1, "Cancel")
        #Attach event
        self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.cancel.GetId() )
        
        #Add to sizer
        grids = wx.GridBagSizer(5,5)
        grids.AddMany([(prodtext, (0, 0), (1,1)),
                       (prod, (0,1), (1, 3)),
                       (amounttext, (1,0), (1, 1)),
                       (amount, (1,1), (1,1)),
                       (costtext, (2,0), (1, 1)),
                       (cost, (2,1), (1, 3))                       
        ])
        
        hboxer = wx.BoxSizer(wx.HORIZONTAL)
        hboxer.Add(comit, 0, wx.LEFT | wx.RIGHT, 8)
        hboxer.Add(self.cancel, 0, wx.LEFT | wx.RIGHT, 8)
        
        #Add to main sizer
        msizer = wx.BoxSizer(wx.VERTICAL)
        msizer.Add(grids, 1, wx.EXPAND | wx.ALL, 8)
        msizer.Add(hboxer, 0, wx.TOP | wx.BOTTOM, 8 )
        
        self.SetSizer(msizer)
        self.Layout()
        
        #Events belonging to class
    def OnCancel(self, event):
        #self.Destroy()
        self.main_window.Show(True)

Thanks Griboullis, this have pushed me far in the python programming knowledge
Steve

For the first question, I specify MainPanel as an argument because the function's body uses the MainPanel ! An alternative would be to keep the MainPanel in the object as a member self.MainPanel . The method could then access this object without a parameter.

For the second question, you must think of self.cell as a list of lists like this

[
    [ wx.TextControl, wx.TextControl, wx.TextControl],
    [ wx.TextControl, wx.TextControl, wx.TextControl],
    [ wx.TextControl, wx.TextControl, wx.TextControl],
    [ wx.TextControl, wx.TextControl, wx.TextControl],
]

I built this like this

initially
[]

I add a row
[[]]

In this row I add an item

[[wx.TextControl]]

another

[[wx.TextControl, wx.TextControl]]

etc, then another row

[
    [wx.TextControl, wx.TextControl, wx.TextControl],
    []
]

etc

For the third question, I forget to mention that you must also add the parameter when you call AddData, so in OnEdit, you should write

call = AddData(None, -1, "Please Login for Authentication", self)

Good luck for your interface with the database. I think it's a lot of work !

I Have tried to replace it but I have this error:
Traceback (most recent call last):
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 142, in OnEdit
call = AddData(None, -1, "Please Login for Authentication", self)
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 10, in __init__
prodtext = wx.StaticText(self, -1, "Product")
File "C:\Python25\Lib\site-packages\wx-2.8-msw-unicode\wx\_controls.py", line 1136, in __init__
_controls_.StaticText_swiginit(self,_controls_.new_StaticText(*args, **kwargs))
TypeError: in method 'new_StaticText', expected argument 1 of type 'wxWindow *'
Traceback (most recent call last):
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 142, in OnEdit
call = AddData(None, -1, "Please Login for Authentication", self)
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 10, in __init__
prodtext = wx.StaticText(self, -1, "Product")
File "C:\Python25\Lib\site-packages\wx-2.8-msw-unicode\wx\_controls.py", line 1136, in __init__
_controls_.StaticText_swiginit(self,_controls_.new_StaticText(*args, **kwargs))
TypeError: in method 'new_StaticText', expected argument 1 of type 'wxWindow *'
Traceback (most recent call last):
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 142, in OnEdit
call = AddData(None, -1, "Please Login for Authentication", self)
File "c:\Users\Elijah Ministries\Documents\NetBeansProjects\Learning Python\src\database - Griboullis.py", line 10, in __init__
prodtext = wx.StaticText(self, -1, "Product")
File "C:\Python25\Lib\site-packages\wx-2.8-msw-unicode\wx\_controls.py", line 1136, in __init__
_controls_.StaticText_swiginit(self,_controls_.new_StaticText(*args, **kwargs))
TypeError: in method 'new_StaticText', expected argument 1 of type 'wxWindow *'

I don't have Idea of what it complains. The static text is well defined, and I think I have done somerhing wrong.

BTW what main_window does? I feel that I have something wrongly arranged especially main_window.
Thanks again
Steve

When you create a subclass, you must initialize the instances of the subclass with the parent's class, so I think your __init__ function for the AddData class should begin like this

class AddData(wx.Dialog):
    def __init__(self, parent, id, title, main_window):
        wx.Dialog.__init__(self, parent, id, title, size=(200, 150))
        ....

I misspelled this in the code I wrote above

Thanks alot,
THE THINGS WENT WELL.
Just to get familiar with the code, why do we define main_window? I mean is it main_window something built in or just custom and can be changed to anything?
why when we included it worked. Is it a that way how to define a parent to any dialog box/frame?

No it's just a trick I used. I want your AddData class to call Show(True) on your main window. For this it must have an access to the main window, so I pass the main window to the AddData object and it stores it as a member main_window. It could have been self.foo instead. It can then call self.main_window.Show(True)

commented: This man have highly helped me.He/She seems to be great in python and very innovative +2

Ok thanks alot,
Appreciate your time taking effort and I value what you added to me. You qualify to teach Python at very high level

Highly Appreciate!
Steve

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.