PageRenderTime 34ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/examples/thinking_in_tkinter/tt070.py

https://github.com/jasoncbautista/Focus-Motivator
Python | 156 lines | 142 code | 11 blank | 3 comment | 15 complexity | d580ba94833cd8506d1a1a24207a3d8f MD5 | raw file
  1. """<tt070.py
  2. In the previous program, you could make the buttons do something by clicking on
  3. them with the mouse, but you couldn't make them do something by pressing a key
  4. on the keyboard. In this program, we see how to make them react to keyboard
  5. events as well as mouse events.
  6. First, we need the concept of "input focus", or simply "focus".
  7. If you're familiar with Greek mythology (or if you saw the Disney animated movie
  8. "Hercules") you may remember the Fates. The Fates were three old women who
  9. controlled the destinies of men. Each human life was a thread in the hands of
  10. the Fates, and when they cut the thread, the life ended.
  11. The remarkable thing about the Fates was that they shared only one eye among
  12. all three of them. The one with the eye had to do all of the seeing, and tell
  13. the other two what she saw. The eye could be passed from one Fate to another,
  14. so they could take turns seeing. And of course, if you could steal the eye, you
  15. had a MAJOR bargaining chip when negotiating with the Fates.
  16. "Focus" is what allows the widgets on your GUI to see keyboard events. It is to
  17. the widgets on your GUI, what the single eye was to the Fates.
  18. Only one widget at a time can have the focus, and the widget that "has focus" is
  19. the widget that sees, and responds to, keyboard events. "Setting focus" on a
  20. widget is the process of giving the focus to the widget.
  21. In this program, for example, our GUI has two buttons: "OK" and "Cancel".
  22. Suppose I hit the RETURN button on the keyboard. Will that keypress "Return"
  23. event be seen by (or sent to) the "OK" button, indicating the user has accepted
  24. his choice? Or will the "Return" event be seen by (or sent to) the "Cancel"
  25. button, indicating that the user has cancelled the operation? It depends on
  26. where the "focus" is. That is, it depends on which (if any) of the buttons "has
  27. focus".
  28. Like the Fates' eye, which could be passed from one Fate to another, focus can
  29. be passed from one GUI widget to another. There are several ways of passing, or
  30. moving, the focus from one widget to another. One way is with the mouse. You
  31. can "set focus" on a widget by clicking on the widget with the left mouse
  32. button. (At least, this model, which is called the "click to type" model, is
  33. the way it works on Windows and Macintosh, and in Tk and Tkinter. There are
  34. some systems that use a "focus follows mouse" convention in which the widget
  35. that is under the mouse automatically has focus, and no click is necessary. You
  36. can get the same effect in Tk by using the tk_focusFollowsMouse procedure.)
  37. Another way to set focus is with the keyboard. The set of widgets that are
  38. capable of receiving the focus are stored in a circular list (the "traversal
  39. order") in the order in which the widgets were created. Hitting the TAB key on
  40. the keyboard moves the focus from its current location (which may be nowhere) to
  41. the next widget in the list. At the end of the list, the focus moves to the
  42. widget at the head of the list. And hitting SHIFT+TAB moves the focus backward,
  43. rather than forward, in the list.
  44. When a GUI button has focus, the fact that it has focus is shown by a small
  45. dotted box around the text of the button. Here's how to see it. Run our
  46. previous program. When the program starts, and the GUI displays, neither of the
  47. buttons has focus, so you don't see the dotted box. Now hit the TAB key. You
  48. will see the little dotted box appear around the left button, showing that focus
  49. has been given to it. Now hit the TAB key again, and again. You will see how
  50. the focus jumps to the next button, and when it reaches the last button, it
  51. wraps around again to the first one. (Since the program shows only two buttons,
  52. the effect is that the focus jumps back and forth between the two buttons.)
  53. (0)
  54. In this program, we would like the OK button to have focus from the very
  55. beginning. So we use the "focus_force()" method, which forces the focus to go to
  56. the OK button. When you run this program, you will see that the OK button has
  57. focus from the time the application starts.
  58. In the last program, our buttons responded to only one keyboard event -- a keyprees
  59. of the TAB key -- which moved the focus back and forth between the two buttons.
  60. But if you hit the ENTER/RETURN key on the keyboard, nothing happened. That is
  61. because we had bound only mouse clicks, not keyboard events, to our buttons.
  62. In this program we will also bind keyboard events to the buttons.
  63. (1) (2)
  64. The statements to bind keyboard events to the buttons are quite simple -- they
  65. have the same format as statements to bind mouse events. The only difference is
  66. that the name of the event is the name of a keyboard event (in this case,
  67. "<Return>") rather than a mouse event.
  68. We want a press of the RETURN key on the keyboard and a click of the left mouse
  69. button to have the same effect on the widget, so we bind the same event handler
  70. to both types of events.
  71. This program shows that you can bind multiple types of events to a single widget
  72. (such as a button). And you can bind multiple <widget, event> combinations to
  73. the same event handler.
  74. (3) (4)
  75. Now that our button widgets respond to multiple kinds of events, we can
  76. demonstrate how to retrieve information from an event object. What we will do
  77. is to pass the event objects to (5) a "report_event" routine that will (6) print
  78. out information about the event that it obtains from the event's attributes.
  79. Note that in order to see this information printed out on the console, you
  80. must run this program using python (not pythonw) from a console window.
  81. PROGRAM BEHAVIOR
  82. When you run this program, you will see two buttons. Clicking on the left
  83. button, or pressing the RETURN key when the button has the keyboard focus, will
  84. change its color. Clicking on the right button, or pressing the RETURN key when
  85. the button has the keyboard focus, will shut down the application. For any of
  86. these keyboard or mouse events, you should see a printed message giving the time
  87. of the event and describing the event.
  88. [Revised: 2002-09-26]
  89. >"""
  90. from Tkinter import *
  91. class MyApp:
  92. def __init__(self, parent):
  93. self.myParent = parent
  94. self.myContainer1 = Frame(parent)
  95. self.myContainer1.pack()
  96. self.button1 = Button(self.myContainer1)
  97. self.button1.configure(text="OK", background= "green")
  98. self.button1.pack(side=LEFT)
  99. self.button1.focus_force() ### (0)
  100. self.button1.bind("<Button-1>", self.button1Click)
  101. self.button1.bind("<Return>", self.button1Click) ### (1)
  102. self.button2 = Button(self.myContainer1)
  103. self.button2.configure(text="Cancel", background="red")
  104. self.button2.pack(side=RIGHT)
  105. self.button2.bind("<Button-1>", self.button2Click)
  106. self.button2.bind("<Return>", self.button2Click) ### (2)
  107. def button1Click(self, event):
  108. report_event(event) ### (3)
  109. if self.button1["background"] == "green":
  110. self.button1["background"] = "yellow"
  111. else:
  112. self.button1["background"] = "green"
  113. def button2Click(self, event):
  114. report_event(event) ### (4)
  115. self.myParent.destroy()
  116. def report_event(event): ### (5)
  117. """Print a description of an event, based on its attributes.
  118. """
  119. event_name = {"2": "KeyPress", "4": "ButtonPress"}
  120. print "Time:", str(event.time) ### (6)
  121. print "EventType=" + str(event.type), \
  122. event_name[str(event.type)],\
  123. "EventWidgetId=" + str(event.widget), \
  124. "EventKeySymbol=" + str(event.keysym)
  125. root = Tk()
  126. myapp = MyApp(root)
  127. root.mainloop()