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).
Contents
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
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
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
Additional Information
Link :
http://wxpython-users.1045709.n5.nabble.com/Example-of-Database-Interaction-td2361801.html
http://www.kitebird.com/articles/pydbapi.html
https://www.pgadmin.org/download/
https://github.com/1966bc/pyggybank
https://sourceforge.net/projects/pyggybank/
- - - - -
https://wiki.wxpython.org/TitleIndex
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....