Create a list control and a SQLite database (Phoenix)

Keywords : ListCtrl, SQLite, Database, Data tables, Load, Connect, Select, Insert, Update, Delete, Sort, Highlighted row, Bitmap, Icon, ListCtrlAutoWidthMixin, ColumnSorterMixin, Widget Inspection Tool (WIT).


Demonstrating :

Tested py3.x, wx4.x and Win10.

Are you ready to use some samples ? ;)

Test, modify, correct, complete, improve and share your discoveries ! (!)


Example of database interaction :

First example

img_sample_one.png

To know : for a voluminous database, you must use a virtual list control.

   1 # sample_one.py
   2 
   3 # Authors      : Beppe and Guldo
   4 #                Updated and improved for wxPython Phoenix by Ecco
   5 # Date (d/m/y) : 31/09/2007 (v0.0.1)
   6 #                01/06/2019 (v0.0.2)
   7 # Version      : 0.0.2
   8 # Web          : Python-it.org
   9 # Description  : Shows some wx.ListCtrl utilities.
  10 #                Correct mode for Insert, Update and Delete
  11 #                record in a SQLite 3 database.
  12 #                How to call a function of a frame from
  13 #                another frame.
  14 #                It use Northwind database ah ah ah !!!
  15 #                Enjoy yourself !
  16 
  17 import sys
  18 import os
  19 import time
  20 import sqlite3
  21 import re
  22 import wx
  23 import wx.lib.mixins.inspection
  24 import wx.lib.mixins.listctrl as listmix
  25 
  26 AppTitle = "List of employees"
  27 iEmployees = 0
  28 
  29 # class MyConnection
  30 # class MyInsertDlg
  31 # class MyUpdateDlg
  32 # class MyListCtrl
  33 # class MyFrame
  34 # class MyApp
  35 
  36 #-------------------------------------------------------------------------------
  37 
  38 class MyConnection(object):
  39     """
  40     ...
  41     """
  42     def __init__(self):
  43 
  44         #------------
  45 
  46         # Return database folder.
  47         self.database_dir = wx.GetApp().GetDatabaseDir()
  48 
  49         # Loading "northwind" file.
  50         dbFile = os.path.join(self.database_dir, "northwind.db")
  51 
  52         #------------
  53 
  54         # Create/connect to a permanent file database.
  55         # For temporary testing you can use memory only.
  56         # Open a connection to a DB in RAM :
  57         # self.con = lite.connect(":memory:")
  58         self.con = sqlite3.connect(dbFile, isolation_level=None,
  59                                    detect_types=sqlite3.PARSE_DECLTYPES)
  60 
  61         # Establish the cursor, needed to execute the connected db.
  62         self.cur = self.con.cursor()
  63 
  64         try:
  65             # Create/execute a table (ex : Employees).
  66             self.cur.execute("""CREATE TABLE IF NOT EXISTS Employees (
  67                                              EmployeeID INTEGER PRIMARY KEY,
  68                                              Surname TEXT,
  69                                              Firstname TEXT,
  70                                              Phone TEXT,
  71                                              Email TEXT)
  72                              """)
  73 
  74         except sqlite3.OperationalError:
  75             wx.LogMessage("Can not create the database, "
  76                           "maybe because it already exists ?")
  77             return
  78 
  79         # Important if you make changes to the database commits
  80         # current data to the db file (data is persistant now).
  81         self.con.commit()
  82 
  83     #---------------------------------------------------------------------------
  84 
  85     def OnQuery(self, sSQL):
  86         """
  87         Execute a query passed in the argument from the main frame.
  88         """
  89 
  90         self.cur.execute(sSQL)
  91         # Here create the recordset.
  92         # It's a list of a list...
  93         rsRecordSet = self.cur.fetchall()
  94 
  95         return rsRecordSet
  96 
  97 
  98     def OnQueryParameter(self, sSQL, sParameter):
  99         """
 100         ...
 101         """
 102 
 103         Parameter =(sParameter, )
 104 
 105         self.cur.execute(sSQL, Parameter)
 106         rsRecordSet = self.cur.fetchall()
 107 
 108         return rsRecordSet
 109 
 110 
 111     def OnQueryUpdate(self, sSQL, sParameter):
 112         """
 113         ...
 114         """
 115 
 116         self.cur.execute(sSQL, sParameter)
 117         rsRecordSet = self.cur.fetchall()
 118 
 119         return rsRecordSet
 120 
 121 
 122     def OnSqliteVersion(self):
 123         """
 124         Returns SQLite version.
 125         """
 126 
 127         self.cur.execute("SELECT SQLITE_VERSION()")
 128 
 129         version = self.cur.fetchone()
 130 
 131         return version
 132 
 133 
 134     def OnCloseDb(self):
 135         """
 136         Disconnect database connection.
 137         """
 138 
 139         # Disconnect from server.
 140         self.cur.close()
 141         self.con.close()
 142 
 143 #-------------------------------------------------------------------------------
 144 
 145 class MyInsertDlg(wx.Dialog):
 146     """
 147     ...
 148     """
 149     def __init__(self, caller_dlgInsert, title=""):
 150         wx.Dialog.__init__(self,
 151                            parent=caller_dlgInsert,
 152                            id=-1,
 153                            title="")
 154 
 155         #------------
 156 
 157         self.caller = caller_dlgInsert
 158 
 159         #------------
 160 
 161         # Return icons folder.
 162         self.icons_dir = wx.GetApp().GetIconsDir()
 163 
 164         #------------
 165 
 166         # Simplified init method.
 167         self.ConnectDb()
 168         self.SetProperties()
 169         self.CreateCtrls()
 170         self.BindEvents()
 171         self.DoLayout()
 172 
 173     #---------------------------------------------------------------------------
 174 
 175     def ConnectDb(self):
 176         """
 177         Connection to the database.
 178         """
 179 
 180         # Instance from Class MyConnection.
 181         self.con = MyConnection()
 182 
 183 
 184     def SetProperties(self):
 185         """
 186         Set the frame properties (title, icon, size...).
 187         """
 188 
 189         # Setting some frame properties.
 190         frameIcon = wx.Icon(os.path.join(self.icons_dir,
 191                                          "icon_wxWidgets.ico"),
 192                             type=wx.BITMAP_TYPE_ICO)
 193         self.SetIcon(frameIcon)
 194 
 195 
 196     def CreateCtrls(self):
 197         """
 198         Create some controls for my frame.
 199         """
 200 
 201         # wx.Font(pointSize, family, style, weight, underline, faceName)
 202         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 203         font.SetWeight(wx.BOLD)
 204 
 205         #------------
 206 
 207         # Widgets.
 208         self.panel = wx.Panel(self)
 209 
 210         #--
 211 
 212         self.stSurname = wx.StaticText(self.panel, -1, "Surname :")
 213         self.stSurname.SetForegroundColour("gray")
 214         self.stSurname.SetFont(font)
 215 
 216         self.txSurname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 217 
 218         #--
 219 
 220         self.stFirstname = wx.StaticText(self.panel, -1, "First name :")
 221         self.stFirstname.SetForegroundColour("gray")
 222         self.stFirstname.SetFont(font)
 223 
 224         self.txFirstname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 225 
 226         #--
 227 
 228         message  = "- Max chars : 2."
 229 
 230         self.stPhone = wx.StaticText(self.panel, -1, "Phone :")
 231         self.stPhone.SetForegroundColour("gray")
 232         self.stPhone.SetFont(font)
 233 
 234         self.txPhone1 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 235                                     style=wx.TE_CENTRE)
 236         self.txPhone1.SetMaxLength(2)
 237         self.txPhone1.SetForegroundColour("gray")
 238         self.txPhone1.SetBackgroundColour("yellow")
 239         self.txPhone1.SetFont(font)
 240 
 241         self.hyphen1 = wx.StaticText(self.panel, -1, "-")
 242 
 243         self.txPhone2 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 244                                     style=wx.TE_CENTRE)
 245         self.txPhone2.SetMaxLength(2)
 246 
 247         self.hyphen2 = wx.StaticText(self.panel, -1, "-")
 248 
 249         self.txPhone3 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 250                                     style=wx.TE_CENTRE)
 251         self.txPhone3.SetMaxLength(2)
 252 
 253         self.hyphen3 = wx.StaticText(self.panel, -1, "-")
 254 
 255         self.txPhone4 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 256                                     style=wx.TE_CENTRE)
 257         self.txPhone4.SetMaxLength(2)
 258 
 259         self.hyphen4 = wx.StaticText(self.panel, -1, "-")
 260 
 261         self.txPhone5 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 262                                     style=wx.TE_CENTRE)
 263         self.txPhone5.SetMaxLength(2)
 264 
 265         #--
 266 
 267         self.stEmail = wx.StaticText(self.panel, -1, "Email :")
 268         self.stEmail.SetForegroundColour("gray")
 269         self.stEmail.SetFont(font)
 270 
 271         self.txEmail = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 272 
 273         #--
 274 
 275         self.StaticSizer = wx.StaticBox(self.panel, -1, "")
 276 
 277         #--
 278 
 279         self.bntSave = wx.Button(self.panel, -1, "&Save")
 280         self.bntSave.SetToolTip("Save !")
 281 
 282         self.bntClose = wx.Button(self.panel, -1, "&Close")
 283         self.bntClose.SetToolTip("Close !")
 284 
 285 
 286     def BindEvents(self):
 287         """
 288         Bind all the events related to my frame.
 289         """
 290 
 291         self.txSurname.Bind(wx.EVT_TEXT, self.OnUpperCaseText)
 292         self.txFirstname.Bind(wx.EVT_TEXT, self.OnCapitalizeCaseText)
 293         self.txEmail.Bind(wx.EVT_TEXT, self.OnLowerCaseText)
 294 
 295         self.txPhone1.Bind(wx.EVT_CHAR, self.OnChar)
 296         self.txPhone2.Bind(wx.EVT_CHAR, self.OnChar)
 297         self.txPhone3.Bind(wx.EVT_CHAR, self.OnChar)
 298         self.txPhone4.Bind(wx.EVT_CHAR, self.OnChar)
 299         self.txPhone5.Bind(wx.EVT_CHAR, self.OnChar)
 300 
 301         self.Bind(wx.EVT_BUTTON, self.OnSave, self.bntSave)
 302         self.Bind(wx.EVT_BUTTON, self.OnExit, self.bntClose)
 303 
 304         self.Bind(wx.EVT_CLOSE, self.OnExit)
 305 
 306 
 307     def DoLayout(self):
 308         """
 309         Do layout.
 310         """
 311 
 312         # Sizers.
 313         mainSizer = wx.BoxSizer(wx.HORIZONTAL)
 314         textSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
 315         textSizer.AddGrowableCol(1)
 316 
 317         buttonSizer = wx.StaticBoxSizer(self.StaticSizer, wx.VERTICAL)
 318 
 319         # Assign widgets to sizers.
 320 
 321         # textSizer.
 322         textSizer.Add(self.stSurname, 0, wx.ALIGN_CENTER_VERTICAL)
 323         textSizer.Add(self.txSurname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 324 
 325         textSizer.Add(self.stFirstname, 0, wx.ALIGN_CENTER_VERTICAL)
 326         textSizer.Add(self.txFirstname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 327 
 328         textSizer.Add(self.stPhone, 0, wx.ALIGN_CENTER_VERTICAL)
 329 
 330         ctrlSizer = wx.BoxSizer(wx.HORIZONTAL)
 331         ctrlSizer.Add(self.txPhone1, 1, wx.EXPAND)
 332         ctrlSizer.Add(self.hyphen1, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 333         ctrlSizer.Add(self.txPhone2, 1, wx.EXPAND)
 334         ctrlSizer.Add(self.hyphen2, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 335         ctrlSizer.Add(self.txPhone3, 1, wx.EXPAND)
 336         ctrlSizer.Add(self.hyphen3, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 337         ctrlSizer.Add(self.txPhone4, 1, wx.EXPAND)
 338         ctrlSizer.Add(self.hyphen4, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 339         ctrlSizer.Add(self.txPhone5, 1, wx.EXPAND)
 340 
 341         textSizer.Add(ctrlSizer, 1, wx.EXPAND)
 342         textSizer.Add(self.stEmail, 0, wx.ALIGN_CENTER_VERTICAL)
 343         textSizer.Add(self.txEmail, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 344 
 345         # buttonSizer.
 346         buttonSizer.Add(self.bntSave)
 347         buttonSizer.Add((5, 5), -1)
 348         buttonSizer.Add(self.bntClose)
 349 
 350         # Assign to mainSizer the other sizers.
 351         mainSizer.Add(textSizer, 0, wx.ALL, 10)
 352         mainSizer.Add(buttonSizer, 0, wx.ALL, 10)
 353 
 354         # Assign to panel the mainSizer.
 355         self.panel.SetSizer(mainSizer)
 356         mainSizer.Fit(self)
 357         mainSizer.SetSizeHints(self)
 358 
 359 
 360     def FieldsControl(self):
 361         """
 362         ...
 363         """
 364 
 365         if len(self.txSurname.GetValue()) == 0:
 366                 wx.MessageBox('ATTENTION !\nThe "Surname" field is empty !',
 367                               AppTitle,
 368                               wx.OK | wx.ICON_INFORMATION)
 369 
 370                 self.txSurname.SetFocus()
 371 
 372                 return 0
 373 
 374         elif len(self.txFirstname.GetValue()) == 0:
 375                 wx.MessageBox('ATTENTION !\nThe "First name" field is empty !',
 376                               AppTitle,
 377                               wx.OK | wx.ICON_INFORMATION)
 378 
 379                 return 0
 380 
 381         elif len(self.txPhone1.GetValue()) < 2:
 382                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 383                               "Phone number",
 384                               wx.OK | wx.ICON_INFORMATION)
 385 
 386                 return 0
 387 
 388         elif len(self.txPhone2.GetValue()) < 2:
 389                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 390                               "Phone number",
 391                               wx.OK | wx.ICON_INFORMATION)
 392 
 393                 return 0
 394 
 395         elif len(self.txPhone3.GetValue()) < 2:
 396                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 397                               "Phone number",
 398                               wx.OK | wx.ICON_INFORMATION)
 399 
 400                 return 0
 401 
 402         elif len(self.txPhone4.GetValue()) < 2:
 403                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 404                               "Phone number",
 405                               wx.OK | wx.ICON_INFORMATION)
 406 
 407                 return 0
 408 
 409         elif len(self.txPhone5.GetValue()) < 2:
 410                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 411                               "Phone number",
 412                               wx.OK | wx.ICON_INFORMATION)
 413 
 414                 return 0
 415 
 416         elif len(self.txEmail.GetValue()) == 0:
 417                 wx.MessageBox('ATTENTION !\nThe "Email" field is empty !',
 418                               AppTitle,
 419                               wx.OK | wx.ICON_INFORMATION)
 420 
 421                 return 0
 422 
 423 
 424     def OnSave(self, event):
 425         """
 426         ...
 427         """
 428 
 429         if self.FieldsControl() == 0:
 430 
 431             return
 432 
 433         else:
 434             sMessage = "Save new employee data ?"
 435             dlgAsk = wx.MessageDialog(None,
 436                                       sMessage,
 437                                       AppTitle,
 438                                       wx.YES_NO | wx.ICON_QUESTION)
 439 
 440             retCode = dlgAsk.ShowModal()
 441 
 442             if (retCode == wx.ID_YES):
 443                 sSurname = str(self.txSurname.GetValue())
 444                 sFirstname = str(self.txFirstname.GetValue())
 445                 #--
 446                 value1 = str(self.txPhone1.GetValue())
 447                 value2 = str(self.txPhone2.GetValue())
 448                 value3 = str(self.txPhone3.GetValue())
 449                 value4 = str(self.txPhone4.GetValue())
 450                 value5 = str(self.txPhone5.GetValue())
 451                 number = value1 + value2 + value3 + value4 + value5
 452                 sPhone = self.AddHyphens(number)
 453                 #--
 454                 sEmail = str(self.txEmail.GetValue())
 455 
 456                 InsertParameters = (sSurname,
 457                                     sFirstname,
 458                                     sPhone,
 459                                     sEmail)
 460 
 461                 sSQL = "INSERT INTO Employees (Surname, \
 462                                                Firstname, \
 463                                                Phone, \
 464                                                Email) \
 465                                        VALUES (?, ?, ?, ?)"
 466 
 467                 # Insert new data in the database.
 468                 self.con.OnQueryUpdate(sSQL, InsertParameters)
 469 
 470                 # Guldo... thank you !
 471                 self.caller.OnUpdateList()
 472 
 473                 wx.MessageBox("New data insert !",
 474                               AppTitle,
 475                               wx.OK | wx.ICON_INFORMATION)
 476 
 477             elif (retCode == wx.ID_NO):
 478                 wx.MessageBox("Insert operation aborted !",
 479                               AppTitle,
 480                               wx.OK | wx.ICON_INFORMATION)
 481 
 482             dlgAsk.Destroy()
 483             self.OnExit(self)
 484 
 485 
 486     def OnUpperCaseText(self, event):
 487         """
 488         ...
 489         """
 490 
 491         # Write in upper mode on widgets the call it.
 492         # Adapted from a script of David Hughes
 493         # Forestfield Software.
 494         # Retrive the widget.
 495         wdgControl = event.GetEventObject()
 496 
 497         # Retrive what we have write.
 498         retValue = wdgControl.GetValue()
 499 
 500         # Upper it.
 501         upValue = retValue.upper()
 502 
 503         if retValue != upValue:
 504             wdgControl.SetValue(upValue)
 505             # Insert it at the end.
 506             wdgControl.SetInsertionPointEnd()
 507 
 508         event.Skip()
 509 
 510 
 511     def OnLowerCaseText(self, event):
 512         """
 513         ...
 514         """
 515 
 516         # Write in lower mode on widgets the call it.
 517         # Adapted from a script of David Hughes
 518         # Forestfield Software.
 519         # Retrive the widget.
 520         wdgControl = event.GetEventObject()
 521 
 522         # Retrive what we have write.
 523         retValue = wdgControl.GetValue()
 524 
 525         # Lower it.
 526         upValue = retValue.lower()
 527 
 528         if retValue != upValue:
 529             wdgControl.SetValue(upValue)
 530             # Insert it at the end.
 531             wdgControl.SetInsertionPointEnd()
 532 
 533         event.Skip()
 534 
 535 
 536     def OnCapitalizeCaseText(self, event):
 537         """
 538         ...
 539         """
 540 
 541         # Write in capitalize mode on widgets the call it.
 542         # Adapted from a script of David Hughes
 543         # Forestfield Software.
 544         # Retrive the widget.
 545         wdgControl = event.GetEventObject()
 546 
 547         # Retrive what we have write.
 548         retValue = wdgControl.GetValue()
 549 
 550         # Capitalize it.
 551         upValue = retValue.lower().capitalize()
 552 
 553         if retValue != upValue:
 554             wdgControl.SetValue(upValue)
 555             # Insert it at the end.
 556             wdgControl.SetInsertionPointEnd()
 557 
 558         event.Skip()
 559 
 560 
 561     def OnChar(self, event):
 562         """
 563         Block non numbers.
 564         """
 565 
 566         # print("\ndef OnChar")
 567 
 568         key_code = event.GetKeyCode()
 569 
 570         # Allow ASCII numerics.
 571         if ord('0') <= key_code <= ord('9'):
 572             event.Skip()
 573             return
 574 
 575         # Allow decimal points.
 576         if key_code == ord('.'):
 577             event.Skip()
 578             return
 579 
 580         # Allow tabs, for tab navigation between TextCtrls.
 581         if key_code == ord('\t'):
 582             event.Skip()
 583             return
 584 
 585         # Enable backspace, del, left-right.
 586         # The values may be platform dependent.
 587         if key_code in (8, 127, 314, 316):
 588             event.Skip()
 589             return
 590 
 591         # Block everything else.
 592         return
 593 
 594 
 595     def AddHyphens(self, nb):
 596         """
 597         ...
 598         """
 599 
 600         phone = nb[0:2] + '-' + nb[2:4] + '-' + nb[4:6] + '-' + nb[6:8] + '-' + nb[8:10]
 601 
 602         return phone
 603 
 604 
 605     def OnExit(self, event):
 606         """
 607         ...
 608         """
 609 
 610         self.Destroy()
 611 
 612 #-------------------------------------------------------------------------------
 613 
 614 class MyUpdateDlg(wx.Dialog):
 615     """
 616     ...
 617     """
 618     def __init__(self, caller_dlgUpdate, title=""):
 619         wx.Dialog.__init__(self,
 620                            parent=caller_dlgUpdate,
 621                            id=-1,
 622                            title=title,
 623                            size=(400, 200))
 624 
 625         #------------
 626 
 627         self.caller = caller_dlgUpdate
 628 
 629         #------------
 630 
 631         # Return icons folder.
 632         self.icons_dir = wx.GetApp().GetIconsDir()
 633 
 634         #------------
 635 
 636         # Simplified init method.
 637         self.ConnectDb()
 638         self.SetProperties()
 639         self.CreateCtrls()
 640         self.BindEvents()
 641         self.DoLayout()
 642 
 643     #---------------------------------------------------------------------------
 644 
 645     def ConnectDb(self):
 646         """
 647         Connection to the database.
 648         """
 649 
 650         # Instance from Class MyConnection.
 651         self.con = MyConnection()
 652 
 653 
 654     def SetProperties(self):
 655         """
 656         Set the frame properties (title, icon, size...).
 657         """
 658 
 659         # Setting some frame properties.
 660         frameIcon = wx.Icon(os.path.join(self.icons_dir,
 661                                          "icon_wxWidgets.ico"),
 662                             type=wx.BITMAP_TYPE_ICO)
 663         self.SetIcon(frameIcon)
 664 
 665 
 666     def CreateCtrls(self):
 667         """
 668         Create some controls for my frame.
 669         """
 670 
 671         # wx.Font(pointSize, family, style, weight, underline, faceName)
 672         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 673         font.SetWeight(wx.BOLD)
 674 
 675         #------------
 676 
 677         # Widgets.
 678         self.panel = wx.Panel(self)
 679 
 680         #--
 681 
 682         self.stEmployeeID = wx.StaticText(self.panel, -1, "ID :")
 683         self.stEmployeeID.SetForegroundColour("red")
 684         self.stEmployeeID.SetFont(font)
 685 
 686         self.txEmployeeID = wx.TextCtrl(self.panel, -1, "", size=(230, -1),
 687                                         style=wx.TE_READONLY | wx.TE_CENTRE)
 688         self.txEmployeeID.SetForegroundColour("white")
 689         self.txEmployeeID.SetBackgroundColour("#CD5C5C")
 690         self.txEmployeeID.SetFont(font)
 691 
 692         #--
 693 
 694         self.stSurname = wx.StaticText(self.panel, -1, "Surname :")
 695         self.stSurname.SetForegroundColour("gray")
 696         self.stSurname.SetFont(font)
 697 
 698         self.txSurname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 699 
 700         #--
 701 
 702         self.stFirstname = wx.StaticText(self.panel, -1, "First name :")
 703         self.stFirstname.SetForegroundColour("gray")
 704         self.stFirstname.SetFont(font)
 705 
 706         self.txFirstname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 707 
 708         #--
 709 
 710         self.stPhone = wx.StaticText(self.panel, -1, "Phone :")
 711         self.stPhone.SetForegroundColour("gray")
 712         self.stPhone.SetFont(font)
 713 
 714         self.txPhone1 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 715                                     style=wx.TE_CENTRE)
 716         self.txPhone1.SetMaxLength(2)
 717         self.txPhone1.SetForegroundColour("gray")
 718         self.txPhone1.SetBackgroundColour("yellow")
 719         self.txPhone1.SetFont(font)
 720 
 721         self.hyphen1 = wx.StaticText(self.panel, -1, "-")
 722 
 723         self.txPhone2 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 724                                     style=wx.TE_CENTRE)
 725         self.txPhone2.SetMaxLength(2)
 726 
 727         self.hyphen2 = wx.StaticText(self.panel, -1, "-")
 728 
 729         self.txPhone3 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 730                                     style=wx.TE_CENTRE)
 731         self.txPhone3.SetMaxLength(2)
 732 
 733         self.hyphen3 = wx.StaticText(self.panel, -1, "-")
 734 
 735         self.txPhone4 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 736                                     style=wx.TE_CENTRE)
 737         self.txPhone4.SetMaxLength(2)
 738 
 739         self.hyphen4 = wx.StaticText(self.panel, -1, "-")
 740 
 741         self.txPhone5 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 742                                     style=wx.TE_CENTRE)
 743         self.txPhone5.SetMaxLength(2)
 744 
 745         #--
 746 
 747         self.stEmail = wx.StaticText(self.panel, -1, "Email :")
 748         self.stEmail.SetForegroundColour("gray")
 749         self.stEmail.SetFont(font)
 750 
 751         self.txEmail = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 752 
 753         #--
 754 
 755         self.StaticSizer = wx.StaticBox(self.panel, -1,"")
 756 
 757         #--
 758 
 759         self.bntSave = wx.Button(self.panel, -1, "&Save")
 760         self.bntSave.SetToolTip("Save !")
 761 
 762         self.bntClose = wx.Button(self.panel, -1, "&Close")
 763         self.bntClose.SetToolTip("Close !")
 764 
 765 
 766 
 767     def BindEvents(self):
 768         """
 769         Bind all the events related to my frame.
 770         """
 771 
 772         self.txSurname.Bind(wx.EVT_TEXT, self.OnUpperCaseText)
 773         self.txFirstname.Bind(wx.EVT_TEXT, self.OnCapitalizeCaseText)
 774         self.txEmail.Bind(wx.EVT_TEXT, self.OnLowerCaseText)
 775 
 776         self.txPhone1.Bind(wx.EVT_CHAR, self.OnChar)
 777         self.txPhone2.Bind(wx.EVT_CHAR, self.OnChar)
 778         self.txPhone3.Bind(wx.EVT_CHAR, self.OnChar)
 779         self.txPhone4.Bind(wx.EVT_CHAR, self.OnChar)
 780         self.txPhone5.Bind(wx.EVT_CHAR, self.OnChar)
 781 
 782         self.Bind(wx.EVT_BUTTON, self.OnSave, self.bntSave)
 783         self.Bind(wx.EVT_BUTTON, self.OnExit, self.bntClose)
 784 
 785         self.Bind(wx.EVT_CLOSE, self.OnExit)
 786 
 787 
 788     def DoLayout(self):
 789         """
 790         Do layout.
 791         """
 792 
 793         # Sizers.
 794         mainSizer = wx.BoxSizer(wx.HORIZONTAL)
 795         textSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
 796         textSizer.AddGrowableCol(1)
 797 
 798         buttonSizer = wx.StaticBoxSizer(self.StaticSizer, wx.VERTICAL)
 799 
 800         # Assign widgets to sizers.
 801 
 802         # textSizer.
 803         textSizer.Add(self.stEmployeeID, 0, wx.ALIGN_CENTER_VERTICAL)
 804         textSizer.Add(self.txEmployeeID, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 805 
 806         textSizer.Add(self.stSurname, 0, wx.ALIGN_CENTER_VERTICAL)
 807         textSizer.Add(self.txSurname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 808 
 809         textSizer.Add(self.stFirstname, 0, wx.ALIGN_CENTER_VERTICAL)
 810         textSizer.Add(self.txFirstname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 811 
 812         textSizer.Add(self.stPhone, 0, wx.ALIGN_CENTER_VERTICAL)
 813 
 814         ctrlSizer = wx.BoxSizer(wx.HORIZONTAL)
 815         ctrlSizer.Add(self.txPhone1, 1, wx.EXPAND)
 816         ctrlSizer.Add(self.hyphen1, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 817         ctrlSizer.Add(self.txPhone2, 1, wx.EXPAND)
 818         ctrlSizer.Add(self.hyphen2, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 819         ctrlSizer.Add(self.txPhone3, 1, wx.EXPAND)
 820         ctrlSizer.Add(self.hyphen3, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 821         ctrlSizer.Add(self.txPhone4, 1, wx.EXPAND)
 822         ctrlSizer.Add(self.hyphen4, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 823         ctrlSizer.Add(self.txPhone5, 1, wx.EXPAND)
 824 
 825         textSizer.Add(ctrlSizer, 1, wx.EXPAND)
 826 
 827         textSizer.Add(self.stEmail, 0, wx.ALIGN_CENTER_VERTICAL)
 828         textSizer.Add(self.txEmail, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 829 
 830         # buttonSizer.
 831         buttonSizer.Add(self.bntSave)
 832         buttonSizer.Add((5, 5), -1)
 833         buttonSizer.Add(self.bntClose)
 834 
 835         # Assign to mainSizer the other sizers.
 836         mainSizer.Add(textSizer, 0, wx.ALL, 10)
 837         mainSizer.Add(buttonSizer, 0, wx.ALL, 10)
 838 
 839         # Assign to panel the mainSizer.
 840         self.panel.SetSizer(mainSizer)
 841         mainSizer.Fit(self)
 842         mainSizer.SetSizeHints(self)
 843 
 844 
 845     def FieldsControl(self):
 846         """
 847         ...
 848         """
 849 
 850         if len(self.txSurname.GetValue()) == 0:
 851                 wx.MessageBox('ATTENTION !\nThe "Surname" field is empty !',
 852                               AppTitle,
 853                               wx.OK | wx.ICON_INFORMATION)
 854 
 855                 self.txSurname.SetFocus()
 856 
 857                 return 0
 858 
 859         elif len(self.txFirstname.GetValue()) == 0:
 860                 wx.MessageBox('ATTENTION !\nThe "First name" field is empty !',
 861                               AppTitle,
 862                               wx.OK | wx.ICON_INFORMATION)
 863 
 864                 return 0
 865 
 866         elif len(self.txPhone1.GetValue()) < 2:
 867                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 868                               "Phone number",
 869                               wx.OK | wx.ICON_INFORMATION)
 870 
 871                 return 0
 872 
 873         elif len(self.txPhone2.GetValue()) < 2:
 874                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 875                               "Phone number",
 876                               wx.OK | wx.ICON_INFORMATION)
 877 
 878                 return 0
 879 
 880         elif len(self.txPhone3.GetValue()) < 2:
 881                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 882                               "Phone number",
 883                               wx.OK | wx.ICON_INFORMATION)
 884 
 885                 return 0
 886 
 887         elif len(self.txPhone4.GetValue()) < 2:
 888                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 889                               "Phone number",
 890                               wx.OK | wx.ICON_INFORMATION)
 891 
 892                 return 0
 893 
 894         elif len(self.txPhone5.GetValue()) < 2:
 895                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 896                               "Phone number",
 897                               wx.OK | wx.ICON_INFORMATION)
 898 
 899                 return 0
 900 
 901         elif len(self.txEmail.GetValue()) == 0:
 902                 wx.MessageBox('ATTENTION !\nThe "Email" field is empty !',
 903                               AppTitle,
 904                               wx.OK | wx.ICON_INFORMATION)
 905 
 906                 return 0
 907 
 908 
 909     def OnSave(self, event):
 910         """
 911         ...
 912         """
 913 
 914         if self.FieldsControl()==0:
 915 
 916             return
 917 
 918         else:
 919             sMessage = "Save update data?"
 920             dlgAsk = wx.MessageDialog(None,
 921                                       sMessage,
 922                                       AppTitle,
 923                                       wx.YES_NO | wx.ICON_QUESTION)
 924 
 925             retCode = dlgAsk.ShowModal()
 926 
 927             if (retCode == wx.ID_YES):
 928 
 929                 sEmployeeID = str(self.txEmployeeID.GetValue())
 930                 sSurname = str(self.txSurname.GetValue())
 931                 sFirstname = str(self.txFirstname.GetValue())
 932                 #--
 933                 value1 = str(self.txPhone1.GetValue())
 934                 value2 = str(self.txPhone2.GetValue())
 935                 value3 = str(self.txPhone3.GetValue())
 936                 value4 = str(self.txPhone4.GetValue())
 937                 value5 = str(self.txPhone5.GetValue())
 938                 number = value1 + value2 + value3 + value4 + value5
 939                 sPhone = self.AddHyphens(number)
 940                 #--
 941                 sEmail = str(self.txEmail.GetValue())
 942 
 943                 UpdateParameters = (sSurname,
 944                                     sFirstname,
 945                                     sPhone,
 946                                     sEmail,
 947                                     sEmployeeID)
 948 
 949                 sSQL = "UPDATE Employees SET Surname = ?, \
 950                                              Firstname = ?, \
 951                                              Phone = ?, \
 952                                              Email = ? \
 953                                        WHERE EmployeeID = ?"
 954 
 955                 # Update the database.
 956                 self.con.OnQueryUpdate(sSQL, UpdateParameters)
 957 
 958                 # Guldo... thank you !
 959                 self.caller.OnUpdateList()
 960 
 961                 wx.MessageBox("Data update!",
 962                               AppTitle,
 963                               wx.OK | wx.ICON_INFORMATION)
 964 
 965             elif (retCode == wx.ID_NO):
 966                 wx.MessageBox("Update operation aborted!",
 967                               AppTitle,
 968                               wx.OK | wx.ICON_INFORMATION)
 969 
 970             dlgAsk.Destroy()
 971             self.OnExit(self)
 972 
 973 
 974     def OnUpperCaseText(self, event):
 975         """
 976         ...
 977         """
 978 
 979         # Write in upper mode on widgets the call it.
 980         # Adapted from a script of David Hughes
 981         # Forestfield Software.
 982         # Retrive the widget.
 983         wdgControl = event.GetEventObject()
 984 
 985         # Retrive what we have write.
 986         retValue = wdgControl.GetValue()
 987 
 988         # Upper it.
 989         upValue = retValue.upper()
 990 
 991         if retValue != upValue:
 992             wdgControl.SetValue(upValue)
 993             # Insert it at the end.
 994             wdgControl.SetInsertionPointEnd()
 995 
 996         event.Skip()
 997 
 998 
 999     def OnLowerCaseText(self, event):
1000         """
1001         ...
1002         """
1003 
1004         # Write in upper mode on widgets the call it.
1005         # Adapted from a script of David Hughes
1006         # Forestfield Software.
1007         # Retrive the widget.
1008         wdgControl = event.GetEventObject()
1009 
1010         # Retrive what we have write.
1011         retValue = wdgControl.GetValue()
1012 
1013         # Upper it.
1014         upValue = retValue.lower()
1015 
1016         if retValue != upValue:
1017             wdgControl.SetValue(upValue)
1018             # Insert it at the end.
1019             wdgControl.SetInsertionPointEnd()
1020 
1021         event.Skip()
1022 
1023 
1024     def OnCapitalizeCaseText(self, event):
1025         """
1026         ...
1027         """
1028 
1029         # Write in upper mode on widgets the call it.
1030         # Adapted from a script of David Hughes
1031         # Forestfield Software.
1032         # Retrive the widget.
1033         wdgControl = event.GetEventObject()
1034 
1035         # Retrive what we have write.
1036         retValue = wdgControl.GetValue()
1037 
1038         # Upper it.
1039         upValue = retValue.lower().capitalize()
1040 
1041         if retValue != upValue:
1042             wdgControl.SetValue(upValue)
1043             # Insert it at the end.
1044             wdgControl.SetInsertionPointEnd()
1045 
1046         event.Skip()
1047 
1048 
1049     def OnChar(self, event):
1050         """
1051         Block non numbers.
1052         """
1053 
1054         # print("\ndef OnChar")
1055 
1056         key_code = event.GetKeyCode()
1057 
1058         # Allow ASCII numerics.
1059         if ord('0') <= key_code <= ord('9'):
1060             event.Skip()
1061             return
1062 
1063         # Allow decimal points.
1064         if key_code == ord('.'):
1065             event.Skip()
1066             return
1067 
1068         # Allow tabs, for tab navigation between TextCtrls.
1069         if key_code == ord('\t'):
1070             event.Skip()
1071             return
1072 
1073         # Enable backspace, del, left-right.
1074         # The values may be platform dependent.
1075         if key_code in (8, 127, 314, 316):
1076             event.Skip()
1077             return
1078 
1079         # Block everything else.
1080         return
1081 
1082 
1083     def AddHyphens(self, nb):
1084         """
1085         ...
1086         """
1087 
1088         phone = nb[0:2] + '-' + nb[2:4] + '-' + nb[4:6] + '-' + nb[6:8] + '-' + nb[8:10]
1089 
1090         return phone
1091 
1092 
1093     def OnExit(self, event):
1094         """
1095         ...
1096         """
1097 
1098         self.Destroy()
1099 
1100 #-------------------------------------------------------------------------------
1101 
1102 class MyListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
1103     """
1104     ...
1105     """
1106     def __init__(self, parent, id, pos=wx.DefaultPosition,
1107                  size=wx.DefaultSize, style=0):
1108         super(MyListCtrl, self).__init__(parent, id, pos, size, style)
1109 
1110         #------------
1111 
1112         listmix.ListCtrlAutoWidthMixin.__init__(self)
1113 
1114         #------------
1115 
1116         # Simplified init method.
1117         self.CreateColumns()
1118         self.SetProperties()
1119 
1120     #---------------------------------------------------------------------------
1121 
1122     def CreateColumns(self):
1123         """
1124         Create columns for listCtrl.
1125         """
1126 
1127         # Add some columns (x4).
1128         self.InsertColumn(col=0,  heading="ID", format=wx.LIST_FORMAT_LEFT)
1129         self.InsertColumn(col=1,  heading="Surname", format=wx.LIST_FORMAT_LEFT)
1130         self.InsertColumn(col=2,  heading="First name", format=wx.LIST_FORMAT_LEFT)
1131         self.InsertColumn(col=3,  heading="Phone", format=wx.LIST_FORMAT_LEFT)
1132         self.InsertColumn(col=4,  heading="Email", format=wx.LIST_FORMAT_LEFT)
1133 
1134         #------------
1135 
1136         # Set the width of the columns (x4).
1137         # Integer, wx.LIST_AUTOSIZE or wx.LIST_AUTOSIZE_USEHEADER.
1138         self.SetColumnWidth(col=0,  width=50)
1139         self.SetColumnWidth(col=1,  width=130)
1140         self.SetColumnWidth(col=2,  width=130)
1141         self.SetColumnWidth(col=3,  width=110)
1142         self.SetColumnWidth(col=4,  width=2000)
1143 
1144 
1145     def SetProperties(self):
1146         """
1147         Set the list control properties (icon, font, size...).
1148         """
1149 
1150         # Font size and style for listCtrl.
1151         fontSize = self.GetFont().GetPointSize()
1152 
1153         # Text attributes for columns title.
1154         # wx.Font(pointSize, family, style, weight, underline, faceName)
1155         if wx.Platform in ["__WXMAC__", "__WXGTK__"]:
1156             boldFont = wx.Font(fontSize-1,
1157                                wx.DEFAULT,
1158                                wx.NORMAL,
1159                                wx.NORMAL,
1160                                False, "")
1161             self.SetForegroundColour("black")
1162             self.SetBackgroundColour("#ece9d8")   #ecf3fd
1163 
1164         else:
1165             boldFont = wx.Font(fontSize,
1166                                wx.DEFAULT,
1167                                wx.NORMAL,
1168                                wx.BOLD,
1169                                False, "")
1170             self.SetForegroundColour("#808080")
1171             self.SetBackgroundColour("#ece9d8")   #ecf3fd
1172 
1173         self.SetFont(boldFont)
1174 
1175 #-------------------------------------------------------------------------------
1176 
1177 class MyFrame(wx.Frame):
1178     """
1179     ...
1180     """
1181     def __init__(self, parent, id, title,
1182                  style=wx.DEFAULT_FRAME_STYLE |
1183                        wx.NO_FULL_REPAINT_ON_RESIZE |
1184                        wx.CLIP_CHILDREN):
1185         super(MyFrame, self).__init__(parent=None,
1186                                           id=-1,
1187                                           title=title,
1188                                           style=style)
1189 
1190         #------------
1191 
1192         # Returns application name.
1193         self.app_name = wx.GetApp().GetAppName()
1194         # Returns bitmaps folder.
1195         self.bitmaps_dir = wx.GetApp().GetBitmapsDir()
1196         # Returns icons folder.
1197         self.icons_dir = wx.GetApp().GetIconsDir()
1198 
1199         #------------
1200 
1201         # Simplified init method.
1202         self.ConnectDb()
1203         self.SetProperties()
1204         self.MakeMenuBar()
1205         self.MakeStatusBar()
1206         self.CreateCtrls()
1207         self.BindEvents()
1208         self.DoLayout()
1209 
1210         #------------
1211 
1212         # Clock.
1213         self.OnTimer(None)
1214 
1215         self.timer = wx.Timer(self)
1216         self.timer.Start(3000)
1217         self.Bind(wx.EVT_TIMER, self.OnTimer)
1218 
1219     #---------------------------------------------------------------------------
1220 
1221     def ConnectDb(self):
1222         """
1223         Connection to the database.
1224         """
1225 
1226         # Instance from Class MyConnection.
1227         self.con = MyConnection()
1228 
1229 
1230     def SetProperties(self):
1231         """
1232         Set the frame properties (title, icon, size...).
1233         """
1234 
1235         # Setting some frame properties.
1236         frameIcon = wx.Icon(os.path.join(self.icons_dir,
1237                                          "icon_wxWidgets.ico"),
1238                             type=wx.BITMAP_TYPE_ICO)
1239         self.SetIcon(frameIcon)
1240 
1241         #------------
1242 
1243         # Frame cursor.
1244         cursorHand = wx.Cursor(os.path.join(self.icons_dir,
1245                                             "hand.cur"),
1246                                type=wx.BITMAP_TYPE_CUR)
1247         self.SetCursor(cursorHand)
1248 
1249         #------------
1250 
1251         self.SetTitle(("%s") % (self.app_name))
1252 
1253 
1254     def MakeMenuBar(self):
1255         """
1256         Create the menu bar for my app.
1257         """
1258 
1259         # Set an icon to the exit/about menu item.
1260         emptyImg = wx.Bitmap(os.path.join(self.bitmaps_dir,
1261                                           "item_empty.png"),
1262                              type=wx.BITMAP_TYPE_PNG)
1263 
1264         exitImg = wx.Bitmap(os.path.join(self.bitmaps_dir,
1265                                          "item_exit.png"),
1266                             type=wx.BITMAP_TYPE_PNG)
1267 
1268         helpImg = wx.Bitmap(os.path.join(self.bitmaps_dir,
1269                                          "item_about.png"),
1270                             type=wx.BITMAP_TYPE_PNG)
1271 
1272         #------------
1273 
1274         # menu.
1275         mnuFile = wx.Menu()
1276         mnuInfo = wx.Menu()
1277 
1278         # mnuFile.
1279         # Show how to put an icon in the menu item.
1280         menuItem1 = wx.MenuItem(mnuFile, -1, "W&IT\tCtrl+Alt+I", "Widget Inspection Tool !")
1281         menuItem1.SetBitmap(emptyImg)
1282         mnuFile.Append(menuItem1)
1283         self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, menuItem1)
1284 
1285         # Show how to put an icon in the menu item.
1286         menuItem2 = wx.MenuItem(mnuFile, wx.ID_EXIT, "&Quit\tCtrl+Q", "Close !")
1287         menuItem2.SetBitmap(exitImg)
1288         mnuFile.Append(menuItem2)
1289         self.Bind(wx.EVT_MENU, self.OnExit, menuItem2)
1290 
1291         # mnuInfo.
1292         # Show how to put an icon in the menu item.
1293         menuItem2 = wx.MenuItem(mnuInfo, wx.ID_ABOUT, "A&bout\tCtrl+A", "Info about developers !")
1294         menuItem2.SetBitmap(helpImg)
1295         mnuInfo.Append(menuItem2)
1296         self.Bind(wx.EVT_MENU, self.OnAbout, menuItem2)
1297 
1298         # menuBar.
1299         menubar = wx.MenuBar()
1300 
1301         # Add menu voices.
1302         menubar.Append(mnuFile, "&File")
1303         menubar.Append(mnuInfo, "I&nfo")
1304 
1305         self.SetMenuBar(menubar)
1306 
1307 
1308     def MakeStatusBar(self):
1309         """
1310         Create the status bar for my frame.
1311         """
1312 
1313         # Statusbar.
1314         self.myStatusBar = self.CreateStatusBar(1)
1315         self.myStatusBar.SetFieldsCount(2)
1316         self.myStatusBar.SetStatusWidths([-8, -4])
1317         self.myStatusBar.SetStatusText("", 0)
1318         self.myStatusBar.SetStatusText("Python-it.org.", 1)
1319 
1320 
1321     def CreateCtrls(self):
1322         """
1323         Create some controls for my frame.
1324         """
1325 
1326         # Font style for wx.StaticText.
1327         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1328         font.SetWeight(wx.BOLD)
1329 
1330         #------------
1331 
1332         # Widgets.
1333         self.panel = wx.Panel(self)
1334 
1335         self.stEmployees = wx.StaticText(self.panel, -1, "Employees list :")
1336         self.stEmployees.SetForegroundColour("gray")
1337         self.stEmployees.SetFont(font)
1338 
1339         # Image list.
1340         self.il = wx.ImageList(16, 16, True)
1341 
1342         # Set an icon for the first column.
1343         self.bmp = wx.Bitmap(os.path.join(self.bitmaps_dir,
1344                                           "employee.png"),
1345                              type=wx.BITMAP_TYPE_PNG)
1346 
1347         # Add image to list.
1348         self.img_idx = self.il.Add(self.bmp)
1349 
1350         self.listCtrl = MyListCtrl(self.panel,
1351                                    -1,
1352                                    style=wx.LC_REPORT |
1353                                          wx.LC_SINGLE_SEL |
1354                                          wx.LC_VRULES |
1355                                          wx.BORDER_SUNKEN)
1356 
1357         # Assign the image list to it.
1358         self.listCtrl.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
1359 
1360         # Retrieve data from the database.
1361         self.employeeData = self.OnLoadData()
1362 
1363         # Populate the wx.ListCtrl.
1364         for i in self.employeeData:
1365             index = self.listCtrl.InsertItem(self.listCtrl.GetItemCount(),
1366                                              ((str(i[0]))))
1367             self.listCtrl.SetItem(index, 1, i[1])
1368             self.listCtrl.SetItem(index, 2, i[2])
1369             self.listCtrl.SetItem(index, 3, i[3])
1370             self.listCtrl.SetItem(index, 4, i[4])
1371             self.listCtrl.SetItemImage(self.listCtrl.GetItemCount() - 1,
1372                                        self.img_idx)
1373 
1374             # Alternate the row colors of a ListCtrl.
1375             # Mike Driscoll... thank you !
1376             if index % 2:
1377                 self.listCtrl.SetItemBackgroundColour(index, "#ffffff")
1378             else:
1379                 self.listCtrl.SetItemBackgroundColour(index, "#ece9d8")   #ecf3fd
1380 
1381         self.stSearch = wx.StaticText(self.panel, -1, 'Search "Surname" :')
1382         self.txSearch = wx.TextCtrl(self.panel, -1, "", size=(100, -1))
1383         self.txSearch.SetToolTip("Search employee !")
1384 
1385         self.StaticSizer = wx.StaticBox(self.panel, -1, "Commands :")
1386         self.StaticSizer.SetForegroundColour("red")
1387         self.StaticSizer.SetFont(font)
1388 
1389         self.bntSearch = wx.Button(self.panel, -1, "&Search")
1390         self.bntSearch.SetToolTip("Search employee !")
1391 
1392         self.bntClear = wx.Button(self.panel, -1, "&Clear")
1393         self.bntClear.SetToolTip("Clear the search text !")
1394 
1395         self.bntShowAll = wx.Button(self.panel, -1, "&All")
1396         self.bntShowAll.SetToolTip("Show all !")
1397 
1398         self.bntNew = wx.Button(self.panel, -1, "&Insert")
1399         self.bntNew.SetToolTip("Insert a new employee !")
1400 
1401         self.bntEdit = wx.Button(self.panel, -1, "&Update")
1402         self.bntEdit.SetToolTip("Update selected employee !")
1403 
1404         self.bntDelete = wx.Button(self.panel, -1, "&Delete")
1405         self.bntDelete.SetToolTip("Delete selected employee !")
1406 
1407         self.bntClose = wx.Button(self.panel, -1, "&Quit")
1408         self.bntClose.SetToolTip("Close !")
1409 
1410 
1411     def BindEvents(self):
1412         """
1413         Bind all the events related to my frame.
1414         """
1415 
1416         self.txSearch.Bind(wx.EVT_TEXT, self.OnUpperCaseText)
1417 
1418         # Intercept the click on the wx.ListCtrl.
1419         self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.listCtrl)
1420         self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.listCtrl)
1421         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.listCtrl)
1422 
1423         self.Bind(wx.EVT_BUTTON, self.OnSearch, self.bntSearch)
1424         self.Bind(wx.EVT_BUTTON, self.OnClear, self.bntClear)
1425         self.Bind(wx.EVT_BUTTON, self.OnShowAll, self.bntShowAll)
1426         self.Bind(wx.EVT_BUTTON, self.OnNew, self.bntNew)
1427         self.Bind(wx.EVT_BUTTON, self.OnEdit, self.bntEdit)
1428         self.Bind(wx.EVT_BUTTON, self.OnDelete, self.bntDelete)
1429         self.Bind(wx.EVT_BUTTON, self.OnExit, self.bntClose)
1430 
1431         self.Bind(wx.EVT_CLOSE, self.OnExit)
1432 
1433 
1434     def DoLayout(self):
1435         """
1436         Do layout.
1437         """
1438 
1439         # Sizer.
1440         mainSizer = wx.BoxSizer(wx.HORIZONTAL)
1441         textSizer = wx.BoxSizer(wx.VERTICAL)
1442         btnSizer = wx.StaticBoxSizer(self.StaticSizer, wx.VERTICAL)
1443 
1444         # Assign widgets to sizers.
1445 
1446         # textSizer.
1447         textSizer.Add(self.stEmployees, 0, wx.BOTTOM, 5)
1448         textSizer.Add(self.listCtrl, 1, wx.EXPAND)
1449 
1450         # btnSizer.
1451         btnSizer.Add(self.stSearch)
1452         btnSizer.Add(self.txSearch)
1453         btnSizer.Add((5, 5), -1)
1454         btnSizer.Add(self.bntSearch, 0, wx.ALL, 5)
1455         btnSizer.Add((5, 5), -1)
1456         btnSizer.Add(self.bntClear, 0, wx.ALL, 5)
1457         btnSizer.Add((5, 5), -1)
1458         btnSizer.Add(self.bntShowAll, 0, wx.ALL, 5)
1459         btnSizer.Add((5, 5), -1)
1460         btnSizer.Add(self.bntNew, 0, wx.ALL, 5)
1461         btnSizer.Add((5, 5), -1)
1462         btnSizer.Add(self.bntEdit, 0, wx.ALL, 5)
1463         btnSizer.Add((5, 5), -1)
1464         btnSizer.Add(self.bntDelete, 0, wx.ALL, 5)
1465         btnSizer.Add((5, 5), -1)
1466         btnSizer.Add(self.bntClose, 0, wx.ALL, 5)
1467 
1468         # Assign to mainSizer the other sizers.
1469         mainSizer.Add(textSizer, 1, wx.ALL | wx.EXPAND, 10)
1470         mainSizer.Add(btnSizer, 0, wx.ALL, 10)
1471 
1472         # Assign to panel the mainSizer.
1473         self.panel.SetSizer(mainSizer)
1474         mainSizer.Fit(self)
1475         # mainSizer.SetSizeHints(self)
1476 
1477 
1478     def OnLoadData(self):
1479         """
1480         Retrieve data from the database.
1481         """
1482 
1483         global iCount
1484 
1485         # Retrieve employees data from database
1486         # using the module named data.py
1487         strSQL = "SELECT * FROM Employees"
1488 
1489         # The recordset retrieved
1490         rsRecordset = self.con.OnQuery(strSQL)
1491 
1492         return rsRecordset
1493 
1494 
1495     def OnItemActivated(self, event):
1496         """
1497         ...
1498         """
1499 
1500         item = event.GetItem()
1501         iEmployee = item.GetText()
1502 
1503         # Show what was selected in the frame status bar.
1504         self.myStatusBar.SetStatusText("Selected employee = %s " %(iEmployee), 1)
1505 
1506         #------------
1507 
1508         frame = self.GetTopLevelParent()
1509         frame.OnEdit(event)
1510 
1511 
1512     def OnDelete(self, event):
1513         """
1514         ...
1515         """
1516 
1517         global iEmployees
1518 
1519         # It means that we haven't select a record.
1520         if iEmployees ==0:
1521              wx.MessageBox("ATTENTION !\nSelect an employee !",
1522                            AppTitle,
1523                            wx.OK | wx.ICON_INFORMATION)
1524 
1525              return
1526 
1527         else:
1528             # Ask for delete.
1529             sMessage = "Delete selected employee ? %s " %(iEmployees)
1530             dlgAsk = wx.MessageDialog(None,
1531                                       sMessage,
1532                                       AppTitle,
1533                                       wx.YES_NO | wx.ICON_QUESTION)
1534 
1535             retCode = dlgAsk.ShowModal()
1536 
1537             if (retCode == wx.ID_YES):
1538 
1539                 sSQL = "DELETE FROM Employees WHERE EmployeeID = ?"
1540                 self.con.OnQueryParameter(sSQL, iEmployees)
1541 
1542                 self.OnShowAll(self)
1543 
1544                 wx.MessageBox("Delete operation terminate !",
1545                               AppTitle,
1546                               wx.OK | wx.ICON_INFORMATION)
1547 
1548             elif (retCode == wx.ID_NO):
1549                 wx.MessageBox("Delete operation aborted !",
1550                               AppTitle,
1551                               wx.OK | wx.ICON_INFORMATION)
1552 
1553             dlgAsk.Destroy()
1554 
1555 
1556     def OnUpdateList(self):
1557         """
1558         ...
1559         """
1560 
1561         self.OnShowAll(self)
1562 
1563 
1564     def OnShowAll(self, event):
1565         """
1566         ...
1567         """
1568 
1569         wx.BeginBusyCursor()
1570 
1571         sSQL = "SELECT * FROM Employees WHERE EmployeeID LIKE ? "
1572         sSearch = "%"
1573 
1574         self.OnRetrieveData(sSQL, sSearch)
1575 
1576         self.myStatusBar.SetStatusText("Python-it.org.", 1)
1577 
1578         self.OnClear(self)
1579 
1580         wx.CallAfter(wx.EndBusyCursor)
1581 
1582 
1583     def OnClear(self, event):
1584         """
1585         ...
1586         """
1587 
1588         global iEmployees
1589 
1590         sSQL = "SELECT * FROM Employees WHERE EmployeeID LIKE ? "
1591         sSearch = "%"
1592 
1593         self.OnRetrieveData(sSQL, sSearch)
1594 
1595         self.txSearch.Clear()
1596         self.txSearch.SetFocus()
1597 
1598         iEmployees = 0
1599 
1600 
1601     def OnSearch(self, event):
1602         """
1603         ...
1604         """
1605 
1606         # Retrieve what we have write.
1607         sSearch = str(self.txSearch.GetValue())
1608 
1609         # Remove spaces.
1610         # sSearch = "".join(sSearch.strip().split())
1611 
1612         # Add & symbol to force the search.
1613         sSearch = sSearch+"%"
1614 
1615         # Control if we have write something
1616         # before launch the research.
1617         if sSearch == "%" :
1618                 wx.MessageBox("ATTENTION !\nThe search text is empty !",
1619                               AppTitle,
1620                               wx.OK | wx.ICON_INFORMATION)
1621 
1622                 self.txSearch.SetFocus()
1623 
1624                 return
1625 
1626         else:
1627             sSQL = "SELECT * FROM Employees WHERE Surname LIKE ? "
1628             self.OnRetrieveData(sSQL, sSearch)
1629 
1630 
1631     def OnRetrieveData(self, sSQL, IDParameter):
1632         """
1633         ...
1634         """
1635 
1636         global iEmployees
1637 
1638         # Delete the item from listctrl.
1639         self.listCtrl.SetFocus()
1640         self.listCtrl.DeleteAllItems()
1641 
1642         # Retrieve the products recordset from data module.
1643         self.employeeData = self.con.OnQueryParameter(sSQL, IDParameter)
1644 
1645         # Populate the listctrl.
1646         if self.employeeData:
1647             for i in self.employeeData:
1648                 index = self.listCtrl.InsertItem(self.listCtrl.GetItemCount(),
1649                                                  ((str(i[0]))))
1650                 self.listCtrl.SetItem(index, 1, i[1])
1651                 self.listCtrl.SetItem(index, 2, i[2])
1652                 self.listCtrl.SetItem(index, 3, i[3])
1653                 self.listCtrl.SetItem(index, 4, i[4])
1654 
1655                 # Alternate the row colors of a ListCtrl.
1656                 # Mike Driscoll... thank you !
1657                 if index % 2:
1658                     self.listCtrl.SetItemBackgroundColour(index, "#ffffff")
1659                 else:
1660                     self.listCtrl.SetItemBackgroundColour(index, "#ece9d8")   #ecf3fd
1661 
1662         else:
1663              wx.MessageBox("ATTENTION !\nNo results for your research criteria.\nTry with another criteria !",
1664                            AppTitle,
1665                            wx.OK | wx.ICON_INFORMATION)
1666 
1667 
1668     def OnEdit(self, event):
1669         """
1670         ...
1671         """
1672 
1673         global iEmployees
1674 
1675         # It means that we haven't select an employee.
1676         if iEmployees ==0:
1677              wx.MessageBox("ATTENTION !\nSelect an employee !",
1678                            AppTitle,
1679                            wx.OK | wx.ICON_INFORMATION)
1680 
1681              return
1682 
1683         else:
1684             sSQL = "SELECT * FROM Employees WHERE EmployeeID = ?"
1685             self.OnOpenEdit(sSQL, iEmployees)
1686 
1687 
1688     def OnNew(self, event):
1689         """
1690         ...
1691         """
1692 
1693         # Create an instance of the Child_Frame.
1694         self.dlgInsert = self.dlgInsert = MyInsertDlg(caller_dlgInsert=self)
1695 
1696         sTitle = "Insert new employee"
1697         self.dlgInsert.SetTitle(sTitle)
1698         self.dlgInsert.CenterOnParent(wx.BOTH)
1699         self.dlgInsert.ShowModal()
1700         self.dlgInsert.Destroy()
1701 
1702 
1703     def OnOpenEdit(self, sSQL, sParameter):
1704         """
1705         ...
1706         """
1707 
1708         # Retrieve data for the selected product.
1709         rsEmployees = self.con.OnQueryParameter(sSQL, sParameter)
1710 
1711         # Create an instance of the Child_Frame.
1712         self.dlgEdit = self.dlgEdit = MyUpdateDlg(caller_dlgUpdate=self)
1713 
1714         # Populate the fields of the frame with the recordset.
1715         for i in rsEmployees:
1716             self.dlgEdit.txEmployeeID.SetValue(str(i[0]))
1717             self.dlgEdit.txSurname.SetValue(str(i[1]))
1718             self.dlgEdit.txFirstname.SetValue(str(i[2]))
1719             self.dlgEdit.txPhone1.SetValue(str(i[3][0:2]))
1720             self.dlgEdit.txPhone2.SetValue(str(i[3][3:5]))
1721             self.dlgEdit.txPhone3.SetValue(str(i[3][6:8]))
1722             self.dlgEdit.txPhone4.SetValue(str(i[3][9:11]))
1723             self.dlgEdit.txPhone5.SetValue(str(i[3][12:14]))
1724             self.dlgEdit.txEmail.SetValue(str(i[4]))
1725 
1726             # We use this for the title of the frame.
1727             sEmployees =(str(i[1]))
1728 
1729         sTitle = "Select employee : %s" %(sEmployees)
1730         self.dlgEdit.SetTitle(sTitle)
1731         self.dlgEdit.CenterOnParent(wx.BOTH)
1732         self.dlgEdit.ShowModal()
1733         self.dlgEdit.Destroy()
1734 
1735 
1736     def OnUpperCaseText(self, event):
1737         """
1738         ...
1739         """
1740 
1741         # Write in upper mode on widgets the call it.
1742         # Adapted from a script of David Hughes
1743         # Forestfield Software.
1744         # Retrive the widget.
1745         wdgControl = event.GetEventObject()
1746 
1747         # Retrive what we have write.
1748         retValue = wdgControl.GetValue()
1749 
1750         # Upper it.
1751         upValue = retValue.upper()
1752 
1753         if retValue != upValue:
1754             wdgControl.SetValue(upValue)
1755             # Insert it at the end.
1756             wdgControl.SetInsertionPointEnd()
1757 
1758         event.Skip()
1759 
1760 
1761     def OnItemSelected(self, event):
1762         """
1763         ...
1764         """
1765 
1766         global iEmployees
1767 
1768         item = event.GetItem()
1769         iEmployees = item.GetText()
1770 
1771         # Show what was selected in the frame status bar.
1772         self.myStatusBar.SetStatusText("Selected employee = %s " %(iEmployees), 1)
1773 
1774 
1775     def OnColBeginDrag(self, event):
1776         """
1777         Show how to not allow a column to be resized.
1778         """
1779 
1780         if event.GetColumn() == 0:
1781             event.Veto()
1782 
1783 
1784     def OnOpenWidgetInspector(self, event):
1785         """
1786         Activate the widget inspection tool,
1787         giving it a widget to preselect in the tree.
1788         Use either the one under the cursor,
1789         if any, or this frame.
1790         """
1791 
1792         from wx.lib.inspection import InspectionTool
1793         wnd = wx.FindWindowAtPointer()
1794         if not wnd:
1795             wnd = self
1796         InspectionTool().Show(wnd, True)
1797 
1798 
1799     def OnAbout(self, event):
1800         """
1801         ...
1802         """
1803 
1804         # Returns SQLite version.
1805         sSQLversion = self.con.OnSqliteVersion()
1806 
1807         message = """Python-it.org\n
1808                      How to use a wx.ListCtrl.
1809                      Developed in wxPython by Guldo and Beppe.\n
1810                      Improved and updated for wxPython Phoenix by Ecco :-)\n
1811                      Have fun ! ---> Amusez-vous bien !\n
1812                      SQLite version : %s""" %(sSQLversion)
1813 
1814         wx.MessageBox(message,
1815                       AppTitle,
1816                       wx.OK)
1817 
1818 
1819     def OnClose(self):
1820         """
1821         ...
1822         """
1823 
1824         ret = wx.MessageBox("Do you want exit ?",
1825                             AppTitle,
1826                             wx.YES_NO |wx.ICON_QUESTION|
1827                             wx.CENTRE |wx.NO_DEFAULT)
1828 
1829         return ret
1830 
1831 
1832     def OnExit(self, event):
1833         """
1834         ...
1835         """
1836 
1837         # Ask for exit.
1838         intChoice = self.OnClose()
1839 
1840         if intChoice == 2:
1841             # Disconnect from server.
1842             self.con.OnCloseDb()
1843             self.Destroy()
1844 
1845 
1846     def OnTimer(self, event):
1847         """
1848         ...
1849         """
1850 
1851         t = time.localtime(time.time())
1852         sbTime = time.strftime("Astral date %d/%m/%Y are %H:%M:%S", t)
1853         self.myStatusBar.SetStatusText(sbTime, 0)
1854 
1855 #-------------------------------------------------------------------------------
1856 
1857 class MyApp(wx.App, wx.lib.mixins.inspection.InspectionMixin):
1858     """
1859     Thanks to Andrea Gavana.
1860     """
1861     def OnInit(self):
1862 
1863         #------------
1864 
1865         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
1866 
1867         #------------
1868 
1869         self.SetAppName("List of employees (v0.0.2)")
1870 
1871         #------------
1872 
1873         self.installDir = os.path.split(os.path.abspath(sys.argv[0]))[0]
1874 
1875         #------------
1876 
1877         # Simplified init method.
1878         # For the InspectionMixin base class.
1879         self.InitInspection()
1880 
1881         #------------
1882 
1883         frame = MyFrame(None, -1, title="")
1884         frame.SetSize(800, 527)
1885         self.SetTopWindow(frame)
1886         frame.Center()
1887         frame.Show(True)
1888 
1889         return True
1890 
1891     #---------------------------------------------------------------------------
1892 
1893     def GetInstallDir(self):
1894         """
1895         Returns the installation directory for my application.
1896         """
1897 
1898         return self.installDir
1899 
1900 
1901     def GetIconsDir(self):
1902         """
1903         Returns the icons directory for my application.
1904         """
1905 
1906         icons_dir = os.path.join(self.installDir, "icons")
1907         return icons_dir
1908 
1909 
1910     def GetBitmapsDir(self):
1911         """
1912         Returns the bitmaps directory for my application.
1913         """
1914 
1915         bitmaps_dir = os.path.join(self.installDir, "bitmaps")
1916         return bitmaps_dir
1917 
1918 
1919     def GetDatabaseDir(self):
1920         """
1921         Returns the database directory for my application.
1922         """
1923 
1924         if not os.path.exists("data"):
1925             # Create the data folder, it still doesn't exist.
1926             os.makedirs("data")
1927 
1928         database_dir = os.path.join(self.installDir, "data")
1929         return database_dir
1930 
1931 #-------------------------------------------------------------------------------
1932 
1933 def main():
1934     app = MyApp(redirect=False)
1935     app.MainLoop()
1936 
1937 #-------------------------------------------------------------------------------
1938 
1939 if __name__ == "__main__" :
1940     main()


Second example

img_sample_two.png

To know : for a voluminous database, you must use a virtual list control.

   1 # sample_two.py
   2 
   3 # Authors      : Beppe and Guldo
   4 #                Updated and improved for wxPython Phoenix by Ecco
   5 # Date (d/m/y) : 31/09/2007 (v0.0.1)
   6 #                15/06/2020 (v0.0.3)
   7 # Version      : 0.0.3
   8 # Web          : Python-it.org
   9 # Description  : Shows some wx.ListCtrl utilities.
  10 #                Correct mode for Insert, Update and Delete
  11 #                record in a SQLite 3 database.
  12 #                How to call a function of a frame from
  13 #                another frame.
  14 #                It use Northwind database ah ah ah !!!
  15 #                Enjoy yourself !
  16 
  17 import sys
  18 import os
  19 import time
  20 import sqlite3
  21 import re
  22 import wx
  23 import wx.lib.mixins.inspection
  24 import wx.lib.mixins.listctrl as listmix
  25 
  26 AppTitle = "List of employees (sort)"
  27 iEmployees = 0
  28 
  29 ID_LIST = wx.NewIdRef()
  30 
  31 # class MyConnection
  32 # class MyInsertDlg
  33 # class MyUpdateDlg
  34 # class MyListCtrl
  35 # class MyFrame
  36 # class MyApp
  37 
  38 #-------------------------------------------------------------------------------
  39 
  40 
  41 class MyConnection(object):
  42     """
  43     ...
  44     """
  45     def __init__(self):
  46 
  47         #------------
  48 
  49         # Return database folder.
  50         self.database_dir = wx.GetApp().GetDatabaseDir()
  51 
  52         # Loading "northwind" file.
  53         dbFile = os.path.join(self.database_dir, "northwind.db")
  54 
  55         #------------
  56 
  57         # Create/connect to a permanent file database.
  58         # For temporary testing you can use memory only.
  59         # Open a connection to a DB in RAM :
  60         # self.con = lite.connect(":memory:")
  61         self.con = sqlite3.connect(dbFile, isolation_level=None,
  62                                    detect_types=sqlite3.PARSE_DECLTYPES)
  63 
  64         # Establish the cursor, needed to execute the connected db.
  65         self.cur = self.con.cursor()
  66 
  67         try:
  68             # Create/execute a table (ex : Employees) :
  69             self.cur.execute("""CREATE TABLE IF NOT EXISTS Employees (
  70                                              EmployeeID INTEGER PRIMARY KEY,
  71                                              Surname TEXT,
  72                                              Firstname TEXT,
  73                                              Phone TEXT,
  74                                              Email TEXT)
  75                              """)
  76 
  77         except sqlite3.OperationalError:
  78             wx.LogMessage("Can not create the database, "
  79                           "maybe because it already exists ?")
  80             return
  81 
  82         # Important if you make changes to the database commits
  83         # current data to the db file (data is persistant now).
  84         self.con.commit()
  85 
  86     #-----------------------------------------------------------------------
  87 
  88     def OnQuery(self, sSQL):
  89         """
  90         Execute a query passed in the argument from the main frame.
  91         """
  92 
  93         self.cur.execute(sSQL)
  94         # Here create the recordset.
  95         # It's a list of a list...
  96         rsRecordSet = self.cur.fetchall()
  97 
  98         return rsRecordSet
  99 
 100 
 101     def OnQueryParameter(self, sSQL, sParameter):
 102         """
 103         ...
 104         """
 105 
 106         Parameter =(sParameter, )
 107 
 108         self.cur.execute(sSQL, Parameter)
 109         rsRecordSet = self.cur.fetchall()
 110 
 111         return rsRecordSet
 112 
 113 
 114     def OnQueryUpdate(self, sSQL, sParameter):
 115         """
 116         ...
 117         """
 118 
 119         self.cur.execute(sSQL, sParameter)
 120         rsRecordSet = self.cur.fetchall()
 121 
 122         return rsRecordSet
 123 
 124 
 125     def OnSqliteVersion(self):
 126         """
 127         Returns SQLite version.
 128         """
 129 
 130         self.cur.execute("SELECT SQLITE_VERSION()")
 131 
 132         version = self.cur.fetchone()
 133 
 134         return version
 135 
 136 
 137     def OnCloseDb(self):
 138         """
 139         Disconnect database connection.
 140         """
 141 
 142         # Disconnect from server.
 143         self.cur.close()
 144         self.con.close()
 145 
 146 #-------------------------------------------------------------------------------
 147 
 148 class MyInsertDlg(wx.Dialog):
 149     """
 150     ...
 151     """
 152     def __init__(self, caller_dlgInsert, title=""):
 153         wx.Dialog.__init__(self,
 154                            parent=caller_dlgInsert,
 155                            id=-1,
 156                            title="")
 157 
 158         #------------
 159 
 160         self.caller = caller_dlgInsert
 161 
 162         #------------
 163 
 164         # Return icons folder.
 165         self.icons_dir = wx.GetApp().GetIconsDir()
 166 
 167         #------------
 168 
 169         # Simplified init method.
 170         self.ConnectDb()
 171         self.SetProperties()
 172         self.CreateCtrls()
 173         self.BindEvents()
 174         self.DoLayout()
 175 
 176     #---------------------------------------------------------------------------
 177 
 178     def ConnectDb(self):
 179         """
 180         Connection to the database.
 181         """
 182 
 183         # Instance from Class MyConnection.
 184         self.con = MyConnection()
 185 
 186 
 187     def SetProperties(self):
 188         """
 189         Set the frame properties (title, icon, size...).
 190         """
 191 
 192         # Setting some frame properties.
 193         frameIcon = wx.Icon(os.path.join(self.icons_dir,
 194                                          "icon_wxWidgets.ico"),
 195                             type=wx.BITMAP_TYPE_ICO)
 196         self.SetIcon(frameIcon)
 197 
 198 
 199     def CreateCtrls(self):
 200         """
 201         Create some controls for my frame.
 202         """
 203 
 204         # wx.Font(pointSize, family, style, weight, underline, faceName)
 205         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 206         font.SetWeight(wx.BOLD)
 207 
 208         #------------
 209 
 210         # Widgets.
 211         self.panel = wx.Panel(self)
 212 
 213         #--
 214 
 215         self.stSurname = wx.StaticText(self.panel, -1, "Surname :")
 216         self.stSurname.SetForegroundColour("gray")
 217         self.stSurname.SetFont(font)
 218 
 219         self.txSurname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 220 
 221         #--
 222 
 223         self.stFirstname = wx.StaticText(self.panel, -1, "First name :")
 224         self.stFirstname.SetForegroundColour("gray")
 225         self.stFirstname.SetFont(font)
 226 
 227         self.txFirstname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 228 
 229         #--
 230 
 231         message  = "- Max chars : 2."
 232 
 233         self.stPhone = wx.StaticText(self.panel, -1, "Phone :")
 234         self.stPhone.SetForegroundColour("gray")
 235         self.stPhone.SetFont(font)
 236 
 237         self.txPhone1 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 238                                     style=wx.TE_CENTRE)
 239         self.txPhone1.SetMaxLength(2)
 240         self.txPhone1.SetForegroundColour("gray")
 241         self.txPhone1.SetBackgroundColour("yellow")
 242         self.txPhone1.SetFont(font)
 243 
 244         self.hyphen1 = wx.StaticText(self.panel, -1, "-")
 245 
 246         self.txPhone2 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 247                                     style=wx.TE_CENTRE)
 248         self.txPhone2.SetMaxLength(2)
 249 
 250         self.hyphen2 = wx.StaticText(self.panel, -1, "-")
 251 
 252         self.txPhone3 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 253                                     style=wx.TE_CENTRE)
 254         self.txPhone3.SetMaxLength(2)
 255 
 256         self.hyphen3 = wx.StaticText(self.panel, -1, "-")
 257 
 258         self.txPhone4 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 259                                     style=wx.TE_CENTRE)
 260         self.txPhone4.SetMaxLength(2)
 261 
 262         self.hyphen4 = wx.StaticText(self.panel, -1, "-")
 263 
 264         self.txPhone5 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 265                                     style=wx.TE_CENTRE)
 266         self.txPhone5.SetMaxLength(2)
 267 
 268         #--
 269 
 270         self.stEmail = wx.StaticText(self.panel, -1, "Email :")
 271         self.stEmail.SetForegroundColour("gray")
 272         self.stEmail.SetFont(font)
 273 
 274         self.txEmail = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 275 
 276         #--
 277 
 278         self.StaticSizer = wx.StaticBox(self.panel, -1, "")
 279 
 280         #--
 281 
 282         self.bntSave = wx.Button(self.panel, -1, "&Save")
 283         self.bntSave.SetToolTip("Save !")
 284 
 285         self.bntClose = wx.Button(self.panel, -1, "&Close")
 286         self.bntClose.SetToolTip("Close !")
 287 
 288 
 289     def BindEvents(self):
 290         """
 291         Bind all the events related to my frame.
 292         """
 293 
 294         self.txSurname.Bind(wx.EVT_TEXT, self.OnUpperCaseText)
 295         self.txFirstname.Bind(wx.EVT_TEXT, self.OnCapitalizeCaseText)
 296         self.txEmail.Bind(wx.EVT_TEXT, self.OnLowerCaseText)
 297 
 298         self.txPhone1.Bind(wx.EVT_CHAR, self.OnChar)
 299         self.txPhone2.Bind(wx.EVT_CHAR, self.OnChar)
 300         self.txPhone3.Bind(wx.EVT_CHAR, self.OnChar)
 301         self.txPhone4.Bind(wx.EVT_CHAR, self.OnChar)
 302         self.txPhone5.Bind(wx.EVT_CHAR, self.OnChar)
 303 
 304         self.Bind(wx.EVT_BUTTON, self.OnSave, self.bntSave)
 305         self.Bind(wx.EVT_BUTTON, self.OnExit, self.bntClose)
 306 
 307         self.Bind(wx.EVT_CLOSE, self.OnExit)
 308 
 309 
 310     def DoLayout(self):
 311         """
 312         Do layout.
 313         """
 314 
 315         # Sizers.
 316         mainSizer = wx.BoxSizer(wx.HORIZONTAL)
 317         textSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
 318         textSizer.AddGrowableCol(1)
 319 
 320         buttonSizer = wx.StaticBoxSizer(self.StaticSizer, wx.VERTICAL)
 321 
 322         # Assign widgets to sizers.
 323 
 324         # textSizer.
 325         textSizer.Add(self.stSurname, 0, wx.ALIGN_CENTER_VERTICAL)
 326         textSizer.Add(self.txSurname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 327 
 328         textSizer.Add(self.stFirstname, 0, wx.ALIGN_CENTER_VERTICAL)
 329         textSizer.Add(self.txFirstname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 330 
 331         textSizer.Add(self.stPhone, 0, wx.ALIGN_CENTER_VERTICAL)
 332 
 333         ctrlSizer = wx.BoxSizer(wx.HORIZONTAL)
 334         ctrlSizer.Add(self.txPhone1, 1, wx.EXPAND)
 335         ctrlSizer.Add(self.hyphen1, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 336         ctrlSizer.Add(self.txPhone2, 1, wx.EXPAND)
 337         ctrlSizer.Add(self.hyphen2, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 338         ctrlSizer.Add(self.txPhone3, 1, wx.EXPAND)
 339         ctrlSizer.Add(self.hyphen3, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 340         ctrlSizer.Add(self.txPhone4, 1, wx.EXPAND)
 341         ctrlSizer.Add(self.hyphen4, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 342         ctrlSizer.Add(self.txPhone5, 1, wx.EXPAND)
 343 
 344         textSizer.Add(ctrlSizer, 1, wx.EXPAND)
 345         textSizer.Add(self.stEmail, 0, wx.ALIGN_CENTER_VERTICAL)
 346         textSizer.Add(self.txEmail, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 347 
 348         # buttonSizer.
 349         buttonSizer.Add(self.bntSave)
 350         buttonSizer.Add((5, 5), -1)
 351         buttonSizer.Add(self.bntClose)
 352 
 353         # Assign to mainSizer the other sizers.
 354         mainSizer.Add(textSizer, 0, wx.ALL, 10)
 355         mainSizer.Add(buttonSizer, 0, wx.ALL, 10)
 356 
 357         # Assign to panel the mainSizer.
 358         self.panel.SetSizer(mainSizer)
 359         mainSizer.Fit(self)
 360         mainSizer.SetSizeHints(self)
 361 
 362 
 363     def FieldsControl(self):
 364         """
 365         ...
 366         """
 367 
 368         if len(self.txSurname.GetValue()) == 0:
 369                 wx.MessageBox('ATTENTION !\nThe "Surname" field is empty !',
 370                               AppTitle,
 371                               wx.OK | wx.ICON_INFORMATION)
 372 
 373                 self.txSurname.SetFocus()
 374 
 375                 return 0
 376 
 377         elif len(self.txFirstname.GetValue()) == 0:
 378                 wx.MessageBox('ATTENTION !\nThe "First name" field is empty !',
 379                               AppTitle,
 380                               wx.OK | wx.ICON_INFORMATION)
 381 
 382                 return 0
 383 
 384         elif len(self.txPhone1.GetValue()) < 2:
 385                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 386                               "Phone number",
 387                               wx.OK | wx.ICON_INFORMATION)
 388 
 389                 return 0
 390 
 391         elif len(self.txPhone2.GetValue()) < 2:
 392                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 393                               "Phone number",
 394                               wx.OK | wx.ICON_INFORMATION)
 395 
 396                 return 0
 397 
 398         elif len(self.txPhone3.GetValue()) < 2:
 399                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 400                               "Phone number",
 401                               wx.OK | wx.ICON_INFORMATION)
 402 
 403                 return 0
 404 
 405         elif len(self.txPhone4.GetValue()) < 2:
 406                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 407                               "Phone number",
 408                               wx.OK | wx.ICON_INFORMATION)
 409 
 410                 return 0
 411 
 412         elif len(self.txPhone5.GetValue()) < 2:
 413                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 414                               "Phone number",
 415                               wx.OK | wx.ICON_INFORMATION)
 416 
 417                 return 0
 418 
 419         elif len(self.txEmail.GetValue()) == 0:
 420                 wx.MessageBox('ATTENTION !\nThe "Email" field is empty !',
 421                               AppTitle,
 422                               wx.OK | wx.ICON_INFORMATION)
 423 
 424                 return 0
 425 
 426 
 427     def OnSave(self, event):
 428         """
 429         ...
 430         """
 431 
 432         if self.FieldsControl() == 0:
 433 
 434             return
 435 
 436         else:
 437             sMessage = "Save new employee data ?"
 438             dlgAsk = wx.MessageDialog(None,
 439                                       sMessage,
 440                                       AppTitle,
 441                                       wx.YES_NO | wx.ICON_QUESTION)
 442 
 443             retCode = dlgAsk.ShowModal()
 444 
 445             if (retCode == wx.ID_YES):
 446                 sSurname = str(self.txSurname.GetValue())
 447                 sFirstname = str(self.txFirstname.GetValue())
 448                 #--
 449                 value1 = str(self.txPhone1.GetValue())
 450                 value2 = str(self.txPhone2.GetValue())
 451                 value3 = str(self.txPhone3.GetValue())
 452                 value4 = str(self.txPhone4.GetValue())
 453                 value5 = str(self.txPhone5.GetValue())
 454                 number = value1 + value2 + value3 + value4 + value5
 455                 sPhone = self.AddHyphens(number)
 456                 #--
 457                 sEmail = str(self.txEmail.GetValue())
 458 
 459                 InsertParameters = (sSurname,
 460                                     sFirstname,
 461                                     sPhone,
 462                                     sEmail)
 463 
 464                 sSQL = "INSERT INTO Employees (Surname, \
 465                                                Firstname, \
 466                                                Phone, \
 467                                                Email) \
 468                                        VALUES (?, ?, ?, ?)"
 469 
 470                 # Insert new data in the database.
 471                 self.con.OnQueryUpdate(sSQL, InsertParameters)
 472 
 473                 # Guldo... thank you !
 474                 self.caller.OnUpdateList()
 475 
 476                 wx.MessageBox("New data insert !",
 477                               AppTitle,
 478                               wx.OK | wx.ICON_INFORMATION)
 479 
 480             elif (retCode == wx.ID_NO):
 481                 wx.MessageBox("Insert operation aborted !",
 482                               AppTitle,
 483                               wx.OK | wx.ICON_INFORMATION)
 484 
 485             dlgAsk.Destroy()
 486             self.OnExit(self)
 487 
 488 
 489     def OnUpperCaseText