Entry, Combox, Spinbox¶
Several widgets allow to enter text or numerical information in a single field.
- the Entry widgets allows to type text
- the Combobox allows to either type text or select text from a drop-down list
- the Spinbox allows to select from a numerical range or from a list
- the Scale allows to use a slider to choose a value
Since these widgets are very similar, we treat them in the same section.
Entry widget¶
An entry widget presents the user an empty field where he can enter a text value.
Each ttk.Entry
object has these options:
- parent - the parent object
- textvariable - the text variable to hold the entered string
- width - the numbers of characters
- show - to indicate
*
for passwords
The Entry widget does not have a text
or image
option.
You have to use an additional label widget instead.
import tkinter as tk
root = tk.Tk()
name = tk.StringVar()
tk.Label(text='Name').pack()
tk.Entry(root, textvariable=name, width=10).pack()
password = tk.StringVar()
tk.Label(text='Password').pack()
tk.Entry(root, textvariable=password, show='*').pack()
root.mainloop()
A better Entry class¶
It’s time now to define a new and better Entry
class
which can do everything in one line:
Entry('First name:', 'print(self.var.get())')
This new class has the attributes:
- label - to automatically add label in front of the entry field
- cmd - to execute a command string when hitting the Return key
- val - a default value
The command function evaluates the expression entered and displays the result in the following label widget:
Entry('Enter expression', 'App.res["text"] = eval(self.var.get())')
App.res = Label('Result')
"""Create entry fields."""
from tklib import *
app = App('Entry')
Label('Entry fields', font='Arial 24')
Entry('First name:', 'print(self.var.get())', 'James')
Entry('Last name:', 'print(self.var.get())')
Entry('Password:', 'print(self.var.get())', show='*')
Entry('Enter expression', 'App.res["text"] = eval(self.var.get())')
App.res = Label('Result')
app.run()
Now let’s see how this class is defined
class Entry(ttk.Entry, EntryMixin):
"""Create an Entry object with label and callback."""
def __init__(self, label='', cmd='', val='', **kwargs):
self.var = tk.StringVar()
self.var.set(val)
self.add_widget(label, Entry, kwargs)
self['textvariable'] = self.var
self.add_cmd(cmd)
Combobox¶
A combobox combines an entry widget with a list of choices. The user can either select text from a drop-down menu or write his own text.
The first combobox allows to also enter your own text, while the second one
is restricted to chose an item from the drop-down menu by setting state='readonly'
.
The Combobox class has the options
- parent - for the parent object
- textvariable - for the variable which stores the value
- values - for the items list
- state - to indicate
readonly
Standard Combobox¶
from tklib import *
app = App('Combobox')
Label('Combobox with text entry')
days = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')
day = tk.StringVar()
day.set(days[0])
ttk.Combobox(App.stack[-1], textvariable=day, values=days).grid()
Label('state=readonly')
day2 = tk.StringVar()
day2.set(days[1])
ttk.Combobox(App.stack[-1], textvariable=day2, values=days, state='readonly').grid()
app.run()
A better Combobox class¶
A combobox combines a list of choices with an entry. The user can select from the list, but he can also enter directly a value.
The items list can be a:
- semicolon-separated string
- integer list: [2005, 2006, 2007]
- list expression (list(range10))
from tklib import *
app = App('Combobox')
Combobox('Weekday', 'Mon;Tue;Wed;Thu;Fri', 'print(self.item)')
Combobox('Country', 'Switzerland;France;Italy;Germany', 'print(self.item)')
Combobox('Year', [2005, 2006, 2007], 'print(self.item)')
Combobox('Integer', list(range(10)), 'print(self.item)')
app.run()
How is this new class defined ?
class Combobox(ttk.Combobox, EntryMixin):
"""Create a Combobox with label and callback."""
def __init__(self, label='', values='', cmd='', val=0, **kwargs):
if isinstance(values, str):
values = values.split(';')
self.var = tk.StringVar()
self.var.set(values[val])
self.add_widget(label, Combobox, kwargs)
self['textvariable'] = self.var
self['values'] = values
self.add_cmd(cmd)
self.bind('<<ComboboxSelected>>', self.cb)
Exemple¶
from tklib import *
app = App('Combobox')
Combobox('dir(tk)', dir(tk), 'print(self.item); App.entry.var.set(eval("tk."+self.item))')
App.entry = Entry('value')
Combobox('dir(ttk)', dir(ttk), 'print(eval("ttk."+self.item))')
app.run()
Another exemple¶
The items list can be a:
- semicolon-separated string
- tuple
- list
- list expression (list(range10))
The command function can be either a string to execute or a function.
from tklib import *
app = App('Combobox')
def cb(e=None):
print(c1.var.get())
Combobox('string - "1;2;3"', '1;2;3')
Combobox('tuple - (1, 2, 3)', (1, 2, 3))
Combobox('list - [1, 2, 3]', [1, 2, 3])
Combobox('range(100)', list(range(100)))
Combobox('width=10', '1;2;3', width=10)
c1 = Combobox('cmd function', (1, 2, 3), cb)
Combobox('cmd string', (1, 2, 3), 'print(self.item)')
Combobox(values='a;b;c', cmd='print(self.item)')
Combobox(values='a;b;c', cmd='print(self.item)', width=10)
app.run()
Spinbox¶
A spinbox widget is an entry widget with built-in up and down buttons that are used to either modify a numeric value or to select among a set of values. The widget implements all the features of the entry widget.
from tklib import *
app = App('Spinbox')
var1 = tk.StringVar(value='10')
ttk.Spinbox(App.stack[-1], from_=5.0, to=100.0, increment=25, textvariable=var1).grid()
# default increment=1, from_=0, to=0
var2 = tk.StringVar(value='2')
ttk.Spinbox(App.stack[-1], to=10, textvariable=var2).grid()
# how to use a value list
values = 'Frank;Conny;Jim'.split(';')
var3 = tk.StringVar(value=values[0])
ttk.Spinbox(App.stack[-1], values=values, textvariable=var3).grid()
app.run()
from entry import *
app = App('Spinbox')
Spinbox('values=(1, 2, 5, 50)', values=(1, 2, 5, 10), val=5)
Spinbox('from_=-5, to=5', from_=-5, to=5, wrap=True)
Spinbox('to=5, wrap=True', to=5, wrap=True)
Spinbox('to=50, increment=5', to=50, increment=5)
Spinbox('to=1, increment=0.1', to=1, increment=0.1)
Spinbox('<Return> self.configure()', 'print(self.configure())')
Spinbox('<Return> self.var.get()', 'print(self.var.get())', to=5)
Spinbox('state=disabled', to=5, state='disabled', val=2)
Spinbox('state=readonly', to=5, state='readonly', val=2)
app.run()
Scale¶
A scale widget provides a way for users to choose a numeric value through direct manipulation.
from entry import *
app = App('Scale')
Scale('Scale', 'print(self.var.get())', to=10, length=200)
Scale('from=-50, to=50', 'print(self.var.get())', from_=-50, to=50)
app.run()
Final implementation¶
The four classes Entry
, Combobox
, Spinbox
and Scale
have two common parts:
- adding an optional label in front of the widget
- adding a callback function
This two functions can be placed in a specal class called EntryMixin
,
which serves as second parent class for the 4 entry classes.
class EntryMixin:
"""Add label, widget and callback function."""
def add_widget(self, label, widget, kwargs):
"""Add widget with optional label."""
if label == '':
super(widget, self).__init__(App.stack[-1], **kwargs)
self.grid()
else:
d = 2 if App.debug else 0
frame = ttk.Frame(App.stack[-1], relief='solid', borderwidth=d)
frame.grid(sticky='e')
ttk.Label(frame, text=label).grid()
super(widget, self).__init__(frame, **kwargs)
self.grid(row=0, column=1)
def add_cmd(self, cmd):
# if cmd is a string store it, and replace it 'cb' callback function
if isinstance(cmd, str):
self.cmd = cmd
cmd = self.cb
self.bind('<Return>', lambda event: cmd(self, event))
def cb(self, item=None, event=None):
"""Execute the cmd string in the widget context."""
exec(self.cmd)
This allows to make the Entry
class much shorter.
class Entry(ttk.Entry, EntryMixin):
"""Create an Entry object with label and callback."""
def __init__(self, label='', cmd='', val='', **kwargs):
self.var = tk.StringVar()
self.var.set(val)
self.add_widget(label, Entry, kwargs)
self['textvariable'] = self.var
self.add_cmd(cmd)
The other class definitions are as follows:
class Combobox(ttk.Combobox, EntryMixin):
"""Create a Combobox with label and callback."""
def __init__(self, label='', values='', cmd='', val=0, **kwargs):
if isinstance(values, str):
values = values.split(';')
self.var = tk.StringVar()
self.var.set(values[val])
self.add_widget(label, Combobox, kwargs)
self['textvariable'] = self.var
self['values'] = values
self.add_cmd(cmd)
self.bind('<<ComboboxSelected>>', self.cb)
class Spinbox(ttk.Spinbox, EntryMixin):
"""Create a Spinbox with label and callback."""
def __init__(self, label='', cmd='', values='', val=0, **kwargs):
if isinstance(values, str):
values = values.split(';')
if len(values) > 1:
val = values[val]
self.var = tk.StringVar(value=val)
self.add_widget(label, Spinbox, kwargs)
self['textvariable'] = self.var
if len(values) > 1:
self['values'] = values
self.add_cmd(cmd)
class Scale(ttk.Scale, EntryMixin):
"""Create a Spinbox with label and callback."""
def __init__(self, label='', cmd='', val=0, **kwargs):
self.var = tk.IntVar(value=val)
if not 'length' in kwargs:
kwargs.update({'length': 200})
self.add_widget(label, Scale, kwargs)
self['variable'] = self.var
self.add_cmd(cmd)
if isinstance(cmd, str):
self.cmd = cmd
cmd = self.cb
self['command'] = lambda event: cmd(self, event)