|
| 1 | +"""A banana preferences survey written in Python with Tkinter""" |
| 2 | + |
| 3 | +import tkinter as tk |
| 4 | + |
| 5 | +# Create the root window |
| 6 | +root = tk.Tk() |
| 7 | + |
| 8 | +# set the title |
| 9 | +root.title('Banana interest survey') |
| 10 | + |
| 11 | +# set the root window size |
| 12 | +root.geometry('640x480+300+300') |
| 13 | +root.resizable(False, False) |
| 14 | + |
| 15 | +########### |
| 16 | +# Widgets # |
| 17 | +########### |
| 18 | + |
| 19 | +# Use a Label to show the title |
| 20 | +# 'font' lets us set a font |
| 21 | +title = tk.Label( |
| 22 | + root, |
| 23 | + text='Please take the survey', |
| 24 | + font=('Arial 16 bold'), |
| 25 | + bg='brown', |
| 26 | + fg='#FF0' |
| 27 | +) |
| 28 | + |
| 29 | +# Use an Entry to get a string |
| 30 | +name_label = tk.Label(root, text='What is your name?') |
| 31 | +name_inp = tk.Entry(root) |
| 32 | + |
| 33 | +# Use Checkbutton to get a boolean |
| 34 | +eater_inp = tk.Checkbutton(root, text='Check this box if you eat bananas') |
| 35 | + |
| 36 | +# Spinboxes are good for number entry |
| 37 | +num_label = tk.Label(root, text='How many bananas do you eat per day?') |
| 38 | +num_inp = tk.Spinbox(root, from_=0, increment=1, value=3) |
| 39 | + |
| 40 | +# Listbox is good for choices |
| 41 | + |
| 42 | +color_label = tk.Label(root, text='What is the best color for a banana?') |
| 43 | +color_inp = tk.Listbox(root, height=1) # Only show selected item |
| 44 | +# add choices |
| 45 | +color_choices = ( |
| 46 | + 'Any', |
| 47 | + 'Green', |
| 48 | + 'Green-Yellow', |
| 49 | + 'Yellow', |
| 50 | + 'Brown spotted', |
| 51 | + 'Black' |
| 52 | +) |
| 53 | +for choice in color_choices: |
| 54 | + # END is a tkinter constant that means the end of an input |
| 55 | + color_inp.insert(tk.END, choice) |
| 56 | + |
| 57 | + |
| 58 | +# RadioButtons are good for small choices |
| 59 | + |
| 60 | +plantain_label = tk.Label(root, text='Do you eat plantains?') |
| 61 | +# Use a Frame to keep widgets together |
| 62 | +plantain_frame = tk.Frame(root) |
| 63 | +plantain_yes_inp = tk.Radiobutton(plantain_frame, text='Yes') |
| 64 | +plantain_no_inp = tk.Radiobutton(plantain_frame, text='Ewww, no!') |
| 65 | + |
| 66 | +# The Text widget is good for long pieces of text |
| 67 | +banana_haiku_label = tk.Label(root, text='Write a haiku about bananas') |
| 68 | +banana_haiku_inp = tk.Text(root, height=3) |
| 69 | + |
| 70 | +# Buttons are used to trigger actions |
| 71 | + |
| 72 | +submit_btn = tk.Button(root, text='Submit Survey') |
| 73 | + |
| 74 | +# Use a label to display a line of output |
| 75 | +# 'anchor' sets where the text is stuck if the label is wider than needed. |
| 76 | +# 'justify' determines how multiple lines of text are aligned |
| 77 | +output_line = tk.Label(root, text='', anchor='w', justify='left') |
| 78 | + |
| 79 | + |
| 80 | +####################### |
| 81 | +# Geometry Management # |
| 82 | +####################### |
| 83 | +# Using Grid instead of pack |
| 84 | +# Put our widgets on the root window |
| 85 | +#title.grid() |
| 86 | +# columnspan allows the widget to span multiple columns |
| 87 | +title.grid(columnspan=2) |
| 88 | + |
| 89 | +# add name label and input |
| 90 | +# Column defaults to 0 |
| 91 | +name_label.grid(row=1, column=0) |
| 92 | + |
| 93 | +# The grid automatically expands |
| 94 | +# when we add a widget to the next row or column |
| 95 | +name_inp.grid(row=1, column=1) |
| 96 | + |
| 97 | +# 'sticky' attaches the widget to the named sides, |
| 98 | +# so it will expand with the grid |
| 99 | +eater_inp.grid(row=2, columnspan=2, sticky='we') |
| 100 | +# tk constants can be used instead of strings |
| 101 | +num_label.grid(row=3, sticky=tk.W) |
| 102 | +num_inp.grid(row=3, column=1, sticky=(tk.W + tk.E)) |
| 103 | + |
| 104 | +#padx and pady can still be used to add horizontal or vertical padding |
| 105 | +color_label.grid(row=4, columnspan=2, sticky=tk.W, pady=10) |
| 106 | +color_inp.grid(row=5, columnspan=2, sticky=tk.W + tk.E, padx=25) |
| 107 | + |
| 108 | +# We can still use pack on the plantain frame. |
| 109 | +# pack and grid can be mixed in a layout as long as we don't |
| 110 | +# use them in the same frame |
| 111 | +plantain_yes_inp.pack(side='left', fill='x', ipadx=10, ipady=5) |
| 112 | +plantain_no_inp.pack(side='left', fill='x', ipadx=10, ipady=5) |
| 113 | +plantain_label.grid(row=6, columnspan=2, sticky=tk.W) |
| 114 | +plantain_frame.grid(row=7, columnspan=2, stick=tk.W) |
| 115 | + |
| 116 | +# Sticky on all sides will allow the widget to fill vertical and horizontal |
| 117 | +banana_haiku_label.grid(row=8, sticky=tk.W) |
| 118 | +banana_haiku_inp.grid(row=9, columnspan=2, sticky='NSEW') |
| 119 | + |
| 120 | +# Add the button and output |
| 121 | +submit_btn.grid(row=99) |
| 122 | +output_line.grid(row=100, columnspan=2, sticky='NSEW') |
| 123 | + |
| 124 | +# columnconfigure can be used to set options on the columns of the grid |
| 125 | +# 'weight' means that column will be preferred for expansion |
| 126 | +root.columnconfigure(1, weight=1) |
| 127 | + |
| 128 | +# rowconfigure works for rows |
| 129 | +root.rowconfigure(99, weight=2) |
| 130 | +root.rowconfigure(100, weight=1) |
| 131 | + |
| 132 | +##################### |
| 133 | +# Add some behavior # |
| 134 | +##################### |
| 135 | + |
| 136 | +def on_submit(): |
| 137 | + """To be run when the user submits the form""" |
| 138 | + |
| 139 | + # Many widgets use "get" to retrieve contents |
| 140 | + name = name_inp.get() |
| 141 | + # spinboxes return a str, not a float or int! |
| 142 | + number = num_inp.get() |
| 143 | + # Listboxes are more involved |
| 144 | + selected_idx = color_inp.curselection() |
| 145 | + if selected_idx: |
| 146 | + color = color_inp.get(selected_idx) |
| 147 | + else: |
| 148 | + color = '' |
| 149 | + # We're going to need some way to get our button values! |
| 150 | + # banana_eater = ???? |
| 151 | + |
| 152 | + # Text widgets require a range |
| 153 | + haiku = banana_haiku_inp.get('1.0', tk.END) |
| 154 | + |
| 155 | + # Update the text in our output |
| 156 | + message = ( |
| 157 | + f'Thanks for taking the survey, {name}.\n' |
| 158 | + f'Enjoy your {number} {color} bananas!' |
| 159 | + ) |
| 160 | + output_line.configure(text=message) |
| 161 | + print(haiku) |
| 162 | + |
| 163 | + |
| 164 | +# configure the button to trigger submission |
| 165 | +submit_btn.configure(command=on_submit) |
| 166 | + |
| 167 | +############### |
| 168 | +# Execute App # |
| 169 | +############### |
| 170 | + |
| 171 | +root.mainloop() |
0 commit comments