Curso de Programación en Python/Input-10

De WikiCabal
Ir a la navegación Ir a la búsqueda

Input-10.py

 1 #!/usr/bin/python3
 2 #-*-coding: utf-8 -*-
 3 
 4 from tkinter import *
 5 from tkinter import ttk
 6 
 7 def calculate( *args ):
 8   try:
 9     value = float( pies.get() )
10     meters.set( ( 0.3048 * value * 10000.0 + 0.5 )/10000.0 )
11   except ValueError:
12     pass
13     
14 root = Tk()
15 root.title( "Pies a Metros" )
16 
17 mainframe = ttk.Frame( root, padding="3 3 12 12" )
18 mainframe.grid( column=0, row=0, sticky=( N, W, E, S ) )
19 mainframe.columnconfigure( 0, weight=1 )
20 mainframe.rowconfigure( 0, weight=1 )
21 
22 pies = StringVar()
23 meters = StringVar()
24 
25 pies_entry = ttk.Entry( mainframe, width=7, textvariable=pies )
26 pies_entry.grid( column=2, row=1, sticky=( W, E ) )
27 
28 ttk.Label( mainframe, textvariable=meters ).grid( column=2, row=2, sticky=( W, E ) )
29 ttk.Button( mainframe, text="Calcular", command=calculate ).grid( column=3, row=3, sticky=W )
30 
31 ttk.Label( mainframe, text="pies" ).grid(column=3, row=1, sticky=W )
32 ttk.Label( mainframe, text="es equivalente a" ).grid(column=1, row=2, sticky=E )
33 ttk.Label( mainframe, text="metros" ).grid(column=3, row=2, sticky=W )
34 
35 for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)
36 
37 pies_entry.focus()
38 root.bind('<Return>', calculate)
39 
40 root.mainloop()

Explicación

  1. wm title . "Feet to Meters"
  2. grid [ttk::frame .c -padding "3 3 12 12"] -column 0 -row 0 -sticky nwes
  3. grid columnconfigure . 0 -weight 1; grid rowconfigure . 0 -weight 1
  4. root = TkRoot.new {title "Feet to Meters"}
  5. content = Tk::Tile::Frame.new(root) {padding "3 3 12 12"}.grid(:sticky => 'nsew')
  6. TkGrid.columnconfigure root, 0, :weight => 1; TkGrid.rowconfigure root, 0, :weight => 1
  7. Tkx::wm_title(".", "Feet to Meters");
  8. Tkx::ttk__frame(".c", -padding => "3 3 12 12");
  9. Tkx::grid( ".c", -column => 0, -row => 0, -sticky => "nwes");
  10. Tkx::grid_columnconfigure( ".", 0, -weight => 1);
  11. Tkx::grid_rowconfigure(".", 0, -weight => 1);
  12. root = Tk()
  13. root.title("Feet to Meters")
  14. mainframe = ttk.Frame(root, padding="3 3 12 12")
  15. mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
  16. mainframe.columnconfigure(0, weight=1)
  17. mainframe.rowconfigure(0, weight=1)
  18. Yes, the "calculate" function appeared before this. We'll describe it down below, but need to include it near the start because we reference it in other parts of the program.
  19. Next, the above lines set up the main window, giving it the title "Feet to Meters". Next, we create a frame widget, which will hold all the content of our user interface, and place that in our main window. The "columnconfigure"/"rowconfigure" bits just tell Tk that if the main window is resized, the frame should expand to take up the extra space.
  20. Strictly speaking, we could just put the other parts of our interface directly into the main root window, without the intervening content frame. However, the main window isn't itself part of the "themed" widgets, so its background color wouldn't match the themed widgets we will put inside it. Using a "themed" frame widget to hold the content ensures that the background is correct.
  21. grid [ttk::entry .c.pies -width 7 -textvariable pies] -column 2 -row 1 -sticky we
  22. grid [ttk::label .c.meters -textvariable meters] -column 2 -row 2 -sticky we
  23. grid [ttk::button .c.calc -text "Calculate" -command calculate] -column 3 -row 3 -sticky w
  24. $pies = TkVariable.new; $meters = TkVariable.new
  25. f = Tk::Tile::Entry.new(content) {width 7; textvariable $pies}.grid( :column => 2, :row => 1, :sticky => 'we' )
  26. Tk::Tile::Label.new(content) {textvariable $meters}.grid( :column => 2, :row => 2, :sticky => 'we');
  27. Tk::Tile::Button.new(content) {text 'Calculate'; command {calculate}}.grid( :column => 3, :row => 3, :sticky => 'w')
  28. Tkx::ttk__entry(".c.pies", -width => 7, -textvariable => \$pies);
  29. Tkx::grid(".c.pies", -column => 2, -row => 1, -sticky => "we");
  30. Tkx::ttk__label(".c.meters", -textvariable => \$meters);
  31. Tkx::grid(".c.meters", -column => 2, -row => 2, -sticky => "we");
  32. Tkx::ttk__button(".c.calc", -text => "Calculate", -command => sub {calculate();});
  33. Tkx::grid(".c.calc", -column => 3, -row => 3, -sticky => "w");
  34. pies = StringVar()
  35. meters = StringVar()
  36. pies_entry = ttk.Entry(mainframe, width=7, textvariable=pies)
  37. pies_entry.grid(column=2, row=1, sticky=(W, E))
  38. ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
  39. ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)
  40. The preceding lines create the three main widgets in our program: the entry where we type the number of pies in, a label where we put the resulting number of meters, and the calculate button that we press to perform the calculation.
  41. For each of the three widgets, we need to do two things: create the widget itself, and then place it onscreen. All three widgets, which are 'children' of our content window are created as instances of one of Tk's themed widget classes. At the same time as we create them, we give them certain options, such as how wide the entry is, the text to put inside the Button, etc. The entry and label each are assigned a mysterious "textvariable"; we'll see what that does shortly.
  42. If the widgets are just created, they won't automatically show up on screen, because Tk doesn't know how you want them to be placed relative to other widgets. That's what the "grid" part does. Remembering the layout grid for our application, we place each widget in the appropriate column (1, 2 or 3), and row (also 1, 2 or 3). The "sticky" option says how the widget would line up within the grid cell, using compass directions. So "w" (west) means anchor the widget to the left side of the cell, "we" (west-east) means anchor it to both the left and right sides, and so on.
  43. grid [ttk::label .c.flbl -text "pies"] -column 3 -row 1 -sticky w
  44. grid [ttk::label .c.islbl -text "is equivalent to"] -column 1 -row 2 -sticky e
  45. grid [ttk::label .c.mlbl -text "meters"] -column 3 -row 2 -sticky w
  46. Tk::Tile::Label.new(content) {text 'pies'}.grid( :column => 3, :row => 1, :sticky => 'w')
  47. Tk::Tile::Label.new(content) {text 'is equivalent to'}.grid( :column => 1, :row => 2, :sticky => 'e')
  48. Tk::Tile::Label.new(content) {text 'meters'}.grid( :column => 3, :row => 2, :sticky => 'w')
  49. Tkx::grid( Tkx::ttk__label(".c.flbl", -text => "pies"), -column => 3, -row => 1, -sticky => "w");
  50. Tkx::grid( Tkx::ttk__label(".c.islbl", -text => "is equivalent to"), -column => 1, -row => 2, -sticky => "e");
  51. Tkx::grid( Tkx::ttk__label(".c.mlbl", -text => "meters"), -column => 3, -row => 2, -sticky => "w");
  52. ttk.Label(mainframe, text="pies").grid(column=3, row=1, sticky=W)
  53. ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
  54. ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)
  55. The above three lines do exactly the same thing for the three static text labels in our user interface; create each one, and place it onscreen in the appropriate cell in the grid.
  56. foreach w [winfo children .c] {grid configure $w -padx 5 -pady 5}
  57. focus .c.pies
  58. bind . <Return> {calculate}
  59. TkWinfo.children(content).each {|w| TkGrid.configure w, :padx => 5, :pady => 5}
  60. f.focus
  61. root.bind("Return") {calculate}
  62. foreach (Tkx::SplitList(Tkx::winfo_children(".c"))) { Tkx::grid_configure($_, -padx => 5, -pady => 5); }
  63. Tkx::focus(".c.pies");
  64. Tkx::bind(".", "<Return>", sub {calculate();});
  65. for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)
  66. pies_entry.focus()
  67. root.bind('<Return>', calculate)
  68. The preceeding three lines help put some nice finishing touches on our user interface.
  69. The first line walks through all of the widgets that are children of our content frame, and adds a little bit of padding around each, so they aren't so scrunched together. We could have added these options to each "grid" call when we first put the widgets onscreen, but this is a nice shortcut.
  70. The second line tells Tk to put the focus on our entry widget. That way the cursor will start in that field, so the user doesn't have to click in it before starting to type.
  71. The third line tells Tk that if the user presses the Return key (Enter on Windows) anywhere within the root window, that it should call our calculate routine, the same as if the user pressed the Calculate button.
  72. proc calculate {} {
  73. if {[catch {
  74. set ::meters [expr {round($::pies*0.3048*10000.0)/10000.0}]
  75. }]!=0} {
  76. set ::meters ""
  77. }
  78. }
  79. def calculate
  80. begin
  81. $meters.value = (0.3048*$pies*10000.0).round()/10000.0
  82. rescue
  83. $meters.value =
  84. end
  85. end
  86. sub calculate {
  87. $meters = int(0.3048*$pies*10000.0+.5)/10000.0 || ;
  88. }
  89. def calculate(*args):
  90. try:
  91. value = float(pies.get())
  92. meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
  93. except ValueError:
  94. pass
  95. Here we define our calculate procedure, which is called either when the user presses the Calculate button, or hits the Return key. It performs the pies to meters calculation, taking the number of pies from our entry widget, and placing the result in our label widget.
  96. Say what? It doesn't look like we're doing anything with those widgets! Here's where the magic "textvariable" options we specified when creating the widgets come into play. We specified the global variable "pies" as the textvariable for the entry, which means that anytime the entry changes, Tk will automatically update the global variable pies. Similarly, if we explicitly change the value of a textvariable associated with a widget (as we're doing for "meters" which is attached to our label), the widget will automatically be updated with the current contents of the variable. Slick.
  97. Tk.mainloop
  98. This final line tells Tk to enter its event loop, which is needed to make everything run.
  99. Tkx::MainLoop();
  100. This final line tells Tk to enter its event loop, which is needed to make everything run.
  101. root.mainloop();
  102. This final line tells Tk to enter its event loop, which is needed to make everything run.


Resultado

Input-10.png