Skip to content

Commit

Permalink
update intro, listbox, canvas, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
rasql committed Mar 14, 2020
1 parent 77579ac commit e7a7697
Show file tree
Hide file tree
Showing 55 changed files with 596 additions and 415 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ More tutorials
--------------

* https://opencv-tutorial.readthedocs.io
* https://pygame.readthedocs.io
* https://pymunk-tutorial.readthedocs.io
* https://cocos2d-tutorial.readthedocs.io
* https://sqlite-tutorial.readthedocs.io
* https://ev3-tutorial.readthedocs.io
* https://tk-tutorial.readthedocs.io
* https://cocos2d-tutorial.readthedocs.io
* https://pygame.readthedocs.io
13 changes: 6 additions & 7 deletions docs/button/bind1.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import tkinter as tk

root = tk.Tk()
l = tk.Label(root, text='starting...', font='Arial 36')
l.pack()
label = tk.Label(root, text='starting...', font='Arial 36')
label.pack()

l.bind('<Enter>', lambda e: l.configure(text='mouse inside'))
l.bind('<Leave>', lambda e: l.configure(text='mouse outside'))
l.bind('<1>', lambda e: l.configure(text='mouse click'))

root.mainloop()
label.bind('<Enter>', lambda e: l.configure(text='mouse inside'))
label.bind('<Leave>', lambda e: l.configure(text='mouse outside'))
label.bind('<1>', lambda e: l.configure(text='mouse click'))

root.mainloop()
46 changes: 25 additions & 21 deletions docs/button/button.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,16 @@ Finally root calls the ``mainloop()`` method to start the program::
Convert feet to meters
----------------------

Now let's create a real application.
Let's create a small program which has an input, an output
and does something when you press a button (or when you hit the return key).
It's a small program which converts feet to meters.
Now let's create a real application which does something useful.
The following program has an **input** entry field, a **button** and an **output** label.
When you press the button (or hit the return key) it converts feet to meters.

.. image:: button2.png

After importing the **classic Tk** module as ``tk``
we define the ``calculate`` function which gets the feet value
and converts it to the meter value::
we create the ``root`` object and set a descriptive window title::

def calculate(*args):
try:
value = float(feet.get())
meters.set(0.3048 * value)
except ValueError:
pass

Then we create the ``root`` object and give a title to the window::
import tkinter as tk

root = tk.Tk()
root.title("Feet to meters")
Expand All @@ -67,7 +58,7 @@ Now it's time to create the three widgets:

* an entry widget with the text variable ``feet``
* a button widget with the command function ``calculate``
* a label widget with the text variable ``meters```
* a label widget with the text variable ``meters``

All three widgets are placed with the ``pack()`` method::

Expand All @@ -81,6 +72,19 @@ and start the main loop::
root.bind('<Return>', calculate)
root.mainloop()

The conversion is done by calling the ``calculate`` function which gets the feet value
from the ``StringVar`` **feet**,
converts the value to meters and sets the ``StringVar`` **meters**.
We enclose the calculation inside a ``try-except`` statement to account for value errors,
in case the input string is not numeric. ::

def calculate(*args):
try:
value = float(feet.get())
meters.set(0.3048 * value)
except ValueError:
pass

:download:`button2.py<button2.py>`

.. literalinclude:: button2.py
Expand All @@ -97,7 +101,7 @@ To understand Tk you need to understand:
Widgets are the things you can see on the screen,
for example a label, an entry field or a button.
Later you will see checkboxes, radiobuttons, and listboxes.
Widgets are often referred to as controls.
Widgets are sometimes referred to as controls.

Widgets are objects, instances of classes.
In the example above we had the following 2-level hierarchy:
Expand Down Expand Up @@ -177,7 +181,7 @@ Common options are:
* ``text`` - a static text
* ``textvariable`` - a dynamic text from a variable
* ``image`` - an image to be displayed
* ``compound`` - conter, top, bottom, left, right
* ``compound`` - center, top, bottom, left, right (text position in in relation to image)
* ``justifiy`` - left, center, right
* ``wraplength`` - linelength for long labels

Expand Down Expand Up @@ -210,14 +214,14 @@ This function is called, but without an argument.
We can use the ``lambda`` function to create a function on the fly and
provide an argument.

.. literalinclude:: button3.py

:download:`button3.py<button3.py>`

Pressing the 3 buttons one after another writes this to the console::

button 1
button 2
button 3

.. literalinclude:: button3.py

:download:`button3.py<button3.py>`


14 changes: 7 additions & 7 deletions docs/button/button2.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import tkinter as tk

def calculate(*args):
try:
value = float(feet.get())
meters.set(0.3048 * value)
except ValueError:
pass

root = tk.Tk()
root.title("Feet to meters")

feet = tk.StringVar()
meters = tk.StringVar()

def calculate(*args):
try:
value = float(feet.get())
meters.set(0.3048 * value)
except ValueError:
pass

tk.Entry(root, width=10, textvariable=feet).pack()
tk.Button(root, text='Convert feet to meters', command=calculate).pack()
tk.Label(root, textvariable=meters).pack()
Expand Down
18 changes: 17 additions & 1 deletion docs/canvas/canvas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,20 @@ Draw shapes with the mouse

.. literalinclude:: canvas9.py

:download:`canvas9.py<canvas9.py>`
:download:`canvas9.py<canvas9.py>`


Draw straight lines with the mouse
----------------------------------

In order to draw with the mouse we have to add two bindings to the canvas:

- **<Button-1>** to initiate the drawing, calling the ``start()`` method
- **<B1_Motion>** to update the current drawing, calling the ``move()`` method

.. image:: draw1.png

.. literalinclude:: draw1.py

:download:`draw1.py<draw1.py>`

Binary file modified docs/canvas/canvas1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions docs/canvas/canvas6.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ def __init__(self):
super().__init__()
Label("Canvas configuration", font="Arial 24")

Spinbox('width', 'App.c["width"]=self.val.get()', inc=50, to=1000)
Spinbox('height', 'App.c["height"]=self.val.get()', inc=50, to=1000)
Combobox('background', 'white;yellow;pink;light blue', 'App.c.config(background=self.val.get())')
Combobox('highlightcolor', 'black;red;blue;green', 'App.c.config(highlightcolor=self.val.get())')
Combobox('relief', 'flat;sunken;raised;groove', 'App.c.config(relief=self.val.get())')
Combobox('state', 'normal;disabled;hidden', 'App.c.config(state=self.val.get())')
Spinbox('borderwidth', 'App.c.config(borderwidth=self.val.get())')
Spinbox('width', 'App.c["width"]=self.var.get()', inc=50, to=1000)
Spinbox('height', 'App.c["height"]=self.var.get()', inc=50, to=1000)
Combobox('background', 'white;yellow;pink;light blue', 'App.c.config(background=self.var.get())')
Combobox('highlightcolor', 'black;red;blue;green', 'App.c.config(highlightcolor=self.var.get())')
Combobox('relief', 'flat;sunken;raised;groove', 'App.c.config(relief=self.var.get())')
Combobox('state', 'normal;disabled;hidden', 'App.c.config(state=self.var.get())')
Spinbox('borderwidth', 'App.c.config(borderwidth=self.var.get())')

Button('Config', 'print(App.c.config())')

Expand Down
21 changes: 20 additions & 1 deletion docs/canvas/canvas7.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
"""Canvas configuration with Treeview"""
from tklib import *

class Option:
def __init__(self, widget):
self.w = widget
tree = Treeview(columns=(0))
tree.column(0, width=150)
tree.heading(0, text='Value')
tree.grid(row=0, column=2)

d = self.w.config()
print(d)
for (k, v) in d.items():
if len(v)>2:
tree.insert('', 'end', text=k, values=v[-1])


class Demo(App):
def __init__(self):
super().__init__()
Label("Canvas configuration", font="Arial 24")

App.stack[-1]=Frame()
App.c = Canvas()
App.c = Canvas(background='lightblue',
borderwidth=10,
height=250)
d = App.c.config()

tree = Treeview(columns=(0))
Expand All @@ -19,4 +36,6 @@ def __init__(self):
if len(v)>2:
tree.insert('', 'end', text=k, values=v[-1])

Option(App.c)

Demo().run()
Binary file added docs/canvas/draw1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions docs/canvas/draw1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# draw straight lines on a canvas
from tklib import *

class Canvas(tk.Canvas):
"""Define a canvas with line drawing"""

def __init__(self, **kwargs):
# super(Canvas, self).__init__(App.stack[-1], width=w, height=h, bg='light blue')
super(Canvas, self).__init__(App.stack[-1], **kwargs)
self.grid()
self.bind('<Button-1>', self.start)
self.bind('<B1-Motion>', self.move)
self.bind('<D>', self.print_msg)
self.bind('<Key>', self.print_msg)
self.bind('<Return>', self.print_msg)


def start(self, event=None):
# Execute a callback function.
self.x0 = event.x
self.y0 = event.y
self.id = self.create_line(self.x0, self.y0, self.x0, self.y0)
self.itemconfig(self.id, fill=color.var.get())
self.itemconfig(self.id, width=thickness.var.get())

def move(self, event=None):
self.x1 = event.x
self.y1 = event.y
self.coords(self.id, self.x0, self.y0, self.x1, self.y1)

def print_msg(self, event):
print(event)

app = App('Drawing lines on a canvas')
color = Combobox('Color', 'black;red;green;blue;yellow;cyan;magenta')
thickness = Combobox('Thickness', '1;2;5;10;20')
Canvas(width=600, height=200)

app.run()
50 changes: 50 additions & 0 deletions docs/canvas/draw2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# draw straight lines on a canvas
from tklib import *

class Canvas(tk.Canvas):
"""Define a canvas with line drawing"""

def __init__(self, **kwargs):
# super(Canvas, self).__init__(App.stack[-1], width=w, height=h, bg='light blue')
super(Canvas, self).__init__(App.stack[-1], **kwargs)
self.grid()
self.bind('<Button-1>', self.start)
self.bind('<B1-Motion>', self.move)
self.bind('<D>', self.print_msg)
self.bind('<Key>', self.print_msg)
self.bind('<Return>', self.print_msg)


def start(self, event=None):
# Execute a callback function.
self.x0 = event.x
self.y0 = event.y
self.id = self.create_line(self.x0, self.y0, self.x0, self.y0)
self.itemconfig(self.id, fill=color.var.get())
self.itemconfig(self.id, width=thickness.var.get())

def move(self, event=None):
self.x1 = event.x
self.y1 = event.y
self.coords(self.id, self.x0, self.y0, self.x1, self.y1)

def print_msg(self, event):
print(event)

colors = ('red', 'blue', 'green', 'cyan', 'magenta', 'yellow', 'black')

app = App('Drawing lines on a canvas')
color = Combobox('Color', 'black;red;green;blue;yellow;cyan;magenta')
thickness = Combobox('Thickness', '1;2;5;10;20')

canvas = Canvas(width=600, height=200)

x = 10
d = 20
for col in colors:
id = canvas.create_rectangle(x, 0, x+d, d, fill=col)
canvas.tag_bind(id, '<Button-1>', lambda e : print(eval(col)))

x += d

app.run()
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
# -- Project information -----------------------------------------------------

project = 'Tk tutorial'
copyright = '2019, Raphael Holzer'
copyright = '2019-2020, Raphael Holzer'
author = 'Raphael Holzer'

# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = '2019'
release = '2020'


# -- General configuration ---------------------------------------------------
Expand Down
39 changes: 39 additions & 0 deletions docs/event/event.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,42 @@ This is a screen capture of the above program.
.. literalinclude:: event3.py

:download:`event3.py<event3.py>`


Keyboard events
---------------

Specific keyboard events can be bound to a specific widget and trigger a callback function.
In the example below we bind different keys to the root widget in order to call a callback function.
The callback function inserts the event despcriptor or a short text into a **Text** widget.

- **<Key>** - any key
- **a** - a lower-case a (or any other letter)
- **A** - an upper-case A
- **<Return>** - the Return key
- **<Escape>** - the Escape key
- **<Tab>** - the Tab key

Modifier keys can also bind to a callback function.
They work equally for the left and the right keys.

- **<Shift_L>** for the Shift keys
- **<Control_L>** for the Control keys
- **<Alt_L>** for the Alt keys
- **<Meta_L>** for the Command key (on the Mac)
- **<Super_L>** for the Fn key (on the Mac)

Finally we configure the **BackSpace** key to clear the screen::

root.bind('<BackSpace>', lambda e: text.delete('1.0', 'end'))

The *x=-5, y=-50* coordinates are the position of the widget.

This is a screen capture showing the trace of various key presses.

.. image:: event4.png

.. literalinclude:: event4.py

:download:`event4.py<event4.py>`

0 comments on commit e7a7697

Please sign in to comment.