How to create a list control with 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(self, event):
 490         """
 491         ...
 492         """
 493 
 494         # Write in upper mode on widgets the call it.
 495         # Adapted from a script of David Hughes
 496         # Forestfield Software.
 497         # Retrive the widget.
 498         wdgControl = event.GetEventObject()
 499 
 500         # Retrive what we have write.
 501         retValue = wdgControl.GetValue()
 502 
 503         # Upper it.
 504         upValue = retValue.upper()
 505 
 506         if retValue != upValue:
 507             wdgControl.SetValue(upValue)
 508             # Insert it at the end.
 509             wdgControl.SetInsertionPointEnd()
 510 
 511         event.Skip()
 512 
 513 
 514     def OnLowerCaseText(self, event):
 515         """
 516         ...
 517         """
 518 
 519         # Write in lower mode on widgets the call it.
 520         # Adapted from a script of David Hughes
 521         # Forestfield Software.
 522         # Retrive the widget.
 523         wdgControl = event.GetEventObject()
 524 
 525         # Retrive what we have write.
 526         retValue = wdgControl.GetValue()
 527 
 528         # Lower it.
 529         upValue = retValue.lower()
 530 
 531         if retValue != upValue:
 532             wdgControl.SetValue(upValue)
 533             # Insert it at the end.
 534             wdgControl.SetInsertionPointEnd()
 535 
 536         event.Skip()
 537 
 538 
 539     def OnCapitalizeCaseText(self, event):
 540         """
 541         ...
 542         """
 543 
 544         # Write in capitalize mode on widgets the call it.
 545         # Adapted from a script of David Hughes
 546         # Forestfield Software.
 547         # Retrive the widget.
 548         wdgControl = event.GetEventObject()
 549 
 550         # Retrive what we have write.
 551         retValue = wdgControl.GetValue()
 552 
 553         # Capitalize it.
 554         upValue = retValue.lower().capitalize()
 555 
 556         if retValue != upValue:
 557             wdgControl.SetValue(upValue)
 558             # Insert it at the end.
 559             wdgControl.SetInsertionPointEnd()
 560 
 561         event.Skip()
 562 
 563 
 564     def OnChar(self, event):
 565         """
 566         Block non numbers.
 567         """
 568 
 569         # print("\ndef OnChar")
 570 
 571         key_code = event.GetKeyCode()
 572 
 573         # Allow ASCII numerics.
 574         if ord('0') <= key_code <= ord('9'):
 575             event.Skip()
 576             return
 577 
 578         # Allow decimal points.
 579         if key_code == ord('.'):
 580             event.Skip()
 581             return
 582 
 583         # Allow tabs, for tab navigation between TextCtrls.
 584         if key_code == ord('\t'):
 585             event.Skip()
 586             return
 587 
 588         # Enable backspace, del, left-right.
 589         # The values may be platform dependent.
 590         if key_code in (8, 127, 314, 316):
 591             event.Skip()
 592             return
 593 
 594         # Block everything else.
 595         return
 596 
 597 
 598     def AddHyphens(self, nb):
 599         """
 600         ...
 601         """
 602 
 603         phone = nb[0:2] + '-' + nb[2:4] + '-' + nb[4:6] + '-' + nb[6:8] + '-' + nb[8:10]
 604 
 605         return phone
 606 
 607 
 608     def OnExit(self, event):
 609         """
 610         ...
 611         """
 612 
 613         self.Destroy()
 614 
 615 #-------------------------------------------------------------------------------
 616 
 617 class MyUpdateDlg(wx.Dialog):
 618     """
 619     ...
 620     """
 621     def __init__(self, caller_dlgUpdate, title=""):
 622         wx.Dialog.__init__(self,
 623                            parent=caller_dlgUpdate,
 624                            id=-1,
 625                            title=title,
 626                            size=(400, 200))
 627 
 628         #------------
 629 
 630         self.caller = caller_dlgUpdate
 631 
 632         #------------
 633 
 634         # Return icons folder.
 635         self.icons_dir = wx.GetApp().GetIconsDir()
 636 
 637         #------------
 638 
 639         # Simplified init method.
 640         self.ConnectDb()
 641         self.SetProperties()
 642         self.CreateCtrls()
 643         self.BindEvents()
 644         self.DoLayout()
 645 
 646     #---------------------------------------------------------------------------
 647 
 648     def ConnectDb(self):
 649         """
 650         Connection to the database.
 651         """
 652 
 653         # Instance from Class MyConnection.
 654         self.con = MyConnection()
 655 
 656 
 657     def SetProperties(self):
 658         """
 659         Set the frame properties (title, icon, size...).
 660         """
 661 
 662         # Setting some frame properties.
 663         frameIcon = wx.Icon(os.path.join(self.icons_dir,
 664                                          "icon_wxWidgets.ico"),
 665                             type=wx.BITMAP_TYPE_ICO)
 666         self.SetIcon(frameIcon)
 667 
 668 
 669     def CreateCtrls(self):
 670         """
 671         Create some controls for my frame.
 672         """
 673 
 674         # wx.Font(pointSize, family, style, weight, underline, faceName)
 675         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
 676         font.SetWeight(wx.BOLD)
 677 
 678         #------------
 679 
 680         # Widgets.
 681         self.panel = wx.Panel(self)
 682 
 683         #--
 684 
 685         self.stEmployeeID = wx.StaticText(self.panel, -1, "ID :")
 686         self.stEmployeeID.SetForegroundColour("red")
 687         self.stEmployeeID.SetFont(font)
 688 
 689         self.txEmployeeID = wx.TextCtrl(self.panel, -1, "", size=(230, -1),
 690                                         style=wx.TE_READONLY | wx.TE_CENTRE)
 691         self.txEmployeeID.SetForegroundColour("white")
 692         self.txEmployeeID.SetBackgroundColour("#CD5C5C")
 693         self.txEmployeeID.SetFont(font)
 694 
 695         #--
 696 
 697         self.stSurname = wx.StaticText(self.panel, -1, "Surname :")
 698         self.stSurname.SetForegroundColour("gray")
 699         self.stSurname.SetFont(font)
 700 
 701         self.txSurname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 702 
 703         #--
 704 
 705         self.stFirstname = wx.StaticText(self.panel, -1, "First name :")
 706         self.stFirstname.SetForegroundColour("gray")
 707         self.stFirstname.SetFont(font)
 708 
 709         self.txFirstname = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 710 
 711         #--
 712 
 713         self.stPhone = wx.StaticText(self.panel, -1, "Phone :")
 714         self.stPhone.SetForegroundColour("gray")
 715         self.stPhone.SetFont(font)
 716 
 717         self.txPhone1 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 718                                     style=wx.TE_CENTRE)
 719         self.txPhone1.SetMaxLength(2)
 720         self.txPhone1.SetForegroundColour("gray")
 721         self.txPhone1.SetBackgroundColour("yellow")
 722         self.txPhone1.SetFont(font)
 723 
 724         self.hyphen1 = wx.StaticText(self.panel, -1, "-")
 725 
 726         self.txPhone2 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 727                                     style=wx.TE_CENTRE)
 728         self.txPhone2.SetMaxLength(2)
 729 
 730         self.hyphen2 = wx.StaticText(self.panel, -1, "-")
 731 
 732         self.txPhone3 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 733                                     style=wx.TE_CENTRE)
 734         self.txPhone3.SetMaxLength(2)
 735 
 736         self.hyphen3 = wx.StaticText(self.panel, -1, "-")
 737 
 738         self.txPhone4 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 739                                     style=wx.TE_CENTRE)
 740         self.txPhone4.SetMaxLength(2)
 741 
 742         self.hyphen4 = wx.StaticText(self.panel, -1, "-")
 743 
 744         self.txPhone5 = wx.TextCtrl(self.panel, -1, "", size=(35, -1),
 745                                     style=wx.TE_CENTRE)
 746         self.txPhone5.SetMaxLength(2)
 747 
 748         #--
 749 
 750         self.stEmail = wx.StaticText(self.panel, -1, "Email :")
 751         self.stEmail.SetForegroundColour("gray")
 752         self.stEmail.SetFont(font)
 753 
 754         self.txEmail = wx.TextCtrl(self.panel, -1, "", size=(230, -1))
 755 
 756         #--
 757 
 758         self.StaticSizer = wx.StaticBox(self.panel, -1,"")
 759 
 760         #--
 761 
 762         self.bntSave = wx.Button(self.panel, -1, "&Save")
 763         self.bntSave.SetToolTip("Save !")
 764 
 765         self.bntClose = wx.Button(self.panel, -1, "&Close")
 766         self.bntClose.SetToolTip("Close !")
 767 
 768 
 769 
 770     def BindEvents(self):
 771         """
 772         Bind all the events related to my frame.
 773         """
 774 
 775         self.txSurname.Bind(wx.EVT_TEXT, self.OnUpperCaseText)
 776         self.txFirstname.Bind(wx.EVT_TEXT, self.OnCapitalizeCaseText)
 777         self.txEmail.Bind(wx.EVT_TEXT, self.OnLowerCaseText)
 778 
 779         self.txPhone1.Bind(wx.EVT_CHAR, self.OnChar)
 780         self.txPhone2.Bind(wx.EVT_CHAR, self.OnChar)
 781         self.txPhone3.Bind(wx.EVT_CHAR, self.OnChar)
 782         self.txPhone4.Bind(wx.EVT_CHAR, self.OnChar)
 783         self.txPhone5.Bind(wx.EVT_CHAR, self.OnChar)
 784 
 785         self.Bind(wx.EVT_BUTTON, self.OnSave, self.bntSave)
 786         self.Bind(wx.EVT_BUTTON, self.OnExit, self.bntClose)
 787 
 788         self.Bind(wx.EVT_CLOSE, self.OnExit)
 789 
 790 
 791     def DoLayout(self):
 792         """
 793         Do layout.
 794         """
 795 
 796         # Sizers.
 797         mainSizer = wx.BoxSizer(wx.HORIZONTAL)
 798         textSizer = wx.FlexGridSizer(cols=2, vgap=5, hgap=5)
 799         textSizer.AddGrowableCol(1)
 800 
 801         buttonSizer = wx.StaticBoxSizer(self.StaticSizer, wx.VERTICAL)
 802 
 803         # Assign widgets to sizers.
 804 
 805         # textSizer.
 806         textSizer.Add(self.stEmployeeID, 0, wx.ALIGN_CENTER_VERTICAL)
 807         textSizer.Add(self.txEmployeeID, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 808 
 809         textSizer.Add(self.stSurname, 0, wx.ALIGN_CENTER_VERTICAL)
 810         textSizer.Add(self.txSurname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 811 
 812         textSizer.Add(self.stFirstname, 0, wx.ALIGN_CENTER_VERTICAL)
 813         textSizer.Add(self.txFirstname, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 814 
 815         textSizer.Add(self.stPhone, 0, wx.ALIGN_CENTER_VERTICAL)
 816 
 817         ctrlSizer = wx.BoxSizer(wx.HORIZONTAL)
 818         ctrlSizer.Add(self.txPhone1, 1, wx.EXPAND)
 819         ctrlSizer.Add(self.hyphen1, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 820         ctrlSizer.Add(self.txPhone2, 1, wx.EXPAND)
 821         ctrlSizer.Add(self.hyphen2, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 822         ctrlSizer.Add(self.txPhone3, 1, wx.EXPAND)
 823         ctrlSizer.Add(self.hyphen3, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 824         ctrlSizer.Add(self.txPhone4, 1, wx.EXPAND)
 825         ctrlSizer.Add(self.hyphen4, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5)
 826         ctrlSizer.Add(self.txPhone5, 1, wx.EXPAND)
 827 
 828         textSizer.Add(ctrlSizer, 1, wx.EXPAND)
 829 
 830         textSizer.Add(self.stEmail, 0, wx.ALIGN_CENTER_VERTICAL)
 831         textSizer.Add(self.txEmail, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
 832 
 833         # buttonSizer.
 834         buttonSizer.Add(self.bntSave)
 835         buttonSizer.Add((5, 5), -1)
 836         buttonSizer.Add(self.bntClose)
 837 
 838         # Assign to mainSizer the other sizers.
 839         mainSizer.Add(textSizer, 0, wx.ALL, 10)
 840         mainSizer.Add(buttonSizer, 0, wx.ALL, 10)
 841 
 842         # Assign to panel the mainSizer.
 843         self.panel.SetSizer(mainSizer)
 844         mainSizer.Fit(self)
 845         mainSizer.SetSizeHints(self)
 846 
 847 
 848     def FieldsControl(self):
 849         """
 850         ...
 851         """
 852 
 853         if len(self.txSurname.GetValue()) == 0:
 854                 wx.MessageBox('ATTENTION !\nThe "Surname" field is empty !',
 855                               AppTitle,
 856                               wx.OK | wx.ICON_INFORMATION)
 857 
 858                 self.txSurname.SetFocus()
 859 
 860                 return 0
 861 
 862         elif len(self.txFirstname.GetValue()) == 0:
 863                 wx.MessageBox('ATTENTION !\nThe "First name" field is empty !',
 864                               AppTitle,
 865                               wx.OK | wx.ICON_INFORMATION)
 866 
 867                 return 0
 868 
 869         elif len(self.txPhone1.GetValue()) < 2:
 870                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 871                               "Phone number",
 872                               wx.OK | wx.ICON_INFORMATION)
 873 
 874                 return 0
 875 
 876         elif len(self.txPhone2.GetValue()) < 2:
 877                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 878                               "Phone number",
 879                               wx.OK | wx.ICON_INFORMATION)
 880 
 881                 return 0
 882 
 883         elif len(self.txPhone3.GetValue()) < 2:
 884                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 885                               "Phone number",
 886                               wx.OK | wx.ICON_INFORMATION)
 887 
 888                 return 0
 889 
 890         elif len(self.txPhone4.GetValue()) < 2:
 891                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 892                               "Phone number",
 893                               wx.OK | wx.ICON_INFORMATION)
 894 
 895                 return 0
 896 
 897         elif len(self.txPhone5.GetValue()) < 2:
 898                 wx.MessageBox('ATTENTION !\nThe "Phone" field is empty or icomplete !',
 899                               "Phone number",
 900                               wx.OK | wx.ICON_INFORMATION)
 901 
 902                 return 0
 903 
 904         elif len(self.txEmail.GetValue()) == 0:
 905                 wx.MessageBox('ATTENTION !\nThe "Email" field is empty !',
 906                               AppTitle,
 907                               wx.OK | wx.ICON_INFORMATION)
 908 
 909                 return 0
 910 
 911 
 912     def OnSave(self, event):
 913         """
 914         ...
 915         """
 916 
 917         if self.FieldsControl()==0:
 918 
 919             return
 920 
 921         else:
 922             sMessage = "Save update data?"
 923             dlgAsk = wx.MessageDialog(None,
 924                                       sMessage,
 925                                       AppTitle,
 926                                       wx.YES_NO | wx.ICON_QUESTION)
 927 
 928             retCode = dlgAsk.ShowModal()
 929 
 930             if (retCode == wx.ID_YES):
 931 
 932                 sEmployeeID = str(self.txEmployeeID.GetValue())
 933                 sSurname = str(self.txSurname.GetValue())
 934                 sFirstname = str(self.txFirstname.GetValue())
 935                 #--
 936                 value1 = str(self.txPhone1.GetValue())
 937                 value2 = str(self.txPhone2.GetValue())
 938                 value3 = str(self.txPhone3.GetValue())
 939                 value4 = str(self.txPhone4.GetValue())
 940                 value5 = str(self.txPhone5.GetValue())
 941                 number = value1 + value2 + value3 + value4 + value5
 942                 sPhone = self.AddHyphens(number)
 943                 #--
 944                 sEmail = str(self.txEmail.GetValue())
 945 
 946                 UpdateParameters = (sSurname,
 947                                     sFirstname,
 948                                     sPhone,
 949                                     sEmail,
 950                                     sEmployeeID)
 951 
 952                 sSQL = "UPDATE Employees SET Surname = ?, \
 953                                              Firstname = ?, \
 954                                              Phone = ?, \
 955                                              Email = ? \
 956                                        WHERE EmployeeID = ?"
 957 
 958                 # Update the database.
 959                 self.con.OnQueryUpdate(sSQL, UpdateParameters)
 960 
 961                 # Guldo... thank you !
 962                 self.caller.OnUpdateList()
 963 
 964                 wx.MessageBox("Data update!",
 965                               AppTitle,
 966                               wx.OK | wx.ICON_INFORMATION)
 967 
 968             elif (retCode == wx.ID_NO):
 969                 wx.MessageBox("Update operation aborted!",
 970                               AppTitle,
 971                               wx.OK | wx.ICON_INFORMATION)
 972 
 973             dlgAsk.Destroy()
 974             self.OnExit(self)
 975 
 976 
 977     def OnUpperCaseText(self, event):
 978         """
 979         ...
 980         """
 981 
 982         # Write in upper mode on widgets the call it.
 983         # Adapted from a script of David Hughes
 984         # Forestfield Software.
 985         # Retrive the widget.
 986         wdgControl = event.GetEventObject()
 987 
 988         # Retrive what we have write.
 989         retValue = wdgControl.GetValue()
 990 
 991         # Upper it.
 992         upValue = retValue.upper()
 993 
 994         if retValue != upValue:
 995             wdgControl.SetValue(upValue)
 996             # Insert it at the end.
 997             wdgControl.SetInsertionPointEnd()
 998 
 999         event.Skip()
1000 
1001 
1002     def OnLowerCaseText(self, event):
1003         """
1004         ...
1005         """
1006 
1007         # Write in upper mode on widgets the call it.
1008         # Adapted from a script of David Hughes
1009         # Forestfield Software.
1010         # Retrive the widget.
1011         wdgControl = event.GetEventObject()
1012 
1013         # Retrive what we have write.
1014         retValue = wdgControl.GetValue()
1015 
1016         # Upper it.
1017         upValue = retValue.lower()
1018 
1019         if retValue != upValue:
1020             wdgControl.SetValue(upValue)
1021             # Insert it at the end.
1022             wdgControl.SetInsertionPointEnd()
1023 
1024         event.Skip()
1025 
1026 
1027     def OnCapitalizeCaseText(self, event):
1028         """
1029         ...
1030         """
1031 
1032         # Write in upper mode on widgets the call it.
1033         # Adapted from a script of David Hughes
1034         # Forestfield Software.
1035         # Retrive the widget.
1036         wdgControl = event.GetEventObject()
1037 
1038         # Retrive what we have write.
1039         retValue = wdgControl.GetValue()
1040 
1041         # Upper it.
1042         upValue = retValue.lower().capitalize()
1043 
1044         if retValue != upValue:
1045             wdgControl.SetValue(upValue)
1046             # Insert it at the end.
1047             wdgControl.SetInsertionPointEnd()
1048 
1049         event.Skip()
1050 
1051 
1052     def OnChar(self, event):
1053         """
1054         Block non numbers.
1055         """
1056 
1057         # print("\ndef OnChar")
1058 
1059         key_code = event.GetKeyCode()
1060 
1061         # Allow ASCII numerics.
1062         if ord('0') <= key_code <= ord('9'):
1063             event.Skip()
1064             return
1065 
1066         # Allow decimal points.
1067         if key_code == ord('.'):
1068             event.Skip()
1069             return
1070 
1071         # Allow tabs, for tab navigation between TextCtrls.
1072         if key_code == ord('\t'):
1073             event.Skip()
1074             return
1075 
1076         # Enable backspace, del, left-right.
1077         # The values may be platform dependent.
1078         if key_code in (8, 127, 314, 316):
1079             event.Skip()
1080             return
1081 
1082         # Block everything else.
1083         return
1084 
1085 
1086     def AddHyphens(self, nb):
1087         """
1088         ...
1089         """
1090 
1091         phone = nb[0:2] + '-' + nb[2:4] + '-' + nb[4:6] + '-' + nb[6:8] + '-' + nb[8:10]
1092 
1093         return phone
1094 
1095 
1096     def OnExit(self, event):
1097         """
1098         ...
1099         """
1100 
1101         self.Destroy()
1102 
1103 #-------------------------------------------------------------------------------
1104 
1105 class MyListCtrl(wx.ListCtrl,
1106                  # listmix.ListRowHighlighter,
1107                  listmix.ColumnSorterMixin,
1108                  listmix.ListCtrlAutoWidthMixin):
1109     """
1110     ...
1111     """
1112     def __init__(self, parent, id, pos=wx.DefaultPosition,
1113                  size=wx.DefaultSize, style=0):
1114         super(MyListCtrl, self).__init__(parent, ID_LIST, pos, size, style)
1115 
1116         #------------
1117 
1118         # Returns bitmaps folder.
1119         self.bitmaps_dir = wx.GetApp().GetBitmapsDir()
1120 
1121         #------------
1122 
1123         # Simplified init method
1124         self.ConnectDb()
1125         self.OpenDatabase()
1126         self.CreateColumns()
1127         self.SetProperties()
1128         self.PopulateListCtrl()
1129         self.BindEvents()
1130 
1131         #------------
1132 
1133         # Mixins.
1134         # Now that the list exists we can init the other base class.
1135         # listmix.ListRowHighlighter.__init__(self)
1136 
1137         # Initialize the listCtrl auto width.
1138         listmix.ListCtrlAutoWidthMixin.__init__(self)
1139 
1140         # Initialize the column sorter.
1141         listmix.ColumnSorterMixin.__init__(self, self.GetColumnCount())
1142         # or
1143         # listmix.ColumnSorterMixin.__init__(self, 5)
1144 
1145         #------------
1146 
1147         self.SortListItems(0, True)
1148 
1149     #---------------------------------------------------------------------------
1150 
1151     def ConnectDb(self):
1152         """
1153         Connection to the database.
1154         """
1155 
1156         self.con = MyConnection()
1157 
1158 
1159     def OpenDatabase(self):
1160         """
1161         Open and connect the database.
1162         """
1163 
1164         # Retrieve employees data from database
1165         # using the class named MyConnection.
1166         strSQL = "SELECT * FROM Employees"
1167 
1168         # The recordset retrieved
1169         self.rsRecordset = self.con.OnQuery(strSQL)
1170         self.items = self.rsRecordset
1171 
1172         return self.rsRecordset
1173 
1174 
1175     def CreateColumns(self):
1176         """
1177         Create columns for listCtrl.
1178         """
1179 
1180         columns = ["ID",
1181                    "Surname",
1182                    "First name",
1183                    "Phone",
1184                    "Email"]
1185 
1186         # Add some columns (x5).
1187         for col, header in enumerate(columns):
1188             self.InsertColumn(col, header)
1189 
1190         #------------
1191 
1192         # Set the width of the columns (x5).
1193         # Integer, wx.LIST_AUTOSIZE or wx.LIST_AUTOSIZE_USEHEADER.
1194         for col, width in enumerate((55,
1195                                      130,
1196                                      130,
1197                                      110,
1198                                      2000)):
1199             self.SetColumnWidth(col, width)
1200 
1201 
1202     def SetProperties(self):
1203         """
1204         Set the list control properties (icon, font, size...).
1205         """
1206 
1207         # Font size and style for listCtrl.
1208         fontSize = self.GetFont().GetPointSize()
1209 
1210         # Text attributes for columns title.
1211         # wx.Font(pointSize, family, style, weight, underline, faceName)
1212         if wx.Platform in ["__WXMAC__", "__WXGTK__"]:
1213             boldFont = wx.Font(fontSize-1,
1214                                wx.DEFAULT,
1215                                wx.NORMAL,
1216                                wx.NORMAL,
1217                                False, "")
1218             self.SetForegroundColour("black")
1219             self.SetBackgroundColour("#ece9d8")
1220 
1221         else:
1222             boldFont = wx.Font(fontSize,
1223                                wx.DEFAULT,
1224                                wx.NORMAL,
1225                                wx.BOLD,
1226                                False, "")
1227             self.SetForegroundColour("#808080")
1228             self.SetBackgroundColour("#ece9d8")
1229 
1230         self.SetFont(boldFont)
1231 
1232         #------------
1233 
1234         # Image list.
1235         self.il = wx.ImageList(16, 16, True)
1236 
1237         # Set an icon for the first column.
1238         self.bmp1 = wx.Bitmap(os.path.join(self.bitmaps_dir,
1239                                            "employee.png"),
1240                               type=wx.BITMAP_TYPE_PNG)
1241 
1242 
1243         # Add some arrows for the column sorter.
1244         self.bmp2  = wx.Bitmap(os.path.join(self.bitmaps_dir,
1245                                             "sm_up.png"),
1246                                type=wx.BITMAP_TYPE_PNG)
1247 
1248         self.bmp3 = wx.Bitmap(os.path.join(self.bitmaps_dir,
1249                                            "sm_down.png"),
1250                               type=wx.BITMAP_TYPE_PNG)
1251 
1252         # Add images to list.
1253         self.img_idx = self.il.Add(self.bmp1)
1254         self.sm_up = self.il.Add(self.bmp2)
1255         self.sm_down = self.il.Add(self.bmp3)
1256 
1257         # Assign the image list to it.
1258         self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
1259 
1260 
1261     def PopulateListCtrl(self):
1262         """
1263         Fill the wx.ListCtrl.
1264         """
1265 
1266         # Add the rows;
1267         self.itemDataMap = {}
1268 
1269         # Populate the wx.ListCtrl.
1270         for item in self.rsRecordset:
1271             index = self.InsertItem(self.GetItemCount(),
1272                                              ((str(item[0]))))
1273             self.SetItem(index, 1, item[1])
1274             self.SetItem(index, 2, item[2])
1275             self.SetItem(index, 3, item[3])
1276             self.SetItem(index, 4, item[4])
1277 
1278             # Not useful.
1279             self.SetItemImage(self.GetItemCount() - 1,
1280                               self.img_idx)
1281 
1282             # Give each item a data value, and map it back
1283             # to the item values, for the column sorter.
1284             self.SetItemData(index, index)
1285             self.itemDataMap[index] = item
1286 
1287             # Alternate the row colors of a ListCtrl.
1288             # Mike Driscoll... thank you !
1289             if index % 2:
1290                 self.SetItemBackgroundColour(index, "#ffffff")
1291             else:
1292                 self.SetItemBackgroundColour(index, "#ece9d8")
1293 
1294 
1295     def BindEvents(self):
1296         """
1297         Bind all the events related to my frame.
1298         """
1299 
1300         # Intercept the click on the wx.ListCtrl.
1301         self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=ID_LIST)
1302         self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, id=ID_LIST)
1303         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_LIST)
1304         self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, id=ID_LIST)
1305         self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, id=ID_LIST)
1306         self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, id=ID_LIST)
1307         self.Bind(wx.EVT_LIST_COL_CLICK, self.OnSort, id=ID_LIST)
1308 
1309 
1310     def GetListCtrl(self):
1311         """
1312         Used by the ColumnSorterMixin.
1313         """
1314 
1315         # Alternate the row colors of a ListCtrl.
1316         if self.GetItemCount() > 0:
1317             for x in range(self.GetItemCount()):
1318                 if x % 2 == 0:
1319                     self.SetItemBackgroundColour(x, "#ffffff")
1320                 else:
1321                     self.SetItemBackgroundColour(x, "#ece9d8")
1322 
1323         return self
1324 
1325 
1326     def GetSortImages(self):
1327         """
1328         Used by the ColumnSorterMixin.
1329         """
1330 
1331         return (self.sm_down, self.sm_up)
1332 
1333 
1334     def GetColumnText(self, index, col):
1335         """
1336         ...
1337         """
1338 
1339         item = self.GetItem(index, col)
1340         return item.GetText()
1341 
1342 
1343     def OnItemSelected(self, event):
1344         """
1345         ...
1346         """
1347 
1348         global iEmployees
1349 
1350         #------------
1351 
1352         self.currentItem = event.Index
1353 
1354         item = self.GetItem(self.currentItem)
1355 
1356         iEmployees = item.GetText()
1357 
1358         #------------
1359 
1360         # Show what was selected in the frame status bar.
1361         frame = self.GetTopLevelParent()
1362         frame.PushStatusText("Selected employee = %s " %(iEmployees), 1)
1363 
1364 
1365     def OnItemDeselected(self, event):
1366         """
1367         ...
1368         """
1369 
1370         item = event.GetItem()
1371         print("OnItemDeselected: %d" % event.Index)
1372 
1373         # Show how to reselect something we don't want deselected.
1374         # if event.Index == 11:
1375         #     wx.CallAfter(self.list.SetItemState, 11, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
1376 
1377 
1378     def OnItemActivated(self, event):
1379         """
1380         ...
1381         """
1382 
1383         self.currentItem = event.GetIndex()
1384 
1385         item = self.GetItem(self.currentItem)
1386 
1387         iEmployee = item.GetText()
1388 
1389         #------------
1390 
1391         # Show what was selected in the frame status bar.
1392         frame = self.GetTopLevelParent()
1393         frame.PushStatusText("Selected employee = %s " %(iEmployee), 1)
1394 
1395         #------------
1396 
1397         frame.OnEdit(event)
1398 
1399 
1400     def OnRetrieveData(self, sSQL, IDParameter):
1401         """
1402         ...
1403         """
1404 
1405         global iEmployees
1406 
1407         # Delete the item from listctrl.
1408         self.SetFocus()
1409         self.DeleteAllItems()
1410 
1411         # Retrieve the products recordset from data module.
1412         self.employeeData = self.con.OnQueryParameter(sSQL, IDParameter)
1413 
1414         # Add the rows;
1415         self.itemDataMap = {}
1416 
1417         # Populate the listctrl.
1418         if self.employeeData:
1419             for item in self.employeeData:
1420                 index = self.InsertItem(self.GetItemCount(),
1421                                                  ((str(item[0]))))
1422                 self.SetItem(index, 1, item[1])
1423                 self.SetItem(index, 2, item[2])
1424                 self.SetItem(index, 3, item[3])
1425                 self.SetItem(index, 4, item[4])
1426 
1427                 # Not useful.
1428                 self.SetItemImage(self.GetItemCount() - 1,
1429                                            self.img_idx)
1430 
1431                 # Give each item a data value, and map it back
1432                 # to the item values, for the column sorter.
1433                 self.SetItemData(index, index)
1434                 self.itemDataMap[index] = item
1435 
1436                 # Alternate the row colors of a ListCtrl.
1437                 # Mike Driscoll... thank you !
1438                 if index % 2:
1439                     self.SetItemBackgroundColour(index, "#ffffff")
1440                 else:
1441                     self.SetItemBackgroundColour(index, "#ece9d8")
1442 
1443         else:
1444              wx.MessageBox("ATTENTION !\nNo results for your research criteria.\nTry with another criteria !",
1445                            AppTitle,
1446                            wx.OK | wx.ICON_INFORMATION)
1447 
1448 
1449     def OnRightDown(self, event):
1450         """
1451         Right down.
1452         """
1453 
1454         x = event.GetX()
1455         y = event.GetY()
1456 
1457         item, flags = self.HitTest((x, y))
1458 
1459         if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
1460             self.Select(item)
1461 
1462         #------------
1463 
1464         # Tell the event system to continue
1465         # looking for an event handler, so the
1466         # default handler will get called.
1467         event.Skip()
1468 
1469 
1470     def OnColClick(self, event):
1471         """
1472         Column click.
1473         """
1474 
1475         count = self.GetItemCount()
1476         self.sortedEmployees = [self.GetItem(row, col=0).GetText() for row in range(count)]
1477 
1478         #------------
1479 
1480         # Tell the event system to continue
1481         # looking for an event handler, so the
1482         # default handler will get called.
1483         event.Skip()
1484 
1485 
1486     def OnSort(self, event):
1487         """
1488         Sort column.
1489         """
1490 
1491         idx = event.GetColumn()
1492 
1493 
1494     def OnColRightClick(self, event):
1495         """
1496         Column right click.
1497         """
1498 
1499         item = self.GetColumn(event.GetColumn())
1500 
1501         #------------
1502 
1503         if self.HasColumnOrderSupport():
1504             print("... Column order : %d" %
1505                   (self.GetColumnOrder(event.GetColumn())))
1506 
1507 
1508     def OnColBeginDrag(self, event):
1509         """
1510         Show how to not allow a column to be resized.
1511         """
1512 
1513         if event.GetColumn() == 0:
1514             event.Veto()
1515 
1516 #-------------------------------------------------------------------------------
1517 
1518 class MyFrame(wx.Frame):
1519     """
1520     ...
1521     """
1522     def __init__(self, parent, id, title,
1523                  style=wx.DEFAULT_FRAME_STYLE |
1524                        wx.NO_FULL_REPAINT_ON_RESIZE |
1525                        wx.CLIP_CHILDREN):
1526         super(MyFrame, self).__init__(parent=None,
1527                                       id=-1,
1528                                       title=title,
1529                                       style=style)
1530 
1531         #------------
1532 
1533         # Returns application name.
1534         self.app_name = wx.GetApp().GetAppName()
1535         # Returns bitmaps folder.
1536         self.bitmaps_dir = wx.GetApp().GetBitmapsDir()
1537         # Returns icons folder.
1538         self.icons_dir = wx.GetApp().GetIconsDir()
1539 
1540         #------------
1541 
1542         # Simplified init method.
1543         self.ConnectDb()
1544         self.SetProperties()
1545         self.MakeMenuBar()
1546         self.MakeStatusBar()
1547         self.CreateCtrls()
1548         self.BindEvents()
1549         self.DoLayout()
1550 
1551         #------------
1552 
1553         # Clock.
1554         self.OnTimer(None)
1555 
1556         self.timer = wx.Timer(self)
1557         self.timer.Start(3000)
1558         self.Bind(wx.EVT_TIMER, self.OnTimer)
1559 
1560     #---------------------------------------------------------------------------
1561 
1562     def ConnectDb(self):
1563         """
1564         Connection to the database.
1565         """
1566 
1567         # Instance from Class MyConnection.
1568         self.con = MyConnection()
1569 
1570 
1571     def SetProperties(self):
1572         """
1573         Set the frame properties (title, icon, size...).
1574         """
1575 
1576         # Setting some frame properties.
1577         frameIcon = wx.Icon(os.path.join(self.icons_dir,
1578                                          "icon_wxWidgets.ico"),
1579                             type=wx.BITMAP_TYPE_ICO)
1580         self.SetIcon(frameIcon)
1581 
1582         #------------
1583 
1584         # Frame cursor.
1585         cursorHand = wx.Cursor(os.path.join(self.icons_dir,
1586                                             "hand.cur"),
1587                                type=wx.BITMAP_TYPE_CUR)
1588         self.SetCursor(cursorHand)
1589 
1590         #------------
1591 
1592         self.SetTitle(("%s") % (self.app_name))
1593 
1594 
1595     def MakeMenuBar(self):
1596         """
1597         Create the menu bar for my app.
1598         """
1599 
1600         # Set an icon to the exit/about menu item.
1601         emptyImg = wx.Bitmap(os.path.join(self.bitmaps_dir,
1602                                           "item_empty.png"),
1603                              type=wx.BITMAP_TYPE_PNG)
1604 
1605         exitImg = wx.Bitmap(os.path.join(self.bitmaps_dir,
1606                                          "item_exit.png"),
1607                             type=wx.BITMAP_TYPE_PNG)
1608 
1609         helpImg = wx.Bitmap(os.path.join(self.bitmaps_dir,
1610                                          "item_about.png"),
1611                             type=wx.BITMAP_TYPE_PNG)
1612 
1613         #------------
1614 
1615         # menu.
1616         mnuFile = wx.Menu()
1617         mnuInfo = wx.Menu()
1618 
1619         # mnuFile.
1620         # Show how to put an icon in the menu item.
1621         menuItem1 = wx.MenuItem(mnuFile, -1, "W&IT\tCtrl+Alt+I", "Widget Inspection Tool !")
1622         menuItem1.SetBitmap(emptyImg)
1623         mnuFile.Append(menuItem1)
1624         self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, menuItem1)
1625 
1626         # Show how to put an icon in the menu item.
1627         menuItem2 = wx.MenuItem(mnuFile, wx.ID_EXIT, "&Quit\tCtrl+Q", "Close !")
1628         menuItem2.SetBitmap(exitImg)
1629         mnuFile.Append(menuItem2)
1630         self.Bind(wx.EVT_MENU, self.OnExit, menuItem2)
1631 
1632         # mnuInfo.
1633         # Show how to put an icon in the menu item.
1634         menuItem2 = wx.MenuItem(mnuInfo, wx.ID_ABOUT, "A&bout\tCtrl+A", "Info about developers !")
1635         menuItem2.SetBitmap(helpImg)
1636         mnuInfo.Append(menuItem2)
1637         self.Bind(wx.EVT_MENU, self.OnAbout, menuItem2)
1638 
1639         # menuBar.
1640         menubar = wx.MenuBar()
1641 
1642         # Add menu voices.
1643         menubar.Append(mnuFile, "&File")
1644         menubar.Append(mnuInfo, "I&nfo")
1645 
1646         self.SetMenuBar(menubar)
1647 
1648 
1649     def MakeStatusBar(self):
1650         """
1651         Create the status bar for my frame.
1652         """
1653 
1654         # Statusbar.
1655         self.myStatusBar = self.CreateStatusBar(1)
1656         self.myStatusBar.SetFieldsCount(2)
1657         self.myStatusBar.SetStatusWidths([-8, -4])
1658         self.myStatusBar.SetStatusText("", 0)
1659         self.myStatusBar.SetStatusText("Python-it.org.", 1)
1660 
1661 
1662     def CreateCtrls(self):
1663         """
1664         Create some controls for my frame.
1665         """
1666 
1667         # Font style for wx.StaticText.
1668         font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
1669         font.SetWeight(wx.BOLD)
1670 
1671         #------------
1672 
1673         # Widgets.
1674         self.panel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
1675 
1676         self.stEmployees = wx.StaticText(self.panel, -1, "Employees list :")
1677         self.stEmployees.SetForegroundColour("gray")
1678         self.stEmployees.SetFont(font)
1679 
1680         self.listCtrl = MyListCtrl(self.panel,
1681                                    id=ID_LIST,
1682                                    style=wx.LC_REPORT |
1683                                          wx.LC_SINGLE_SEL |
1684                                          wx.LC_VRULES |
1685                                          wx.BORDER_SUNKEN)
1686 
1687         self.stSearch = wx.StaticText(self.panel, -1, 'Search "Surname :')
1688         self.txSearch = wx.TextCtrl(self.panel, -1, "", size=(100, -1))
1689         self.txSearch.SetToolTip("Search employee !")
1690 
1691         self.StaticSizer = wx.StaticBox(self.panel, -1, "Commands :")
1692         self.StaticSizer.SetForegroundColour("red")
1693         self.StaticSizer.SetFont(font)
1694 
1695         self.bntSearch = wx.Button(self.panel, -1, "&Search")
1696         self.bntSearch.SetToolTip("Search employee !")
1697 
1698         self.bntClear = wx.Button(self.panel, -1, "&Clear")
1699         self.bntClear.SetToolTip("Clear the search text !")
1700 
1701         self.bntShowAll = wx.Button(self.panel, -1, "&All")
1702         self.bntShowAll.SetToolTip("Show all !")
1703 
1704         self.bntNew = wx.Button(self.panel, -1, "&Insert")
1705         self.bntNew.SetToolTip("Insert a new employee !")
1706 
1707         self.bntEdit = wx.Button(self.panel, -1, "&Update")
1708         self.bntEdit.SetToolTip("Update selected employee !")
1709 
1710         self.bntDelete = wx.Button(self.panel, -1, "&Delete")
1711         self.bntDelete.SetToolTip("Delete selected employee !")
1712 
1713         self.bntClose = wx.Button(self.panel, -1, "&Quit")
1714         self.bntClose.SetToolTip("Close !")
1715 
1716 
1717     def BindEvents(self):
1718         """
1719         Bind all the events related to my frame.
1720         """
1721 
1722         self.txSearch.Bind(wx.EVT_TEXT, self.OnUpperCaseText)
1723 
1724         self.Bind(wx.EVT_BUTTON, self.OnSearch, self.bntSearch)
1725         self.Bind(wx.EVT_BUTTON, self.OnClear, self.bntClear)
1726         self.Bind(wx.EVT_BUTTON, self.OnShowAll, self.bntShowAll)
1727         self.Bind(wx.EVT_BUTTON, self.OnNew, self.bntNew)
1728         self.Bind(wx.EVT_BUTTON, self.OnEdit, self.bntEdit)
1729         self.Bind(wx.EVT_BUTTON, self.OnDelete, self.bntDelete)
1730         self.Bind(wx.EVT_BUTTON, self.OnExit, self.bntClose)
1731 
1732         self.Bind(wx.EVT_CLOSE, self.OnExit)
1733 
1734 
1735     def DoLayout(self):
1736         """
1737         Do layout.
1738         """
1739 
1740         # Sizer.
1741         mainSizer = wx.BoxSizer(wx.HORIZONTAL)
1742         textSizer = wx.BoxSizer(wx.VERTICAL)
1743         btnSizer = wx.StaticBoxSizer(self.StaticSizer, wx.VERTICAL)
1744 
1745         # Assign widgets to sizers.
1746 
1747         # textSizer.
1748         textSizer.Add(self.stEmployees, 0, wx.BOTTOM, 5)
1749         textSizer.Add(self.listCtrl, 1, wx.EXPAND)
1750 
1751         # btnSizer.
1752         btnSizer.Add(self.stSearch)
1753         btnSizer.Add(self.txSearch)
1754         btnSizer.Add((5, 5), -1)
1755         btnSizer.Add(self.bntSearch, 0, wx.ALL, 5)
1756         btnSizer.Add((5, 5), -1)
1757         btnSizer.Add(self.bntClear, 0, wx.ALL, 5)
1758         btnSizer.Add((5, 5), -1)
1759         btnSizer.Add(self.bntShowAll, 0, wx.ALL, 5)
1760         btnSizer.Add((5, 5), -1)
1761         btnSizer.Add(self.bntNew, 0, wx.ALL, 5)
1762         btnSizer.Add((5, 5), -1)
1763         btnSizer.Add(self.bntEdit, 0, wx.ALL, 5)
1764         btnSizer.Add((5, 5), -1)
1765         btnSizer.Add(self.bntDelete, 0, wx.ALL, 5)
1766         btnSizer.Add((5, 5), -1)
1767         btnSizer.Add(self.bntClose, 0, wx.ALL, 5)
1768 
1769         # Assign to mainSizer the other sizers.
1770         mainSizer.Add(textSizer, 1, wx.ALL | wx.EXPAND, 10)
1771         mainSizer.Add(btnSizer, 0, wx.ALL, 10)
1772 
1773         # Assign to panel the mainSizer.
1774         self.panel.SetSizer(mainSizer)
1775         mainSizer.Fit(self)
1776         # mainSizer.SetSizeHints(self)
1777 
1778 
1779     def OnDelete(self, event):
1780         """
1781         ...
1782         """
1783 
1784         global iEmployees
1785 
1786         # It means that we haven't select a record.
1787         if iEmployees ==0:
1788              wx.MessageBox("ATTENTION !\nSelect an employee !",
1789                            AppTitle,
1790                            wx.OK | wx.ICON_INFORMATION)
1791 
1792              return
1793 
1794         else:
1795             # Ask for delete.
1796             sMessage = "Delete selected employee ? %s " %(iEmployees)
1797             dlgAsk = wx.MessageDialog(None,
1798                                       sMessage,
1799                                       AppTitle,
1800                                       wx.YES_NO | wx.ICON_QUESTION)
1801 
1802             retCode = dlgAsk.ShowModal()
1803 
1804             if (retCode == wx.ID_YES):
1805 
1806                 sSQL = "DELETE FROM Employees WHERE EmployeeID = ?"
1807                 self.con.OnQueryParameter(sSQL, iEmployees)
1808 
1809                 self.OnShowAll(self)
1810 
1811                 wx.MessageBox("Delete operation terminate !",
1812                               AppTitle,
1813                               wx.OK | wx.ICON_INFORMATION)
1814 
1815             elif (retCode == wx.ID_NO):
1816                 wx.MessageBox("Delete operation aborted !",
1817                               AppTitle,
1818                               wx.OK | wx.ICON_INFORMATION)
1819 
1820             dlgAsk.Destroy()
1821 
1822 
1823     def OnUpdateList(self):
1824         """
1825         ...
1826         """
1827 
1828         self.OnShowAll(self)
1829 
1830 
1831     def OnShowAll(self, event):
1832         """
1833         ...
1834         """
1835 
1836         wx.BeginBusyCursor()
1837 
1838         sSQL = "SELECT * FROM Employees WHERE EmployeeID LIKE ? "
1839         sSearch = "%"
1840 
1841         self.listCtrl.OnRetrieveData(sSQL, sSearch)
1842 
1843         self.myStatusBar.SetStatusText("Python-it.org.", 1)
1844 
1845         self.OnClear(self)
1846 
1847         wx.CallAfter(wx.EndBusyCursor)
1848 
1849 
1850     def OnClear(self, event):
1851         """
1852         ...
1853         """
1854 
1855         global iEmployees
1856 
1857         sSQL = "SELECT * FROM Employees WHERE EmployeeID LIKE ? "
1858         sSearch = "%"
1859 
1860         self.listCtrl.OnRetrieveData(sSQL, sSearch)
1861 
1862         self.txSearch.Clear()
1863         self.txSearch.SetFocus()
1864 
1865         iEmployees = 0
1866 
1867 
1868     def OnSearch(self, event):
1869         """
1870         ...
1871         """
1872 
1873         # Retrieve what we have write.
1874         sSearch = str(self.txSearch.GetValue())
1875 
1876         # Remove spaces.
1877         # sSearch = "".join(sSearch.strip().split())
1878 
1879         # Add & symbol to force the search.
1880         sSearch = sSearch+"%"
1881 
1882         # Control if we have write something
1883         # before launch the research.
1884         if sSearch == "%" :
1885                 wx.MessageBox("ATTENTION !\nThe search text is empty !",
1886                               AppTitle,
1887                               wx.OK | wx.ICON_INFORMATION)
1888 
1889                 self.txSearch.SetFocus()
1890 
1891                 return
1892 
1893         else:
1894             sSQL = "SELECT * FROM Employees WHERE Surname LIKE ? "
1895             self.listCtrl.OnRetrieveData(sSQL, sSearch)
1896 
1897 
1898     def OnEdit(self, event):
1899         """
1900         ...
1901         """
1902 
1903         global iEmployees
1904 
1905         # It means that we haven't select an employee.
1906         if iEmployees ==0:
1907              wx.MessageBox("ATTENTION !\nSelect an employee !",
1908                            AppTitle,
1909                            wx.OK | wx.ICON_INFORMATION)
1910 
1911              return
1912 
1913         else:
1914             sSQL = "SELECT * FROM Employees WHERE EmployeeID = ?"
1915             self.OnOpenEdit(sSQL, iEmployees)
1916 
1917 
1918     def OnNew(self, event):
1919         """
1920         ...
1921         """
1922 
1923         # Create an instance of the Child_Frame.
1924         self.dlgInsert = self.dlgInsert = MyInsertDlg(caller_dlgInsert=self)
1925 
1926         sTitle = "Insert new employee"
1927         self.dlgInsert.SetTitle(sTitle)
1928         self.dlgInsert.CenterOnParent(wx.BOTH)
1929         self.dlgInsert.ShowModal()
1930         self.dlgInsert.Destroy()
1931 
1932 
1933     def OnOpenEdit(self, sSQL, sParameter):
1934         """
1935         ...
1936         """
1937 
1938         # Retrieve data for the selected product.
1939         rsEmployees = self.con.OnQueryParameter(sSQL, sParameter)
1940 
1941         # Create an instance of the Child_Frame.
1942         self.dlgEdit = self.dlgEdit = MyUpdateDlg(caller_dlgUpdate=self)
1943 
1944         # Populate the fields of the frame with the recordset.
1945         for i in rsEmployees:
1946             self.dlgEdit.txEmployeeID.SetValue(str(i[0]))
1947             self.dlgEdit.txSurname.SetValue(str(i[1]))
1948             self.dlgEdit.txFirstname.SetValue(str(i[2]))
1949             self.dlgEdit.txPhone1.SetValue(str(i[3][0:2]))
1950             self.dlgEdit.txPhone2.SetValue(str(i[3][3:5]))
1951             self.dlgEdit.txPhone3.SetValue(str(i[3][6:8]))
1952             self.dlgEdit.txPhone4.SetValue(str(i[3][9:11]))
1953             self.dlgEdit.txPhone5.SetValue(str(i[3][12:14]))
1954             self.dlgEdit.txEmail.SetValue(str(i[4]))
1955 
1956             # We use this for the title of the frame.
1957             sEmployees =(str(i[1]))
1958 
1959         sTitle = "Select employee : %s" %(sEmployees)
1960         self.dlgEdit.SetTitle(sTitle)
1961         self.dlgEdit.CenterOnParent(wx.BOTH)
1962         self.dlgEdit.ShowModal()
1963         self.dlgEdit.Destroy()
1964 
1965 
1966     def OnUpperCaseText(self, event):
1967         """
1968         ...
1969         """
1970 
1971         # Write in upper mode on widgets the call it.
1972         # Adapted from a script of David Hughes
1973         # Forestfield Software.
1974         # Retrive the widget.
1975         wdgControl = event.GetEventObject()
1976 
1977         # Retrive what we have write.
1978         retValue = wdgControl.GetValue()
1979 
1980         # Upper it.
1981         upValue = retValue.upper()
1982 
1983         if retValue != upValue:
1984             wdgControl.SetValue(upValue)
1985             # Insert it at the end.
1986             wdgControl.SetInsertionPointEnd()
1987 
1988         event.Skip()
1989 
1990 
1991     def OnOpenWidgetInspector(self, event):
1992         """
1993         Activate the widget inspection tool,
1994         giving it a widget to preselect in the tree.
1995         Use either the one under the cursor,
1996         if any, or this frame.
1997         """
1998 
1999         from wx.lib.inspection import InspectionTool
2000         wnd = wx.FindWindowAtPointer()
2001         if not wnd:
2002             wnd = self
2003         InspectionTool().Show(wnd, True)
2004 
2005 
2006     def OnAbout(self, event):
2007         """
2008         ...
2009         """
2010 
2011         # Returns SQLite version.
2012         sSQLversion = self.con.OnSqliteVersion()
2013 
2014         message = """Python-it.org\n
2015                      How to use a wx.ListCtrl.
2016                      Developed in wxPython by Guldo and Beppe.\n
2017                      Modified and updated for wxPython Phoenix by Ecco :-)\n
2018                      Have fun ! ---> Amusez-vous bien !\n
2019                      SQLite version : %s""" %(sSQLversion)
2020 
2021         wx.MessageBox(message,
2022                       AppTitle,
2023                       wx.OK)
2024 
2025 
2026     def OnClose(self):
2027         """
2028         ...
2029         """
2030 
2031         ret=wx.MessageBox("Do you want exit ?",
2032                           AppTitle,
2033                           wx.YES_NO |wx.ICON_QUESTION|
2034                           wx.CENTRE |wx.NO_DEFAULT)
2035 
2036         return ret
2037 
2038 
2039     def OnExit(self, event):
2040         """
2041         ...
2042         """
2043 
2044         # Ask for exit.
2045         intChoice = self.OnClose()
2046 
2047         if intChoice == 2:
2048             # Disconnect from server.
2049             self.con.OnCloseDb()
2050             self.Destroy()
2051 
2052 
2053     def OnTimer(self, event):
2054         """
2055         ...
2056         """
2057 
2058         t = time.localtime(time.time())
2059         sbTime = time.strftime("Astral date %d/%m/%Y are %H:%M:%S", t)
2060         self.myStatusBar.SetStatusText(sbTime, 0)
2061 
2062 #-------------------------------------------------------------------------------
2063 
2064 class MyApp(wx.App, wx.lib.mixins.inspection.InspectionMixin):
2065     """
2066     Thanks to Andrea Gavana.
2067     """
2068     def OnInit(self):
2069 
2070         #------------
2071 
2072         self.locale = wx.Locale(wx.LANGUAGE_ENGLISH)
2073 
2074         #------------
2075 
2076         self.SetAppName("List of employees (v0.0.3) - Sort")
2077 
2078         #------------
2079 
2080         self.installDir = os.path.split(os.path.abspath(sys.argv[0]))[0]
2081 
2082         #------------
2083 
2084         # Simplified init method.
2085         # For the InspectionMixin base class.
2086         self.InitInspection()
2087 
2088         #------------
2089 
2090         frame = MyFrame(None, -1, title="")
2091         frame.SetSize(800, 527)
2092         self.SetTopWindow(frame)
2093         frame.Center()
2094         frame.Show(True)
2095 
2096         return True
2097 
2098     #---------------------------------------------------------------------------
2099 
2100     def GetInstallDir(self):
2101         """
2102         Returns the installation directory for my application.
2103         """
2104 
2105         return self.installDir
2106 
2107 
2108     def GetIconsDir(self):
2109         """
2110         Returns the icons directory for my application.
2111         """
2112 
2113         icons_dir = os.path.join(self.installDir, "icons")
2114         return icons_dir
2115 
2116 
2117     def GetBitmapsDir(self):
2118         """
2119         Returns the bitmaps directory for my application.
2120         """
2121 
2122         bitmaps_dir = os.path.join(self.installDir, "bitmaps")
2123         return bitmaps_dir
2124 
2125 
2126     def GetDatabaseDir(self):
2127         """
2128         Returns the database directory for my application.
2129         """
2130 
2131         if not os.path.exists("data"):
2132             # Create the data folder, it still doesn't exist.
2133             os.makedirs("data")
2134 
2135         database_dir = os.path.join(self.installDir, "data")
2136         return database_dir
2137 
2138 #-------------------------------------------------------------------------------
2139 
2140 def main():
2141     app = MyApp(redirect=False)
2142     app.MainLoop()
2143 
2144 #-------------------------------------------------------------------------------
2145 
2146 if __name__ == "__main__" :
2147     main()


Download source

source.zip


Additional Information

Link :

http://wxpython-users.1045709.n5.nabble.com/Example-of-Database-Interaction-td2361801.html

http://www.kitebird.com/articles/pydbapi.html

https://dabodev.com/

https://www.pgadmin.org/download/

https://github.com/1966bc/pyggybank

https://sourceforge.net/projects/pyggybank/

- - - - -

https://wiki.wxpython.org/TitleIndex

https://docs.wxpython.org/


Thanks to

Beppe / Guldo (sample_one.py coding), Giuseppe Costanzi, Python-it.org, Robin Dunn, Robin Rappin, Andrea Gavana, Mike Driscoll, Cody Precord, David Hughes and the wxPython community...


About this page

Date (d/m/y) Person (bot) Comments :

18/05/18 - Ecco (Created page, improved example and updated source for wxPython Phoenix).


Comments

- blah, blah, blah....

How to create a list control with a SQLite database (Phoenix) (last edited 2020-12-13 16:39:59 by Ecco)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.