1 """
2 @version: 0.92(2009-06-22)
3 @note:
4 EasyGui provides an easy-to-use interface for simple GUI interaction
5 with a user. It does not require the programmer to know anything about
6 tkinter, frames, widgets, callbacks or lambda. All GUI interactions are
7 invoked by simple function calls that return results.
8
9
10 @note:
11 WARNING about using EasyGui with IDLE
12
13 You may encounter problems using IDLE to run programs that use EasyGui. Try it
14 and find out. EasyGui is a collection of Tkinter routines that run their own
15 event loops. IDLE is also a Tkinter application, with its own event loop. The
16 two may conflict, with the unpredictable results. If you find that you have
17 problems, try running your program outside of IDLE.
18
19 Note that EasyGui requires Tk release 8.0 or greater.
20 """
21 egversion = __doc__.split()[1]
22
23
24
25 __all__ = ['ynbox'
26 , 'ccbox'
27 , 'boolbox'
28 , 'indexbox'
29 , 'msgbox'
30 , 'buttonbox'
31 , 'integerbox'
32 , 'multenterbox'
33 , 'enterbox'
34 , 'choicebox'
35 , 'codebox'
36 , 'textbox'
37 , 'diropenbox'
38 , 'fileopenbox'
39 , 'filesavebox'
40 , 'passwordbox'
41 , 'multpasswordbox'
42 , 'multchoicebox'
43 , 'abouteasygui'
44 , 'egversion'
45 , 'egdemo'
46 , 'EgStore'
47 ]
48
49 import sys, os, string, types, pickle
50
51
52
53
54 """
55 From the python documentation:
56
57 sys.hexversion contains the version number encoded as a single integer. This is
58 guaranteed to increase with each version, including proper support for non-
59 production releases. For example, to test that the Python interpreter is at
60 least version 1.5.2, use:
61
62 if sys.hexversion >= 0x010502F0:
63 # use some advanced feature
64 ...
65 else:
66 # use an alternative implementation or warn the user
67 ...
68 """
69 if sys.hexversion >= 0x020600F0: runningPython26 = True
70 else: runningPython26 = False
71
72 if sys.hexversion >= 0x030000F0: runningPython3 = True
73 else: runningPython3 = False
74
75 if runningPython3:
76 from tkinter import *
77 import tkinter.filedialog as tk_FileDialog
78 from io import StringIO
79 else:
80 from Tkinter import *
81 import tkFileDialog as tk_FileDialog
82 from StringIO import StringIO
83
85 args = [str(arg) for arg in args]
86 args = " ".join(args)
87 sys.stdout.write(args)
88
92
93
94 if TkVersion < 8.0 :
95 stars = "*"*75
96 writeln("""\n\n\n""" + stars + """
97 You are running Tk version: """ + str(TkVersion) + """
98 You must be using Tk version 8.0 or greater to use EasyGui.
99 Terminating.
100 """ + stars + """\n\n\n""")
101 sys.exit(0)
102
105
106 rootWindowPosition = "+300+200"
107
108 DEFAULT_FONT_FAMILY = ("MS", "Sans", "Serif")
109 MONOSPACE_FONT_FAMILY = ("Courier")
110 DEFAULT_FONT_SIZE = 10
111 BIG_FONT_SIZE = 12
112 SMALL_FONT_SIZE = 9
113 CODEBOX_FONT_SIZE = 9
114 TEXTBOX_FONT_SIZE = DEFAULT_FONT_SIZE
115
116
117 __choiceboxMultipleSelect = None
118 __widgetTexts = None
119 __replyButtonText = None
120 __choiceboxResults = None
121 __firstWidget = None
122 __enterboxText = None
123 __enterboxDefaultText=""
124 __multenterboxText = ""
125 choiceboxChoices = None
126 choiceboxWidget = None
127 entryWidget = None
128 boxRoot = None
129 ImageErrorMsg = (
130 "\n\n---------------------------------------------\n"
131 "Error: %s\n%s")
132
133
134
135
136
137
138
139 -def ynbox(msg="Shall I continue?"
140 , title=" "
141 , choices=("Yes", "No")
142 , image=None
143 ):
144 """
145 Display a msgbox with choices of Yes and No.
146
147 The default is "Yes".
148
149 The returned value is calculated this way::
150 if the first choice ("Yes") is chosen, or if the dialog is cancelled:
151 return 1
152 else:
153 return 0
154
155 If invoked without a msg argument, displays a generic request for a confirmation
156 that the user wishes to continue. So it can be used this way::
157 if ynbox(): pass # continue
158 else: sys.exit(0) # exit the program
159
160 @arg msg: the msg to be displayed.
161 @arg title: the window title
162 @arg choices: a list or tuple of the choices to be displayed
163 """
164 return boolbox(msg, title, choices, image=image)
165
166
167
168
169
170 -def ccbox(msg="Shall I continue?"
171 , title=" "
172 , choices=("Continue", "Cancel")
173 , image=None
174 ):
175 """
176 Display a msgbox with choices of Continue and Cancel.
177
178 The default is "Continue".
179
180 The returned value is calculated this way::
181 if the first choice ("Continue") is chosen, or if the dialog is cancelled:
182 return 1
183 else:
184 return 0
185
186 If invoked without a msg argument, displays a generic request for a confirmation
187 that the user wishes to continue. So it can be used this way::
188
189 if ccbox():
190 pass # continue
191 else:
192 sys.exit(0) # exit the program
193
194 @arg msg: the msg to be displayed.
195 @arg title: the window title
196 @arg choices: a list or tuple of the choices to be displayed
197 """
198 return boolbox(msg, title, choices, image=image)
199
200
201
202
203
204 -def boolbox(msg="Shall I continue?"
205 , title=" "
206 , choices=("Yes","No")
207 , image=None
208 ):
209 """
210 Display a boolean msgbox.
211
212 The default is the first choice.
213
214 The returned value is calculated this way::
215 if the first choice is chosen, or if the dialog is cancelled:
216 returns 1
217 else:
218 returns 0
219 """
220 reply = buttonbox(msg=msg, choices=choices, title=title, image=image)
221 if reply == choices[0]: return 1
222 else: return 0
223
224
225
226
227
228 -def indexbox(msg="Shall I continue?"
229 , title=" "
230 , choices=("Yes","No")
231 , image=None
232 ):
233 """
234 Display a buttonbox with the specified choices.
235 Return the index of the choice selected.
236 """
237 reply = buttonbox(msg=msg, choices=choices, title=title, image=image)
238 index = -1
239 for choice in choices:
240 index = index + 1
241 if reply == choice: return index
242 raise AssertionError(
243 "There is a program logic error in the EasyGui code for indexbox.")
244
245
246
247
248
249 -def msgbox(msg="(Your message goes here)", title=" ", ok_button="OK",image=None,root=None):
250 """
251 Display a messagebox
252 """
253 if type(ok_button) != type("OK"):
254 raise AssertionError("The 'ok_button' argument to msgbox must be a string.")
255
256 return buttonbox(msg=msg, title=title, choices=[ok_button], image=image,root=root)
257
258
259
260
261
342
343
344
345
346
347 -def integerbox(msg=""
348 , title=" "
349 , default=""
350 , argLowerBound=0
351 , argUpperBound=99
352 , image = None
353 , root = None
354 ):
355 """
356 Show a box in which a user can enter an integer.
357
358 In addition to arguments for msg and title, this function accepts
359 integer arguments for default_value, lowerbound, and upperbound.
360
361 The default_value argument may be None.
362
363 When the user enters some text, the text is checked to verify
364 that it can be converted to an integer between the lowerbound and upperbound.
365
366 If it can be, the integer (not the text) is returned.
367
368 If it cannot, then an error msg is displayed, and the integerbox is
369 redisplayed.
370
371 If the user cancels the operation, None is returned.
372 """
373 if default != "":
374 if type(default) != type(1):
375 raise AssertionError(
376 "integerbox received a non-integer value for "
377 + "default of " + dq(str(default)) , "Error")
378
379 if type(argLowerBound) != type(1):
380 raise AssertionError(
381 "integerbox received a non-integer value for "
382 + "argLowerBound of " + dq(str(argLowerBound)) , "Error")
383
384 if type(argUpperBound) != type(1):
385 raise AssertionError(
386 "integerbox received a non-integer value for "
387 + "argUpperBound of " + dq(str(argUpperBound)) , "Error")
388
389 if msg == "":
390 msg = ("Enter an integer between " + str(argLowerBound)
391 + " and "
392 + str(argUpperBound)
393 )
394
395 while 1:
396 reply = enterbox(msg, title, str(default), image=image, root=root)
397 if reply == None: return None
398
399 try:
400 reply = int(reply)
401 except:
402 msgbox ("The value that you entered:\n\t%s\nis not an integer." % dq(str(reply))
403 , "Error")
404 continue
405
406 if reply < argLowerBound:
407 msgbox ("The value that you entered is less than the lower bound of "
408 + str(argLowerBound) + ".", "Error")
409 continue
410
411 if reply > argUpperBound:
412 msgbox ("The value that you entered is greater than the upper bound of "
413 + str(argUpperBound) + ".", "Error")
414 continue
415
416
417
418 return reply
419
420
421
422
423 -def multenterbox(msg="Fill in values for the fields."
424 , title=" "
425 , fields=()
426 , values=()
427 ):
428 r"""
429 Show screen with multiple data entry fields.
430
431 If there are fewer values than names, the list of values is padded with
432 empty strings until the number of values is the same as the number of names.
433
434 If there are more values than names, the list of values
435 is truncated so that there are as many values as names.
436
437 Returns a list of the values of the fields,
438 or None if the user cancels the operation.
439
440 Here is some example code, that shows how values returned from
441 multenterbox can be checked for validity before they are accepted::
442 ----------------------------------------------------------------------
443 msg = "Enter your personal information"
444 title = "Credit Card Application"
445 fieldNames = ["Name","Street Address","City","State","ZipCode"]
446 fieldValues = [] # we start with blanks for the values
447 fieldValues = multenterbox(msg,title, fieldNames)
448
449 # make sure that none of the fields was left blank
450 while 1:
451 if fieldValues == None: break
452 errmsg = ""
453 for i in range(len(fieldNames)):
454 if fieldValues[i].strip() == "":
455 errmsg += ('"%s" is a required field.\n\n' % fieldNames[i])
456 if errmsg == "":
457 break # no problems found
458 fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
459
460 writeln("Reply was: %s" % str(fieldValues))
461 ----------------------------------------------------------------------
462
463 @arg msg: the msg to be displayed.
464 @arg title: the window title
465 @arg fields: a list of fieldnames.
466 @arg values: a list of field values
467 """
468 return __multfillablebox(msg,title,fields,values,None)
469
470
471
472
473
474 -def multpasswordbox(msg="Fill in values for the fields."
475 , title=" "
476 , fields=tuple()
477 ,values=tuple()
478 ):
479 r"""
480 Same interface as multenterbox. But in multpassword box,
481 the last of the fields is assumed to be a password, and
482 is masked with asterisks.
483
484 Example
485 =======
486
487 Here is some example code, that shows how values returned from
488 multpasswordbox can be checked for validity before they are accepted::
489 msg = "Enter logon information"
490 title = "Demo of multpasswordbox"
491 fieldNames = ["Server ID", "User ID", "Password"]
492 fieldValues = [] # we start with blanks for the values
493 fieldValues = multpasswordbox(msg,title, fieldNames)
494
495 # make sure that none of the fields was left blank
496 while 1:
497 if fieldValues == None: break
498 errmsg = ""
499 for i in range(len(fieldNames)):
500 if fieldValues[i].strip() == "":
501 errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
502 if errmsg == "": break # no problems found
503 fieldValues = multpasswordbox(errmsg, title, fieldNames, fieldValues)
504
505 writeln("Reply was: %s" % str(fieldValues))
506 """
507 return __multfillablebox(msg,title,fields,values,"*")
508
509
510
511
512 -def __multfillablebox(msg="Fill in values for the fields."
513 , title=" "
514 , fields=()
515 , values=()
516 , mask = None
517 ):
518 global boxRoot, __multenterboxText, __multenterboxDefaultText, cancelButton, entryWidget, okButton
519
520 choices = ["OK", "Cancel"]
521 if len(fields) == 0: return None
522
523 fields = list(fields[:])
524 values = list(values[:])
525
526 if len(values) == len(fields): pass
527 elif len(values) > len(fields):
528 fields = fields[0:len(values)]
529 else:
530 while len(values) < len(fields):
531 values.append("")
532
533 boxRoot = Tk()
534 boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
535 boxRoot.title(title)
536 boxRoot.iconname('Dialog')
537 boxRoot.geometry(rootWindowPosition)
538 boxRoot.bind("<Escape>", __multenterboxCancel)
539
540
541 messageFrame = Frame(master=boxRoot)
542 messageFrame.pack(side=TOP, fill=BOTH)
543
544
545 messageWidget = Message(messageFrame, width="4.5i", text=msg)
546 messageWidget.configure(font=(DEFAULT_FONT_FAMILY,DEFAULT_FONT_SIZE))
547 messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m')
548
549 global entryWidgets
550 entryWidgets = []
551
552 lastWidgetIndex = len(fields) - 1
553
554 for widgetIndex in range(len(fields)):
555 argFieldName = fields[widgetIndex]
556 argFieldValue = values[widgetIndex]
557 entryFrame = Frame(master=boxRoot)
558 entryFrame.pack(side=TOP, fill=BOTH)
559
560
561 labelWidget = Label(entryFrame, text=argFieldName)
562 labelWidget.pack(side=LEFT)
563
564 entryWidgets.append(Entry(entryFrame, width=40))
565 entryWidgets[widgetIndex].configure(font=(DEFAULT_FONT_FAMILY,BIG_FONT_SIZE))
566 entryWidgets[widgetIndex].pack(side=RIGHT, padx="3m")
567 entryWidgets[widgetIndex].bind("<Return>", __multenterboxGetText)
568 entryWidgets[widgetIndex].bind("<Escape>", __multenterboxCancel)
569
570
571
572 if widgetIndex == lastWidgetIndex:
573 if mask:
574 entryWidgets[widgetIndex].configure(show=mask)
575
576
577 entryWidgets[widgetIndex].insert(0,argFieldValue)
578 widgetIndex += 1
579
580
581 buttonsFrame = Frame(master=boxRoot)
582 buttonsFrame.pack(side=BOTTOM, fill=BOTH)
583
584 okButton = Button(buttonsFrame, takefocus=1, text="OK")
585 okButton.pack(expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
586 okButton.bind("<Return>" , __multenterboxGetText)
587 okButton.bind("<Button-1>", __multenterboxGetText)
588
589
590 cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel")
591 cancelButton.pack(expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
592 cancelButton.bind("<Return>" , __multenterboxCancel)
593 cancelButton.bind("<Button-1>", __multenterboxCancel)
594
595
596 entryWidgets[0].focus_force()
597 boxRoot.mainloop()
598
599
600 boxRoot.destroy()
601 return __multenterboxText
602
603
604
605
607 global __multenterboxText
608
609 __multenterboxText = []
610 for entryWidget in entryWidgets:
611 __multenterboxText.append(entryWidget.get())
612 boxRoot.quit()
613
614
619
620
621
622
623
624 -def enterbox(msg="Enter something."
625 , title=" "
626 , default=""
627 , strip=True
628 , image=None
629 , root=None
630 ):
631 """
632 Show a box in which a user can enter some text.
633
634 You may optionally specify some default text, which will appear in the
635 enterbox when it is displayed.
636
637 Returns the text that the user entered, or None if he cancels the operation.
638
639 By default, enterbox strips its result (i.e. removes leading and trailing
640 whitespace). (If you want it not to strip, use keyword argument: strip=False.)
641 This makes it easier to test the results of the call::
642
643 reply = enterbox(....)
644 if reply:
645 ...
646 else:
647 ...
648 """
649 result = __fillablebox(msg, title, default=default, mask=None,image=image,root=root)
650 if result and strip:
651 result = result.strip()
652 return result
653
654
655 -def passwordbox(msg="Enter your password."
656 , title=" "
657 , default=""
658 , image=None
659 , root=None
660 ):
661 """
662 Show a box in which a user can enter a password.
663 The text is masked with asterisks, so the password is not displayed.
664 Returns the text that the user entered, or None if he cancels the operation.
665 """
666 return __fillablebox(msg, title, default, mask="*",image=image,root=root)
667
668
669 -def __fillablebox(msg
670 , title=""
671 , default=""
672 , mask=None
673 , image=None
674 , root=None
675 ):
676 """
677 Show a box in which a user can enter some text.
678 You may optionally specify some default text, which will appear in the
679 enterbox when it is displayed.
680 Returns the text that the user entered, or None if he cancels the operation.
681 """
682
683 global boxRoot, __enterboxText, __enterboxDefaultText
684 global cancelButton, entryWidget, okButton
685
686 if title == None: title == ""
687 if default == None: default = ""
688 __enterboxDefaultText = default
689 __enterboxText = __enterboxDefaultText
690
691 if root:
692 root.withdraw()
693 boxRoot = Toplevel(master=root)
694 boxRoot.withdraw()
695 else:
696 boxRoot = Tk()
697 boxRoot.withdraw()
698
699 boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
700 boxRoot.title(title)
701 boxRoot.iconname('Dialog')
702 boxRoot.geometry(rootWindowPosition)
703 boxRoot.bind("<Escape>", __enterboxCancel)
704
705 if image:
706 image = os.path.normpath(image)
707 junk,ext = os.path.splitext(image)
708 if ext.lower() == ".gif":
709 if os.path.exists(image):
710 pass
711 else:
712 msg += ImageErrorMsg % (image, "Image file not found.")
713 image = None
714 else:
715 msg += ImageErrorMsg % (image, "Image file is not a .gif file.")
716 image = None
717
718 messageFrame = Frame(master=boxRoot)
719 messageFrame.pack(side=TOP, fill=BOTH)
720
721
722 if image:
723 imageFrame = Frame(master=boxRoot)
724 imageFrame.pack(side=TOP, fill=BOTH)
725 image = PhotoImage(file=image)
726 label = Label(imageFrame,image=image)
727 label.image = image
728 label.pack(side=TOP, expand=YES, fill=X, padx='1m', pady='1m')
729
730
731 entryFrame = Frame(master=boxRoot)
732 entryFrame.pack(side=TOP, fill=BOTH)
733
734
735 buttonsFrame = Frame(master=boxRoot)
736 buttonsFrame.pack(side=TOP, fill=BOTH)
737
738
739 messageWidget = Message(messageFrame, width="4.5i", text=msg)
740 messageWidget.configure(font=(DEFAULT_FONT_FAMILY,DEFAULT_FONT_SIZE))
741 messageWidget.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m')
742
743
744 entryWidget = Entry(entryFrame, width=40)
745 entryWidget.configure(font=(DEFAULT_FONT_FAMILY,BIG_FONT_SIZE))
746 if mask:
747 entryWidget.configure(show=mask)
748 entryWidget.pack(side=LEFT, padx="3m")
749 entryWidget.bind("<Return>", __enterboxGetText)
750 entryWidget.bind("<Escape>", __enterboxCancel)
751
752 entryWidget.insert(0,__enterboxDefaultText)
753
754
755 okButton = Button(buttonsFrame, takefocus=1, text="OK")
756 okButton.pack(expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
757 okButton.bind("<Return>" , __enterboxGetText)
758 okButton.bind("<Button-1>", __enterboxGetText)
759
760 ''' dead code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
761 # ------------------ (possible) restore button -------------------------------
762 if default != None:
763 # make a button to restore the default text
764 restoreButton = Button(buttonsFrame, takefocus=1, text="Restore default")
765 restoreButton.pack(expand=1, side=LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
766 restoreButton.bind("<Return>" , __enterboxRestore)
767 restoreButton.bind("<Button-1>", __enterboxRestore)
768 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dead code '''
769
770
771 cancelButton = Button(buttonsFrame, takefocus=1, text="Cancel")
772 cancelButton.pack(expand=1, side=RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
773 cancelButton.bind("<Return>" , __enterboxCancel)
774 cancelButton.bind("<Button-1>", __enterboxCancel)
775
776
777 entryWidget.focus_force()
778 boxRoot.deiconify()
779 boxRoot.mainloop()
780
781
782 if root: root.deiconify()
783 boxRoot.destroy()
784 return __enterboxText
785
786
791
792
797
798
803
805 """ don't allow WindowManager close
806 """
807 x = Tk()
808 x.withdraw()
809 x.bell()
810 x.destroy()
811
812
813
814
815
816
817 -def multchoicebox(msg="Pick as many items as you like."
818 , title=" "
819 , choices=()
820 , **kwargs
821 ):
822 """
823 Present the user with a list of choices.
824 allow him to select multiple items and return them in a list.
825 if the user doesn't choose anything from the list, return the empty list.
826 return None if he cancelled selection.
827
828 @arg msg: the msg to be displayed.
829 @arg title: the window title
830 @arg choices: a list or tuple of the choices to be displayed
831 """
832 if len(choices) == 0: choices = ["Program logic error - no choices were specified."]
833
834 global __choiceboxMultipleSelect
835 __choiceboxMultipleSelect = 1
836 return __choicebox(msg, title, choices)
837
838
839
840
841
842 -def choicebox(msg="Pick something."
843 , title=" "
844 , choices=()
845 , buttons=()
846 ):
847 """
848 Present the user with a list of choices.
849 return the choice that he selects.
850 return None if he cancels the selection selection.
851
852 @arg msg: the msg to be displayed.
853 @arg title: the window title
854 @arg choices: a list or tuple of the choices to be displayed
855 """
856 if len(choices) == 0: choices = ["Program logic error - no choices were specified."]
857
858 global __choiceboxMultipleSelect
859 __choiceboxMultipleSelect = 0
860 return __choicebox(msg,title,choices,buttons)
861
862
863
864
865
866 -def __choicebox(msg
867 , title
868 , choices
869 , buttons=()
870 ):
871 """
872 internal routine to support choicebox() and multchoicebox()
873 """
874 global boxRoot, __choiceboxResults, choiceboxWidget, defaultText
875 global choiceboxWidget, choiceboxChoices
876
877
878
879
880
881
882 choices = list(choices[:])
883 if len(choices) == 0:
884 choices = ["Program logic error - no choices were specified."]
885 defaultButtons = ["OK", "Cancel"]
886
887
888 for index in range(len(choices)):
889 choices[index] = str(choices[index])
890
891 if buttons:
892 if type(buttons) == type("abc"):
893 choiceboxButtons = [buttons]
894 else:
895 choiceboxButtons = buttons
896 else:
897 choiceboxButtons = defaultButtons
898
899 lines_to_show = min(len(choices), 20)
900 lines_to_show = 20
901
902 if title == None: title = ""
903
904
905
906 __choiceboxResults = None
907
908 boxRoot = Tk()
909 boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
910 screen_width = boxRoot.winfo_screenwidth()
911 screen_height = boxRoot.winfo_screenheight()
912 root_width = int((screen_width * 0.8))
913 root_height = int((screen_height * 0.5))
914 root_xpos = int((screen_width * 0.1))
915 root_ypos = int((screen_height * 0.05))
916
917 boxRoot.title(title)
918 boxRoot.iconname('Dialog')
919 rootWindowPosition = "+0+0"
920 boxRoot.geometry(rootWindowPosition)
921 boxRoot.expand=NO
922 boxRoot.minsize(root_width, root_height)
923 rootWindowPosition = "+" + str(root_xpos) + "+" + str(root_ypos)
924 boxRoot.geometry(rootWindowPosition)
925
926
927 message_and_buttonsFrame = Frame(master=boxRoot)
928 message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO)
929
930 messageFrame = Frame(message_and_buttonsFrame)
931 messageFrame.pack(side=LEFT, fill=X, expand=YES)
932
933
934 buttonsFrame = Frame(message_and_buttonsFrame)
935 buttonsFrame.pack(side=RIGHT, expand=NO, pady=0)
936
937
938 choiceboxFrame = Frame(master=boxRoot)
939 choiceboxFrame.pack(side=BOTTOM, fill=BOTH, expand=YES)
940
941
942
943
944 messageWidget = Message(messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9))
945 messageWidget.configure(font=(DEFAULT_FONT_FAMILY,DEFAULT_FONT_SIZE))
946 messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m')
947
948
949 choiceboxWidget = Listbox(choiceboxFrame
950 , height=lines_to_show
951 , borderwidth="1m"
952 , relief="flat"
953 , bg="white"
954 )
955
956 if __choiceboxMultipleSelect:
957 choiceboxWidget.configure(selectmode=MULTIPLE)
958
959 choiceboxWidget.configure(font=(DEFAULT_FONT_FAMILY,DEFAULT_FONT_SIZE))
960
961
962 rightScrollbar = Scrollbar(choiceboxFrame, orient=VERTICAL, command=choiceboxWidget.yview)
963 choiceboxWidget.configure(yscrollcommand = rightScrollbar.set)
964
965
966 bottomScrollbar = Scrollbar(choiceboxFrame, orient=HORIZONTAL, command=choiceboxWidget.xview)
967 choiceboxWidget.configure(xscrollcommand = bottomScrollbar.set)
968
969
970
971
972
973 bottomScrollbar.pack(side=BOTTOM, fill = X)
974 rightScrollbar.pack(side=RIGHT, fill = Y)
975
976 choiceboxWidget.pack(side=LEFT, padx="1m", pady="1m", expand=YES, fill=BOTH)
977
978
979
980
981
982
983 for index in range(len(choices)):
984 choices[index] == str(choices[index])
985
986 if runningPython3:
987 choices.sort(key=str.lower)
988 else:
989 choices.sort( lambda x,y: cmp(x.lower(), y.lower()))
990
991 lastInserted = None
992 choiceboxChoices = []
993 for choice in choices:
994 if choice == lastInserted: pass
995 else:
996 choiceboxWidget.insert(END, choice)
997 choiceboxChoices.append(choice)
998 lastInserted = choice
999
1000 boxRoot.bind('<Any-Key>', KeyboardListener)
1001
1002
1003 if len(choices) > 0:
1004 okButton = Button(buttonsFrame, takefocus=YES, text="OK", height=1, width=6)
1005 okButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
1006 okButton.bind("<Return>", __choiceboxGetChoice)
1007 okButton.bind("<Button-1>",__choiceboxGetChoice)
1008
1009
1010 choiceboxWidget.bind("<Return>", __choiceboxGetChoice)
1011 choiceboxWidget.bind("<Double-Button-1>", __choiceboxGetChoice)
1012 else:
1013
1014 choiceboxWidget.bind("<Return>", __choiceboxCancel)
1015 choiceboxWidget.bind("<Double-Button-1>", __choiceboxCancel)
1016
1017 cancelButton = Button(buttonsFrame, takefocus=YES, text="Cancel", height=1, width=6)
1018 cancelButton.pack(expand=NO, side=BOTTOM, padx='2m', pady='1m', ipady="1m", ipadx="2m")
1019 cancelButton.bind("<Return>", __choiceboxCancel)
1020 cancelButton.bind("<Button-1>", __choiceboxCancel)
1021
1022
1023 if len(choices) > 0 and __choiceboxMultipleSelect:
1024 selectionButtonsFrame = Frame(messageFrame)
1025 selectionButtonsFrame.pack(side=RIGHT, fill=Y, expand=NO)
1026
1027 selectAllButton = Button(selectionButtonsFrame, text="Select All", height=1, width=6)
1028 selectAllButton.bind("<Button-1>",__choiceboxSelectAll)
1029 selectAllButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
1030
1031 clearAllButton = Button(selectionButtonsFrame, text="Clear All", height=1, width=6)
1032 clearAllButton.bind("<Button-1>",__choiceboxClearAll)
1033 clearAllButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
1034
1035
1036
1037 boxRoot.bind("<Escape>", __choiceboxCancel)
1038
1039
1040
1041 choiceboxWidget.select_set(0)
1042 choiceboxWidget.focus_force()
1043
1044
1045 boxRoot.mainloop()
1046
1047 boxRoot.destroy()
1048 return __choiceboxResults
1049
1050
1064
1065
1069
1073
1074
1075
1081
1082
1131
1132
1133
1134
1135
1136 -def codebox(msg=""
1137 , title=" "
1138 , text=""
1139 ):
1140 """
1141 Display some text in a monospaced font, with no line wrapping.
1142 This function is suitable for displaying code and text that is
1143 formatted using spaces.
1144
1145 The text parameter should be a string, or a list or tuple of lines to be
1146 displayed in the textbox.
1147 """
1148 textbox(msg, title, text, codebox=1 )
1149
1150
1151
1152
1153 -def textbox(msg=""
1154 , title=" "
1155 , text=""
1156 , codebox=0
1157 ):
1158 """
1159 Display some text in a proportional font with line wrapping at word breaks.
1160 This function is suitable for displaying general written text.
1161
1162 The text parameter should be a string, or a list or tuple of lines to be
1163 displayed in the textbox.
1164 """
1165
1166 if msg == None: msg = ""
1167 if title == None: title = ""
1168
1169 global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame
1170 global rootWindowPosition
1171 choices = ["OK"]
1172 __replyButtonText = choices[0]
1173
1174
1175 boxRoot = Tk()
1176
1177 boxRoot.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
1178
1179 screen_width = boxRoot.winfo_screenwidth()
1180 screen_height = boxRoot.winfo_screenheight()
1181 root_width = int((screen_width * 0.8))
1182 root_height = int((screen_height * 0.5))
1183 root_xpos = int((screen_width * 0.1))
1184 root_ypos = int((screen_height * 0.05))
1185
1186 boxRoot.title(title)
1187 boxRoot.iconname('Dialog')
1188 rootWindowPosition = "+0+0"
1189 boxRoot.geometry(rootWindowPosition)
1190 boxRoot.expand=NO
1191 boxRoot.minsize(root_width, root_height)
1192 rootWindowPosition = "+" + str(root_xpos) + "+" + str(root_ypos)
1193 boxRoot.geometry(rootWindowPosition)
1194
1195 mainframe = Frame(master=boxRoot)
1196 mainframe.pack(side=TOP, fill=BOTH, expand=YES)
1197
1198
1199
1200 textboxFrame = Frame(mainframe, borderwidth=3)
1201 textboxFrame.pack(side=BOTTOM , fill=BOTH, expand=YES)
1202
1203 message_and_buttonsFrame = Frame(mainframe)
1204 message_and_buttonsFrame.pack(side=TOP, fill=X, expand=NO)
1205
1206 messageFrame = Frame(message_and_buttonsFrame)
1207 messageFrame.pack(side=LEFT, fill=X, expand=YES)
1208
1209 buttonsFrame = Frame(message_and_buttonsFrame)
1210 buttonsFrame.pack(side=RIGHT, expand=NO)
1211
1212
1213
1214
1215 if codebox:
1216 character_width = int((root_width * 0.6) / CODEBOX_FONT_SIZE)
1217 textbox = Text(textboxFrame,height=25,width=character_width, padx="2m", pady="1m")
1218 textbox.configure(wrap=NONE)
1219 textbox.configure(font=(MONOSPACE_FONT_FAMILY, CODEBOX_FONT_SIZE))
1220
1221 else:
1222 character_width = int((root_width * 0.6) / SMALL_FONT_SIZE)
1223 textbox = Text(
1224 textboxFrame
1225 , height=25
1226 , width=character_width
1227 , padx="2m"
1228 , pady="1m"
1229 )
1230 textbox.configure(wrap=WORD)
1231 textbox.configure(font=(DEFAULT_FONT_FAMILY,TEXTBOX_FONT_SIZE))
1232
1233
1234
1235 mainframe.bind("<Next>" , textbox.yview_scroll( 1,PAGES))
1236 mainframe.bind("<Prior>", textbox.yview_scroll(-1,PAGES))
1237
1238 mainframe.bind("<Right>", textbox.xview_scroll( 1,PAGES))
1239 mainframe.bind("<Left>" , textbox.xview_scroll(-1,PAGES))
1240
1241 mainframe.bind("<Down>", textbox.yview_scroll( 1,UNITS))
1242 mainframe.bind("<Up>" , textbox.yview_scroll(-1,UNITS))
1243
1244
1245
1246 rightScrollbar = Scrollbar(textboxFrame, orient=VERTICAL, command=textbox.yview)
1247 textbox.configure(yscrollcommand = rightScrollbar.set)
1248
1249
1250 bottomScrollbar = Scrollbar(textboxFrame, orient=HORIZONTAL, command=textbox.xview)
1251 textbox.configure(xscrollcommand = bottomScrollbar.set)
1252
1253
1254
1255
1256
1257
1258
1259
1260 if codebox:
1261 bottomScrollbar.pack(side=BOTTOM, fill=X)
1262 rightScrollbar.pack(side=RIGHT, fill=Y)
1263
1264 textbox.pack(side=LEFT, fill=BOTH, expand=YES)
1265
1266
1267
1268 messageWidget = Message(messageFrame, anchor=NW, text=msg, width=int(root_width * 0.9))
1269 messageWidget.configure(font=(DEFAULT_FONT_FAMILY,DEFAULT_FONT_SIZE))
1270 messageWidget.pack(side=LEFT, expand=YES, fill=BOTH, padx='1m', pady='1m')
1271
1272
1273 okButton = Button(buttonsFrame, takefocus=YES, text="OK", height=1, width=6)
1274 okButton.pack(expand=NO, side=TOP, padx='2m', pady='1m', ipady="1m", ipadx="2m")
1275 okButton.bind("<Return>" , __textboxOK)
1276 okButton.bind("<Button-1>", __textboxOK)
1277 okButton.bind("<Escape>" , __textboxOK)
1278
1279
1280
1281 try:
1282
1283 if type(text) == type("abc"): pass
1284 else:
1285 try:
1286 text = "".join(text)
1287 except:
1288 msgbox("Exception when trying to convert "+ str(type(text)) + " to text in textbox")
1289 sys.exit(16)
1290 textbox.insert(END,text, "normal")
1291
1292
1293
1294 except:
1295 msgbox("Exception when trying to load the textbox.")
1296 sys.exit(16)
1297
1298 try:
1299 okButton.focus_force()
1300 except:
1301 msgbox("Exception when trying to put focus on okButton.")
1302 sys.exit(16)
1303
1304 boxRoot.mainloop()
1305 boxRoot.destroy()
1306 return __replyButtonText
1307
1308
1309
1310
1311 -def __textboxOK(event):
1312 global boxRoot
1313 boxRoot.quit()
1314
1315
1316
1317
1318
1319
1320 -def diropenbox(msg=None
1321 , title=None
1322 , default=None
1323 ):
1324 """
1325 A dialog to get a directory name.
1326 Note that the msg argument, if specified, is ignored.
1327
1328 Returns the name of a directory, or None if user chose to cancel.
1329
1330 If the "default" argument specifies a directory name, and that
1331 directory exists, then the dialog box will start with that directory.
1332 """
1333 title=getFileDialogTitle(msg,title)
1334 boxRoot = Tk()
1335 boxRoot.withdraw()
1336 if not default: default = None
1337 f = tk_FileDialog.askdirectory(
1338 parent=boxRoot
1339 , title=title
1340 , initialdir=default
1341 , initialfile=None
1342 )
1343 boxRoot.destroy()
1344 if not f: return None
1345 return os.path.normpath(f)
1346
1347
1348
1349
1350
1351
1355 if msg and title: return "%s - %s" % (title,msg)
1356 if msg and not title: return str(msg)
1357 if title and not msg: return str(title)
1358 return None
1359
1360
1361
1362
1365 if len(filemask) == 0:
1366 raise AssertionError('Filetype argument is empty.')
1367
1368 self.masks = []
1369
1370 if type(filemask) == type("abc"):
1371 self.initializeFromString(filemask)
1372
1373 elif type(filemask) == type([]):
1374 if len(filemask) < 2:
1375 raise AssertionError('Invalid filemask.\n'
1376 +'List contains less than 2 members: "%s"' % filemask)
1377 else:
1378 self.name = filemask[-1]
1379 self.masks = list(filemask[:-1] )
1380 else:
1381 raise AssertionError('Invalid filemask: "%s"' % filemask)
1382
1384 if self.name == other.name: return True
1385 return False
1386
1387 - def add(self,other):
1388 for mask in other.masks:
1389 if mask in self.masks: pass
1390 else: self.masks.append(mask)
1391
1393 return (self.name,tuple(self.masks))
1394
1396 if self.name == "All files": return True
1397 return False
1398
1400
1401 self.ext = os.path.splitext(filemask)[1]
1402 if self.ext == "" : self.ext = ".*"
1403 if self.ext == ".": self.ext = ".*"
1404 self.name = self.getName()
1405 self.masks = ["*" + self.ext]
1406
1408 e = self.ext
1409 if e == ".*" : return "All files"
1410 if e == ".txt": return "Text files"
1411 if e == ".py" : return "Python files"
1412 if e == ".pyc" : return "Python files"
1413 if e == ".xls": return "Excel files"
1414 if e.startswith("."):
1415 return e[1:].upper() + " files"
1416 return e.upper() + " files"
1417
1418
1419
1420
1421
1422 -def fileopenbox(msg=None
1423 , title=None
1424 , default="*"
1425 , filetypes=None
1426 ):
1427 """
1428 A dialog to get a file name.
1429
1430 About the "default" argument
1431 ============================
1432 The "default" argument specifies a filepath that (normally)
1433 contains one or more wildcards.
1434 fileopenbox will display only files that match the default filepath.
1435 If omitted, defaults to "*" (all files in the current directory).
1436
1437 WINDOWS EXAMPLE::
1438 ...default="c:/myjunk/*.py"
1439 will open in directory c:\myjunk\ and show all Python files.
1440
1441 WINDOWS EXAMPLE::
1442 ...default="c:/myjunk/test*.py"
1443 will open in directory c:\myjunk\ and show all Python files
1444 whose names begin with "test".
1445
1446
1447 Note that on Windows, fileopenbox automatically changes the path
1448 separator to the Windows path separator (backslash).
1449
1450 About the "filetypes" argument
1451 ==============================
1452 If specified, it should contain a list of items,
1453 where each item is either::
1454 - a string containing a filemask # e.g. "*.txt"
1455 - a list of strings, where all of the strings except the last one
1456 are filemasks (each beginning with "*.",
1457 such as "*.txt" for text files, "*.py" for Python files, etc.).
1458 and the last string contains a filetype description
1459
1460 EXAMPLE::
1461 filetypes = ["*.css", ["*.htm", "*.html", "HTML files"] ]
1462
1463 NOTE THAT
1464 =========
1465
1466 If the filetypes list does not contain ("All files","*"),
1467 it will be added.
1468
1469 If the filetypes list does not contain a filemask that includes
1470 the extension of the "default" argument, it will be added.
1471 For example, if default="*abc.py"
1472 and no filetypes argument was specified, then
1473 "*.py" will automatically be added to the filetypes argument.
1474
1475 @rtype: string or None
1476 @return: the name of a file, or None if user chose to cancel
1477
1478 @arg msg: the msg to be displayed.
1479 @arg title: the window title
1480 @arg default: filepath with wildcards
1481 @arg filetypes: filemasks that a user can choose, e.g. "*.txt"
1482 """
1483 boxRoot = Tk()
1484 boxRoot.withdraw()
1485
1486 initialbase, initialfile, initialdir, filetypes = fileboxSetup(default,filetypes)
1487
1488
1489
1490
1491
1492
1493
1494 if (initialfile.find("*") < 0) and (initialfile.find("?") < 0):
1495 initialfile = None
1496 elif initialbase == "*":
1497 initialfile = None
1498
1499 f = tk_FileDialog.askopenfilename(parent=boxRoot
1500 , title=getFileDialogTitle(msg,title)
1501 , initialdir=initialdir
1502 , initialfile=initialfile
1503 , filetypes=filetypes
1504 )
1505
1506 boxRoot.destroy()
1507
1508 if not f: return None
1509 return os.path.normpath(f)
1510
1511
1512
1513
1514
1515 -def filesavebox(msg=None
1516 , title=None
1517 , default=""
1518 , filetypes=None
1519 ):
1520 """
1521 A file to get the name of a file to save.
1522 Returns the name of a file, or None if user chose to cancel.
1523
1524 The "default" argument should contain a filename (i.e. the
1525 current name of the file to be saved). It may also be empty,
1526 or contain a filemask that includes wildcards.
1527
1528 The "filetypes" argument works like the "filetypes" argument to
1529 fileopenbox.
1530 """
1531
1532 boxRoot = Tk()
1533 boxRoot.withdraw()
1534
1535 initialbase, initialfile, initialdir, filetypes = fileboxSetup(default,filetypes)
1536
1537 f = tk_FileDialog.asksaveasfilename(parent=boxRoot
1538 , title=getFileDialogTitle(msg,title)
1539 , initialfile=initialfile
1540 , initialdir=initialdir
1541 , filetypes=filetypes
1542 )
1543 boxRoot.destroy()
1544 if not f: return None
1545 return os.path.normpath(f)
1546
1547
1548
1549
1550
1551
1552
1554 if not default: default = os.path.join(".","*")
1555 initialdir, initialfile = os.path.split(default)
1556 if not initialdir : initialdir = "."
1557 if not initialfile: initialfile = "*"
1558 initialbase, initialext = os.path.splitext(initialfile)
1559 initialFileTypeObject = FileTypeObject(initialfile)
1560
1561 allFileTypeObject = FileTypeObject("*")
1562 ALL_filetypes_was_specified = False
1563
1564 if not filetypes: filetypes= []
1565 filetypeObjects = []
1566
1567 for filemask in filetypes:
1568 fto = FileTypeObject(filemask)
1569
1570 if fto.isAll():
1571 ALL_filetypes_was_specified = True
1572
1573 if fto == initialFileTypeObject:
1574 initialFileTypeObject.add(fto)
1575 else:
1576 filetypeObjects.append(fto)
1577
1578
1579
1580
1581 if ALL_filetypes_was_specified:
1582 pass
1583 elif allFileTypeObject == initialFileTypeObject:
1584 pass
1585 else:
1586 filetypeObjects.insert(0,allFileTypeObject)
1587
1588
1589
1590
1591
1592 if len(filetypeObjects) == 0:
1593 filetypeObjects.append(initialFileTypeObject)
1594
1595 if initialFileTypeObject in (filetypeObjects[0], filetypeObjects[-1]):
1596 pass
1597 else:
1598 if runningPython26:
1599 filetypeObjects.append(initialFileTypeObject)
1600 else:
1601 filetypeObjects.insert(0,initialFileTypeObject)
1602
1603 filetypes = [fto.toTuple() for fto in filetypeObjects]
1604
1605 return initialbase, initialfile, initialdir, filetypes
1606
1607
1608
1609
1610
1611
1619
1620
1646
1647
1648
1649
1650
1651
1652
1654 r"""
1655 A class to support persistent storage.
1656
1657 You can use EgStore to support the storage and retrieval
1658 of user settings for an EasyGui application.
1659
1660
1661 # Example A
1662 #-----------------------------------------------------------------------
1663 # define a class named Settings as a subclass of EgStore
1664 #-----------------------------------------------------------------------
1665 class Settings(EgStore):
1666
1667 def __init__(self, filename): # filename is required
1668 #-------------------------------------------------
1669 # Specify default/initial values for variables that
1670 # this particular application wants to remember.
1671 #-------------------------------------------------
1672 self.userId = ""
1673 self.targetServer = ""
1674
1675 #-------------------------------------------------
1676 # For subclasses of EgStore, these must be
1677 # the last two statements in __init__
1678 #-------------------------------------------------
1679 self.filename = filename # this is required
1680 self.restore() # restore values from the storage file if possible
1681
1682
1683
1684 # Example B
1685 #-----------------------------------------------------------------------
1686 # create settings, a persistent Settings object
1687 #-----------------------------------------------------------------------
1688 settingsFile = "myApp_settings.txt"
1689 settings = Settings(settingsFile)
1690
1691 user = "obama_barak"
1692 server = "whitehouse1"
1693 settings.userId = user
1694 settings.targetServer = server
1695 settings.store() # persist the settings
1696
1697 # run code that gets a new value for userId, and persist the settings
1698 user = "biden_joe"
1699 settings.userId = user
1700 settings.store()
1701
1702
1703 # Example C
1704 #-----------------------------------------------------------------------
1705 # recover the Settings instance, change an attribute, and store it again.
1706 #-----------------------------------------------------------------------
1707 settings = Settings(settingsFile)
1708 settings.userId = "vanrossum_g"
1709 settings.store()
1710
1711 """
1713 raise NotImplementedError()
1714
1716 """
1717 Set the values of whatever attributes are recoverable
1718 from the pickle file.
1719
1720 Populate the attributes (the __dict__) of the EgStore object
1721 from the attributes (the __dict__) of the pickled object.
1722
1723 If the pickled object has attributes that have been initialized
1724 in the EgStore object, then those attributes of the EgStore object
1725 will be replaced by the values of the corresponding attributes
1726 in the pickled object.
1727
1728 If the pickled object is missing some attributes that have
1729 been initialized in the EgStore object, then those attributes
1730 of the EgStore object will retain the values that they were
1731 initialized with.
1732
1733 If the pickled object has some attributes that were not
1734 initialized in the EgStore object, then those attributes
1735 will be ignored.
1736
1737 IN SUMMARY:
1738
1739 After the recover() operation, the EgStore object will have all,
1740 and only, the attributes that it had when it was initialized.
1741
1742 Where possible, those attributes will have values recovered
1743 from the pickled object.
1744 """
1745 if not os.path.exists(self.filename): return self
1746 if not os.path.isfile(self.filename): return self
1747
1748 try:
1749 f = open(self.filename)
1750 unpickledObject = pickle.load(f)
1751 f.close()
1752
1753 for key in list(self.__dict__.keys()):
1754 default = self.__dict__[key]
1755 self.__dict__[key] = unpickledObject.__dict__.get(key,default)
1756 except:
1757 pass
1758
1759 return self
1760
1762 """
1763 Save the attributes of the EgStore object to a pickle file.
1764 Note that if the directory for the pickle file does not already exist,
1765 the store operation will fail.
1766 """
1767 f = open(self.filename, "w")
1768 pickle.dump(self, f)
1769 f.close()
1770
1771
1773 """
1774 Delete my persistent file (i.e. pickle file), if it exists.
1775 """
1776 if os.path.isfile(self.filename):
1777 os.remove(self.filename)
1778 return
1779
1781 """
1782 return my contents as a string in an easy-to-read format.
1783 """
1784
1785 longest_key_length = 0
1786 keys = []
1787 for key in self.__dict__.keys():
1788 keys.append(key)
1789 longest_key_length = max(longest_key_length, len(key))
1790
1791 keys.sort()
1792 lines = []
1793 for key in keys:
1794 value = self.__dict__[key]
1795 key = key.ljust(longest_key_length)
1796 lines.append("%s : %s\n" % (key,repr(value)) )
1797 return "".join(lines)
1798
1799
1800
1801
1802
1803
1804
1805
1806
1808 """
1809 Run the EasyGui demo.
1810 """
1811
1812 writeln("\n" * 100)
1813
1814
1815 code_snippet = ("dafsdfa dasflkj pp[oadsij asdfp;ij asdfpjkop asdfpok asdfpok asdfpok"*3) +"\n"+\
1816 """# here is some dummy Python code
1817 for someItem in myListOfStuff:
1818 do something(someItem)
1819 do something()
1820 do something()
1821 if somethingElse(someItem):
1822 doSomethingEvenMoreInteresting()
1823
1824 """*16
1825
1826
1827
1828 text_snippet = ((\
1829 """It was the best of times, and it was the worst of times. The rich ate cake, and the poor had cake recommended to them, but wished only for enough cash to buy bread. The time was ripe for revolution! """ \
1830 *5)+"\n\n")*10
1831
1832
1833
1834 intro_message = ("Pick the kind of box that you wish to demo.\n"
1835 + "\n * Python version " + sys.version
1836 + "\n * EasyGui version " + egversion
1837 + "\n * Tk version " + str(TkVersion)
1838 )
1839
1840
1841
1842
1843 while 1:
1844 choices = [
1845 "msgbox",
1846 "buttonbox",
1847 "buttonbox(image) -- a buttonbox that displays an image",
1848 "choicebox",
1849 "multchoicebox",
1850 "textbox",
1851 "ynbox",
1852 "ccbox",
1853 "enterbox",
1854 "enterbox(image) -- an enterbox that displays an image",
1855 "codebox",
1856 "integerbox",
1857 "boolbox",
1858 "indexbox",
1859 "filesavebox",
1860 "fileopenbox",
1861 "passwordbox",
1862 "multenterbox",
1863 "multpasswordbox",
1864 "diropenbox",
1865 "About EasyGui",
1866 " Help"
1867 ]
1868 choice = choicebox(msg=intro_message
1869 , title="EasyGui " + egversion
1870 , choices=choices)
1871
1872 if not choice: return
1873
1874 reply = choice.split()
1875
1876 if reply[0] == "msgbox":
1877 reply = msgbox("short msg", "This is a long title")
1878 writeln("Reply was: %s" % repr(reply))
1879
1880 elif reply[0] == "About":
1881 reply = abouteasygui()
1882
1883 elif reply[0] == "Help":
1884 _demo_help()
1885
1886 elif reply[0] == "buttonbox":
1887 reply = buttonbox()
1888 writeln("Reply was: %s" % repr(reply))
1889
1890 title = "Demo of Buttonbox with many, many buttons!"
1891 msg = "This buttonbox shows what happens when you specify too many buttons."
1892 reply = buttonbox(msg=msg, title=title, choices=choices)
1893 writeln("Reply was: %s" % repr(reply))
1894
1895 elif reply[0] == "buttonbox(image)":
1896 _demo_buttonbox_with_image()
1897
1898 elif reply[0] == "boolbox":
1899 reply = boolbox()
1900 writeln("Reply was: %s" % repr(reply))
1901
1902 elif reply[0] == "enterbox":
1903 image = "python_and_check_logo.gif"
1904 message = "Enter the name of your best friend."\
1905 "\n(Result will be stripped.)"
1906 reply = enterbox(message, "Love!", " Suzy Smith ")
1907 writeln("Reply was: %s" % repr(reply))
1908
1909 message = "Enter the name of your best friend."\
1910 "\n(Result will NOT be stripped.)"
1911 reply = enterbox(message, "Love!", " Suzy Smith ",strip=False)
1912 writeln("Reply was: %s" % repr(reply))
1913
1914 reply = enterbox("Enter the name of your worst enemy:", "Hate!")
1915 writeln("Reply was: %s" % repr(reply))
1916
1917 elif reply[0] == "enterbox(image)":
1918 image = "python_and_check_logo.gif"
1919 message = "What kind of snake is this?"
1920 reply = enterbox(message, "Quiz",image=image)
1921 writeln("Reply was: %s" % repr(reply))
1922
1923 elif reply[0] == "integerbox":
1924 reply = integerbox(
1925 "Enter a number between 3 and 333",
1926 "Demo: integerbox WITH a default value",
1927 222, 3, 333)
1928 writeln("Reply was: %s" % repr(reply))
1929
1930 reply = integerbox(
1931 "Enter a number between 0 and 99",
1932 "Demo: integerbox WITHOUT a default value"
1933 )
1934 writeln("Reply was: %s" % repr(reply))
1935
1936 elif reply[0] == "diropenbox" : _demo_diropenbox()
1937 elif reply[0] == "fileopenbox": _demo_fileopenbox()
1938 elif reply[0] == "filesavebox": _demo_filesavebox()
1939
1940 elif reply[0] == "indexbox":
1941 title = reply[0]
1942 msg = "Demo of " + reply[0]
1943 choices = ["Choice1", "Choice2", "Choice3", "Choice4"]
1944 reply = indexbox(msg, title, choices)
1945 writeln("Reply was: %s" % repr(reply))
1946
1947 elif reply[0] == "passwordbox":
1948 reply = passwordbox("Demo of password box WITHOUT default"
1949 + "\n\nEnter your secret password", "Member Logon")
1950 writeln("Reply was: %s" % str(reply))
1951
1952 reply = passwordbox("Demo of password box WITH default"
1953 + "\n\nEnter your secret password", "Member Logon", "alfie")
1954 writeln("Reply was: %s" % str(reply))
1955
1956 elif reply[0] == "multenterbox":
1957 msg = "Enter your personal information"
1958 title = "Credit Card Application"
1959 fieldNames = ["Name","Street Address","City","State","ZipCode"]
1960 fieldValues = []
1961 fieldValues = multenterbox(msg,title, fieldNames)
1962
1963
1964 while 1:
1965 if fieldValues == None: break
1966 errmsg = ""
1967 for i in range(len(fieldNames)):
1968 if fieldValues[i].strip() == "":
1969 errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
1970 if errmsg == "": break
1971 fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
1972
1973 writeln("Reply was: %s" % str(fieldValues))
1974
1975 elif reply[0] == "multpasswordbox":
1976 msg = "Enter logon information"
1977 title = "Demo of multpasswordbox"
1978 fieldNames = ["Server ID", "User ID", "Password"]
1979 fieldValues = []
1980 fieldValues = multpasswordbox(msg,title, fieldNames)
1981
1982
1983 while 1:
1984 if fieldValues == None: break
1985 errmsg = ""
1986 for i in range(len(fieldNames)):
1987 if fieldValues[i].strip() == "":
1988 errmsg = errmsg + ('"%s" is a required field.\n\n' % fieldNames[i])
1989 if errmsg == "": break
1990 fieldValues = multpasswordbox(errmsg, title, fieldNames, fieldValues)
1991
1992 writeln("Reply was: %s" % str(fieldValues))
1993
1994 elif reply[0] == "ynbox":
1995 title = "Demo of ynbox"
1996 msg = "Were you expecting the Spanish Inquisition?"
1997 reply = ynbox(msg, title)
1998 writeln("Reply was: %s" % repr(reply))
1999 if reply:
2000 msgbox("NOBODY expects the Spanish Inquisition!", "Wrong!")
2001
2002 elif reply[0] == "ccbox":
2003 title = "Demo of ccbox"
2004 reply = ccbox(msg,title)
2005 writeln("Reply was: %s" % repr(reply))
2006
2007 elif reply[0] == "choicebox":
2008 title = "Demo of choicebox"
2009 longchoice = "This is an example of a very long option which you may or may not wish to choose."*2
2010 listChoices = ["nnn", "ddd", "eee", "fff", "aaa", longchoice
2011 , "aaa", "bbb", "ccc", "ggg", "hhh", "iii", "jjj", "kkk", "LLL", "mmm" , "nnn", "ooo", "ppp", "qqq", "rrr", "sss", "ttt", "uuu", "vvv"]
2012
2013 msg = "Pick something. " + ("A wrapable sentence of text ?! "*30) + "\nA separate line of text."*6
2014 reply = choicebox(msg=msg, choices=listChoices)
2015 writeln("Reply was: %s" % repr(reply))
2016
2017 msg = "Pick something. "
2018 reply = choicebox(msg=msg, title=title, choices=listChoices)
2019 writeln("Reply was: %s" % repr(reply))
2020
2021 msg = "Pick something. "
2022 reply = choicebox(msg="The list of choices is empty!", choices=[])
2023 writeln("Reply was: %s" % repr(reply))
2024
2025 elif reply[0] == "multchoicebox":
2026 listChoices = ["aaa", "bbb", "ccc", "ggg", "hhh", "iii", "jjj", "kkk"
2027 , "LLL", "mmm" , "nnn", "ooo", "ppp", "qqq"
2028 , "rrr", "sss", "ttt", "uuu", "vvv"]
2029
2030 msg = "Pick as many choices as you wish."
2031 reply = multchoicebox(msg,"Demo of multchoicebox", listChoices)
2032 writeln("Reply was: %s" % repr(reply))
2033
2034 elif reply[0] == "textbox":
2035 title = "Demo of textbox"
2036 msg = "Here is some sample text. " * 16
2037 reply = textbox(msg, "Text Sample", text_snippet)
2038 writeln("Reply was: %s" % repr(reply))
2039
2040 elif reply[0] == "codebox":
2041 msg = "Here is some sample code. " * 16
2042 reply = codebox(msg, "Code Sample", code_snippet)
2043 writeln("Reply was: %s" % repr(reply))
2044
2045 else:
2046 msgbox("Choice\n\n" + choice + "\n\nis not recognized", "Program Logic Error")
2047 return
2048
2049
2050
2071
2072
2074 savedStdout = sys.stdout
2075 sys.stdout = capturedOutput = StringIO()
2076 help("easygui")
2077 sys.stdout = savedStdout
2078 codebox("EasyGui Help",text=capturedOutput.getvalue())
2079
2081 filename = "myNewFile.txt"
2082 title = "File SaveAs"
2083 msg ="Save file as:"
2084
2085 f = filesavebox(msg,title,default=filename)
2086 writeln("You chose to save file: %s" % f)
2087
2089 title = "Demo of diropenbox"
2090 msg = "Pick the directory that you wish to open."
2091 d = diropenbox(msg, title)
2092 writeln("You chose directory...: %s" % d)
2093
2094 d = diropenbox(msg, title,default="./")
2095 writeln("You chose directory...: %s" % d)
2096
2097 d = diropenbox(msg, title,default="c:/")
2098 writeln("You chose directory...: %s" % d)
2099
2100
2102 msg = "Python files"
2103 title = "Open files"
2104 default="*.py"
2105 f = fileopenbox(msg,title,default=default)
2106 writeln("You chose to open file: %s" % f)
2107
2108 default="./*.gif"
2109 filetypes = ["*.jpg",["*.zip","*.tgs","*.gz", "Archive files"],["*.htm", "*.html","HTML files"]]
2110 f = fileopenbox(msg,title,default=default,filetypes=filetypes)
2111 writeln("You chose to open file: %s" % f)
2112
2113 """#deadcode -- testing ----------------------------------------
2114 f = fileopenbox(None,None,default=default)
2115 writeln("You chose to open file: %s" % f)
2116
2117 f = fileopenbox(None,title,default=default)
2118 writeln("You chose to open file: %s" % f)
2119
2120 f = fileopenbox(msg,None,default=default)
2121 writeln("You chose to open file: %s" % f)
2122
2123 f = fileopenbox(default=default)
2124 writeln("You chose to open file: %s" % f)
2125
2126 f = fileopenbox(default=None)
2127 writeln("You chose to open file: %s" % f)
2128 #----------------------------------------------------deadcode """
2129
2130
2133
2134 EASYGUI_ABOUT_INFORMATION = '''
2135 ========================================================================
2136 0.92(2009-06-22)
2137 ========================================================================
2138
2139 ENHANCMENTS
2140 ------------------------------------------------------
2141
2142 * Added EgStore class to to provide basic easy-to-use persistence.
2143
2144 BUG FIXES
2145 ------------------------------------------------------
2146
2147 * Fixed a bug that was preventing Linux users from copying text out of
2148 a textbox and a codebox. This was not a problem for Windows users.
2149
2150
2151 ========================================================================
2152 version: 0.91(2009-04-25)
2153 ========================================================================
2154
2155 ENHANCMENTS
2156 ------------------------------------------------------
2157
2158 * exposed egdemo(). Now you can write a program like this:
2159
2160 from easygui import *
2161 egdemo() # run the easygui demo
2162
2163
2164 BUG FIXES
2165 ------------------------------------------------------
2166
2167 * Removed some fileopenbox test code that was accidentally left in,
2168 causing egdemo to crash.
2169
2170 * Made EasyGui "version 2.5 aware" so that it will use the correct
2171 default filemask in fileopenbox and filesavebox under Python 2.5
2172 and earlier.
2173
2174 * fixed bugs in filesavebox by converting it to use the same code as
2175 fileopenbox for handling the "default" and "filetypes" args.
2176
2177
2178 ========================================================================
2179 version: 0.90(2009-04-20)
2180 ========================================================================
2181
2182 ENHANCMENTS
2183 ------------------------------------------------------
2184
2185 * Enhanced fileopenbox to allow it to accept multiple
2186 extensions for a single file type, e.g.:
2187 ... filetype = [[".htm",".html", "HTML filetypes"]]
2188 Previously it accepted only one.
2189
2190
2191 BUG FIXES
2192 ------------------------------------------------------
2193
2194 * Fixed a bug in fileopenbox (it was not displaying initialfile).
2195
2196 Thanks to Matthias Meier in the lovely city of Schwerin, Germany
2197 (http://en.wikipedia.org/wiki/Schwerin) for reporting the problem
2198 and supplying the basic elements of the fix.
2199
2200 * In fileopenbox, removed acceptance of a 1-tuple as a filetype.
2201
2202 This was an unnecessary and confusing feature. In theory,
2203 this change will break backward compatibility ... but
2204 there are probably no programs that used this feature.
2205
2206
2207 NOTES
2208 ----------------------------------------------------------
2209
2210 In some cases (e.g. ... default="junk.txt")
2211 there are minor differences in the display of fileopenbox
2212 between Python version 2.5 on the one hand,
2213 and Python version 2.6 and higher on the other.
2214 Python versions 2.6+ behave correctly.
2215
2216
2217 ========================================================================
2218 version 0.89(2009-04-09)
2219 ========================================================================
2220
2221 BUG FIX
2222 ------------------------------------------------------
2223 * An enhancement in version 0.88 (which added an import of StringIO)
2224 broke compatibility with Python 3.
2225
2226 "In Python 3, the StringIO and cStringIO modules are gone.
2227 Instead, import the io module and use io.StringIO or io.BytesIO
2228 for text and data respectively."
2229
2230 Many thanks to Alan Gauld, author of the "Learn to Program" web site
2231 (http://www.alan-g.me.uk/l2p) for reporting this problem and
2232 supplying the fix.
2233
2234 ========================================================================
2235 version 0.88(2009-04-06)
2236 ========================================================================
2237
2238 ENHANCEMENTS
2239 ------------------------------------------------------
2240 * Support for display of images has been extended to
2241 the various flavors of enterbox. An example of
2242 an enterbox with an image was added to the EasyGui demo.
2243
2244 MODIFICATIONS
2245 ------------------------------------------------------
2246 * In EasyGui demo, HELP output is now captured and displayed
2247 in a codebox rather than being written to stdout.
2248
2249 BUG FIX
2250 ------------------------------------------------------
2251 * Fixed a bug in fileopenbox.
2252 Thanks to Dennis A. Wolf for both the bug report and the fix.
2253
2254
2255 ========================================================================
2256 version 0.87(2009-03-18)
2257 ========================================================================
2258
2259 ENHANCEMENTS
2260 ------------------------------------------------------
2261 * EasyGui will now run under Python version 3.*
2262 as well as version 2.*
2263
2264 BUG FIXES
2265 ------------------------------------------------------
2266 * added support for "root" argument to msgbox, buttonbox, and
2267 enterbox. This feature is not yet documented or very well
2268 tested -- it should be considered experimental/beta.
2269 '''
2270
2277
2278
2279
2280 if __name__ == '__main__':
2281 if True:
2282 egdemo()
2283 else:
2284
2285 root = Tk()
2286 msg = """This is a test of a main Tk() window in which we will place an easygui msgbox.
2287 It will be an interesting experiment.\n\n"""
2288 messageWidget = Message(root, text=msg, width=1000)
2289 messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m')
2290 messageWidget = Message(root, text=msg, width=1000)
2291 messageWidget.pack(side=TOP, expand=YES, fill=X, padx='3m', pady='3m')
2292
2293
2294 msgbox("this is a test of passing in boxRoot", root=root)
2295 msgbox("this is a second test of passing in boxRoot", root=root)
2296
2297 reply = enterbox("Enter something", root=root)
2298 writeln("You wrote:", reply)
2299
2300 reply = enterbox("Enter something else", root=root)
2301 writeln("You wrote:", reply)
2302 root.destroy()
2303