Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
a4aeb336
Commit
a4aeb336
authored
Oct 23, 2019
by
Julin S
Committed by
Raymond Hettinger
Oct 22, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-38539: Update demo files (GH-16890)
parent
20bf8e08
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
850 additions
and
21 deletions
+850
-21
Tools/demo/README
Tools/demo/README
+13
-13
Tools/demo/hanoi.py
Tools/demo/hanoi.py
+5
-5
Tools/demo/rpythond.py
Tools/demo/rpythond.py
+1
-1
Tools/demo/sortvisu.py
Tools/demo/sortvisu.py
+2
-2
Tools/demo/spreadsheet.py
Tools/demo/spreadsheet.py
+829
-0
No files found.
Tools/demo/README
View file @
a4aeb336
This directory contains a collection of demonstration scripts for
various aspects of Python programming.
beer.py Well-known programming example: Bottles of beer.
eiffel.py Python advanced magic: A metaclass for Eiffel post/preconditions.
hanoi.py Well-known programming example: Towers of Hanoi.
life.py Curses programming: Simple game-of-life.
markov.py Algorithms: Markov chain simulation.
mcast.py Network programming: Send and receive UDP multicast packets.
queens.py Well-known programming example: N-Queens problem.
redemo.py Regular Expressions: GUI script to test regexes.
rpython.py Network programming: Small client for remote code execution.
rpythond.py Network programming: Small server for remote code execution.
sortvisu.py GUI programming: Visualization of different sort algorithms.
ss1.py GUI/Application programming: A simple spreadsheet application.
vector.py Python basics: A vector class with demonstrating special methods.
\ No newline at end of file
beer.py Well-known programming example: Bottles of beer.
eiffel.py Python advanced magic: A metaclass for Eiffel post/preconditions.
hanoi.py Well-known programming example: Towers of Hanoi.
life.py Curses programming: Simple game-of-life.
markov.py Algorithms: Markov chain simulation.
mcast.py Network programming: Send and receive UDP multicast packets.
queens.py Well-known programming example: N-Queens problem.
redemo.py Regular Expressions: GUI script to test regexes.
rpython.py Network programming: Small client for remote code execution.
rpythond.py Network programming: Small server for remote code execution.
sortvisu.py GUI programming: Visualization of different sort algorithms.
spreadsheet.py GUI/Application programming: A simple spreadsheet application.
vector.py Python basics: A vector class demonstrating special methods.
Tools/demo/hanoi.py
View file @
a4aeb336
...
...
@@ -27,7 +27,7 @@ def hanoi(n, a, b, c, report):
class
Tkhanoi
:
# Create our objects
def
__init__
(
self
,
n
,
bitmap
=
None
):
def
__init__
(
self
,
n
,
bitmap
=
None
):
self
.
n
=
n
self
.
tk
=
tk
=
Tk
()
self
.
canvas
=
c
=
Canvas
(
tk
)
...
...
@@ -77,7 +77,7 @@ class Tkhanoi:
# Run -- never returns
def
run
(
self
):
while
1
:
while
True
:
hanoi
(
self
.
n
,
0
,
1
,
2
,
self
.
report
)
hanoi
(
self
.
n
,
1
,
2
,
0
,
self
.
report
)
hanoi
(
self
.
n
,
2
,
0
,
1
,
self
.
report
)
...
...
@@ -94,7 +94,7 @@ class Tkhanoi:
# Lift the piece above peg a
ax1
,
ay1
,
ax2
,
ay2
=
c
.
bbox
(
self
.
pegs
[
a
])
while
1
:
while
True
:
x1
,
y1
,
x2
,
y2
=
c
.
bbox
(
p
)
if
y2
<
ay1
:
break
c
.
move
(
p
,
0
,
-
1
)
...
...
@@ -103,7 +103,7 @@ class Tkhanoi:
# Move it towards peg b
bx1
,
by1
,
bx2
,
by2
=
c
.
bbox
(
self
.
pegs
[
b
])
newcenter
=
(
bx1
+
bx2
)
//
2
while
1
:
while
True
:
x1
,
y1
,
x2
,
y2
=
c
.
bbox
(
p
)
center
=
(
x1
+
x2
)
//
2
if
center
==
newcenter
:
break
...
...
@@ -114,7 +114,7 @@ class Tkhanoi:
# Move it down on top of the previous piece
pieceheight
=
y2
-
y1
newbottom
=
by2
-
pieceheight
*
len
(
self
.
pegstate
[
b
])
-
2
while
1
:
while
True
:
x1
,
y1
,
x2
,
y2
=
c
.
bbox
(
p
)
if
y2
>=
newbottom
:
break
c
.
move
(
p
,
0
,
1
)
...
...
Tools/demo/rpythond.py
View file @
a4aeb336
...
...
@@ -29,7 +29,7 @@ def main():
with
conn
:
print
(
'connection from'
,
remotehost
,
remoteport
)
request
=
b''
while
1
:
while
True
:
data
=
conn
.
recv
(
BUFSIZE
)
if
not
data
:
break
...
...
Tools/demo/sortvisu.py
View file @
a4aeb336
...
...
@@ -444,7 +444,7 @@ def quicksort(array):
array
.
wait
(
1000
)
left
=
first
right
=
last
while
1
:
while
True
:
array
.
message
(
"Sweep right pointer"
)
right
=
right
-
1
array
.
show_right
(
right
)
...
...
@@ -473,7 +473,7 @@ def quicksort(array):
array
.
hide_partition
()
def
demosort
(
array
):
while
1
:
while
True
:
for
alg
in
[
quicksort
,
insertionsort
,
selectionsort
,
bubblesort
]:
randomize
(
array
)
alg
(
array
)
...
...
Tools/demo/spreadsheet.py
0 → 100755
View file @
a4aeb336
#!/usr/bin/env python3
"""
SS1 -- a spreadsheet-like application.
"""
import
os
import
re
import
sys
from
xml.parsers
import
expat
from
xml.sax.saxutils
import
escape
LEFT
,
CENTER
,
RIGHT
=
"LEFT"
,
"CENTER"
,
"RIGHT"
def
ljust
(
x
,
n
):
return
x
.
ljust
(
n
)
def
center
(
x
,
n
):
return
x
.
center
(
n
)
def
rjust
(
x
,
n
):
return
x
.
rjust
(
n
)
align2action
=
{
LEFT
:
ljust
,
CENTER
:
center
,
RIGHT
:
rjust
}
align2xml
=
{
LEFT
:
"left"
,
CENTER
:
"center"
,
RIGHT
:
"right"
}
xml2align
=
{
"left"
:
LEFT
,
"center"
:
CENTER
,
"right"
:
RIGHT
}
align2anchor
=
{
LEFT
:
"w"
,
CENTER
:
"center"
,
RIGHT
:
"e"
}
def
sum
(
seq
):
total
=
0
for
x
in
seq
:
if
x
is
not
None
:
total
+=
x
return
total
class
Sheet
:
def
__init__
(
self
):
self
.
cells
=
{}
# {(x, y): cell, ...}
self
.
ns
=
dict
(
cell
=
self
.
cellvalue
,
cells
=
self
.
multicellvalue
,
sum
=
sum
,
)
def
cellvalue
(
self
,
x
,
y
):
cell
=
self
.
getcell
(
x
,
y
)
if
hasattr
(
cell
,
'recalc'
):
return
cell
.
recalc
(
self
.
ns
)
else
:
return
cell
def
multicellvalue
(
self
,
x1
,
y1
,
x2
,
y2
):
if
x1
>
x2
:
x1
,
x2
=
x2
,
x1
if
y1
>
y2
:
y1
,
y2
=
y2
,
y1
seq
=
[]
for
y
in
range
(
y1
,
y2
+
1
):
for
x
in
range
(
x1
,
x2
+
1
):
seq
.
append
(
self
.
cellvalue
(
x
,
y
))
return
seq
def
getcell
(
self
,
x
,
y
):
return
self
.
cells
.
get
((
x
,
y
))
def
setcell
(
self
,
x
,
y
,
cell
):
assert
x
>
0
and
y
>
0
assert
isinstance
(
cell
,
BaseCell
)
self
.
cells
[
x
,
y
]
=
cell
def
clearcell
(
self
,
x
,
y
):
try
:
del
self
.
cells
[
x
,
y
]
except
KeyError
:
pass
def
clearcells
(
self
,
x1
,
y1
,
x2
,
y2
):
for
xy
in
self
.
selectcells
(
x1
,
y1
,
x2
,
y2
):
del
self
.
cells
[
xy
]
def
clearrows
(
self
,
y1
,
y2
):
self
.
clearcells
(
0
,
y1
,
sys
.
maxsize
,
y2
)
def
clearcolumns
(
self
,
x1
,
x2
):
self
.
clearcells
(
x1
,
0
,
x2
,
sys
.
maxsize
)
def
selectcells
(
self
,
x1
,
y1
,
x2
,
y2
):
if
x1
>
x2
:
x1
,
x2
=
x2
,
x1
if
y1
>
y2
:
y1
,
y2
=
y2
,
y1
return
[(
x
,
y
)
for
x
,
y
in
self
.
cells
if
x1
<=
x
<=
x2
and
y1
<=
y
<=
y2
]
def
movecells
(
self
,
x1
,
y1
,
x2
,
y2
,
dx
,
dy
):
if
dx
==
0
and
dy
==
0
:
return
if
x1
>
x2
:
x1
,
x2
=
x2
,
x1
if
y1
>
y2
:
y1
,
y2
=
y2
,
y1
assert
x1
+
dx
>
0
and
y1
+
dy
>
0
new
=
{}
for
x
,
y
in
self
.
cells
:
cell
=
self
.
cells
[
x
,
y
]
if
hasattr
(
cell
,
'renumber'
):
cell
=
cell
.
renumber
(
x1
,
y1
,
x2
,
y2
,
dx
,
dy
)
if
x1
<=
x
<=
x2
and
y1
<=
y
<=
y2
:
x
+=
dx
y
+=
dy
new
[
x
,
y
]
=
cell
self
.
cells
=
new
def
insertrows
(
self
,
y
,
n
):
assert
n
>
0
self
.
movecells
(
0
,
y
,
sys
.
maxsize
,
sys
.
maxsize
,
0
,
n
)
def
deleterows
(
self
,
y1
,
y2
):
if
y1
>
y2
:
y1
,
y2
=
y2
,
y1
self
.
clearrows
(
y1
,
y2
)
self
.
movecells
(
0
,
y2
+
1
,
sys
.
maxsize
,
sys
.
maxsize
,
0
,
y1
-
y2
-
1
)
def
insertcolumns
(
self
,
x
,
n
):
assert
n
>
0
self
.
movecells
(
x
,
0
,
sys
.
maxsize
,
sys
.
maxsize
,
n
,
0
)
def
deletecolumns
(
self
,
x1
,
x2
):
if
x1
>
x2
:
x1
,
x2
=
x2
,
x1
self
.
clearcells
(
x1
,
x2
)
self
.
movecells
(
x2
+
1
,
0
,
sys
.
maxsize
,
sys
.
maxsize
,
x1
-
x2
-
1
,
0
)
def
getsize
(
self
):
maxx
=
maxy
=
0
for
x
,
y
in
self
.
cells
:
maxx
=
max
(
maxx
,
x
)
maxy
=
max
(
maxy
,
y
)
return
maxx
,
maxy
def
reset
(
self
):
for
cell
in
self
.
cells
.
values
():
if
hasattr
(
cell
,
'reset'
):
cell
.
reset
()
def
recalc
(
self
):
self
.
reset
()
for
cell
in
self
.
cells
.
values
():
if
hasattr
(
cell
,
'recalc'
):
cell
.
recalc
(
self
.
ns
)
def
display
(
self
):
maxx
,
maxy
=
self
.
getsize
()
width
,
height
=
maxx
+
1
,
maxy
+
1
colwidth
=
[
1
]
*
width
full
=
{}
# Add column heading labels in row 0
for
x
in
range
(
1
,
width
):
full
[
x
,
0
]
=
text
,
alignment
=
colnum2name
(
x
),
RIGHT
colwidth
[
x
]
=
max
(
colwidth
[
x
],
len
(
text
))
# Add row labels in column 0
for
y
in
range
(
1
,
height
):
full
[
0
,
y
]
=
text
,
alignment
=
str
(
y
),
RIGHT
colwidth
[
0
]
=
max
(
colwidth
[
0
],
len
(
text
))
# Add sheet cells in columns with x>0 and y>0
for
(
x
,
y
),
cell
in
self
.
cells
.
items
():
if
x
<=
0
or
y
<=
0
:
continue
if
hasattr
(
cell
,
'recalc'
):
cell
.
recalc
(
self
.
ns
)
if
hasattr
(
cell
,
'format'
):
text
,
alignment
=
cell
.
format
()
assert
isinstance
(
text
,
str
)
assert
alignment
in
(
LEFT
,
CENTER
,
RIGHT
)
else
:
text
=
str
(
cell
)
if
isinstance
(
cell
,
str
):
alignment
=
LEFT
else
:
alignment
=
RIGHT
full
[
x
,
y
]
=
(
text
,
alignment
)
colwidth
[
x
]
=
max
(
colwidth
[
x
],
len
(
text
))
# Calculate the horizontal separator line (dashes and dots)
sep
=
""
for
x
in
range
(
width
):
if
sep
:
sep
+=
"+"
sep
+=
"-"
*
colwidth
[
x
]
# Now print The full grid
for
y
in
range
(
height
):
line
=
""
for
x
in
range
(
width
):
text
,
alignment
=
full
.
get
((
x
,
y
))
or
(
""
,
LEFT
)
text
=
align2action
[
alignment
](
text
,
colwidth
[
x
])
if
line
:
line
+=
'|'
line
+=
text
print
(
line
)
if
y
==
0
:
print
(
sep
)
def
xml
(
self
):
out
=
[
'<spreadsheet>'
]
for
(
x
,
y
),
cell
in
self
.
cells
.
items
():
if
hasattr
(
cell
,
'xml'
):
cellxml
=
cell
.
xml
()
else
:
cellxml
=
'<value>%s</value>'
%
escape
(
cell
)
out
.
append
(
'<cell row="%s" col="%s">
\
n
%s
\
n
</cell>'
%
(
y
,
x
,
cellxml
))
out
.
append
(
'</spreadsheet>'
)
return
'
\
n
'
.
join
(
out
)
def
save
(
self
,
filename
):
text
=
self
.
xml
()
with
open
(
filename
,
"w"
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
if
text
and
not
text
.
endswith
(
'
\
n
'
):
f
.
write
(
'
\
n
'
)
def
load
(
self
,
filename
):
with
open
(
filename
,
'rb'
)
as
f
:
SheetParser
(
self
).
parsefile
(
f
)
class
SheetParser
:
def
__init__
(
self
,
sheet
):
self
.
sheet
=
sheet
def
parsefile
(
self
,
f
):
parser
=
expat
.
ParserCreate
()
parser
.
StartElementHandler
=
self
.
startelement
parser
.
EndElementHandler
=
self
.
endelement
parser
.
CharacterDataHandler
=
self
.
data
parser
.
ParseFile
(
f
)
def
startelement
(
self
,
tag
,
attrs
):
method
=
getattr
(
self
,
'start_'
+
tag
,
None
)
if
method
:
method
(
attrs
)
self
.
texts
=
[]
def
data
(
self
,
text
):
self
.
texts
.
append
(
text
)
def
endelement
(
self
,
tag
):
method
=
getattr
(
self
,
'end_'
+
tag
,
None
)
if
method
:
method
(
""
.
join
(
self
.
texts
))
def
start_cell
(
self
,
attrs
):
self
.
y
=
int
(
attrs
.
get
(
"row"
))
self
.
x
=
int
(
attrs
.
get
(
"col"
))
def
start_value
(
self
,
attrs
):
self
.
fmt
=
attrs
.
get
(
'format'
)
self
.
alignment
=
xml2align
.
get
(
attrs
.
get
(
'align'
))
start_formula
=
start_value
def
end_int
(
self
,
text
):
try
:
self
.
value
=
int
(
text
)
except
(
TypeError
,
ValueError
):
self
.
value
=
None
end_long
=
end_int
def
end_double
(
self
,
text
):
try
:
self
.
value
=
float
(
text
)
except
(
TypeError
,
ValueError
):
self
.
value
=
None
def
end_complex
(
self
,
text
):
try
:
self
.
value
=
complex
(
text
)
except
(
TypeError
,
ValueError
):
self
.
value
=
None
def
end_string
(
self
,
text
):
self
.
value
=
text
def
end_value
(
self
,
text
):
if
isinstance
(
self
.
value
,
BaseCell
):
self
.
cell
=
self
.
value
elif
isinstance
(
self
.
value
,
str
):
self
.
cell
=
StringCell
(
self
.
value
,
self
.
fmt
or
"%s"
,
self
.
alignment
or
LEFT
)
else
:
self
.
cell
=
NumericCell
(
self
.
value
,
self
.
fmt
or
"%s"
,
self
.
alignment
or
RIGHT
)
def
end_formula
(
self
,
text
):
self
.
cell
=
FormulaCell
(
text
,
self
.
fmt
or
"%s"
,
self
.
alignment
or
RIGHT
)
def
end_cell
(
self
,
text
):
self
.
sheet
.
setcell
(
self
.
x
,
self
.
y
,
self
.
cell
)
class
BaseCell
:
__init__
=
None
# Must provide
"""Abstract base class for sheet cells.
Subclasses may but needn't provide the following APIs:
cell.reset() -- prepare for recalculation
cell.recalc(ns) -> value -- recalculate formula
cell.format() -> (value, alignment) -- return formatted value
cell.xml() -> string -- return XML
"""
class
NumericCell
(
BaseCell
):
def
__init__
(
self
,
value
,
fmt
=
"%s"
,
alignment
=
RIGHT
):
assert
isinstance
(
value
,
(
int
,
float
,
complex
))
assert
alignment
in
(
LEFT
,
CENTER
,
RIGHT
)
self
.
value
=
value
self
.
fmt
=
fmt
self
.
alignment
=
alignment
def
recalc
(
self
,
ns
):
return
self
.
value
def
format
(
self
):
try
:
text
=
self
.
fmt
%
self
.
value
except
:
text
=
str
(
self
.
value
)
return
text
,
self
.
alignment
def
xml
(
self
):
method
=
getattr
(
self
,
'_xml_'
+
type
(
self
.
value
).
__name__
)
return
'<value align="%s" format="%s">%s</value>'
%
(
align2xml
[
self
.
alignment
],
self
.
fmt
,
method
())
def
_xml_int
(
self
):
if
-
2
**
31
<=
self
.
value
<
2
**
31
:
return
'<int>%s</int>'
%
self
.
value
else
:
return
'<long>%s</long>'
%
self
.
value
def
_xml_float
(
self
):
return
'<double>%r</double>'
%
self
.
value
def
_xml_complex
(
self
):
return
'<complex>%r</complex>'
%
self
.
value
class
StringCell
(
BaseCell
):
def
__init__
(
self
,
text
,
fmt
=
"%s"
,
alignment
=
LEFT
):
assert
isinstance
(
text
,
str
)
assert
alignment
in
(
LEFT
,
CENTER
,
RIGHT
)
self
.
text
=
text
self
.
fmt
=
fmt
self
.
alignment
=
alignment
def
recalc
(
self
,
ns
):
return
self
.
text
def
format
(
self
):
return
self
.
text
,
self
.
alignment
def
xml
(
self
):
s
=
'<value align="%s" format="%s"><string>%s</string></value>'
return
s
%
(
align2xml
[
self
.
alignment
],
self
.
fmt
,
escape
(
self
.
text
))
class
FormulaCell
(
BaseCell
):
def
__init__
(
self
,
formula
,
fmt
=
"%s"
,
alignment
=
RIGHT
):
assert
alignment
in
(
LEFT
,
CENTER
,
RIGHT
)
self
.
formula
=
formula
self
.
translated
=
translate
(
self
.
formula
)
self
.
fmt
=
fmt
self
.
alignment
=
alignment
self
.
reset
()
def
reset
(
self
):
self
.
value
=
None
def
recalc
(
self
,
ns
):
if
self
.
value
is
None
:
try
:
self
.
value
=
eval
(
self
.
translated
,
ns
)
except
:
exc
=
sys
.
exc_info
()[
0
]
if
hasattr
(
exc
,
"__name__"
):
self
.
value
=
exc
.
__name__
else
:
self
.
value
=
str
(
exc
)
return
self
.
value
def
format
(
self
):
try
:
text
=
self
.
fmt
%
self
.
value
except
:
text
=
str
(
self
.
value
)
return
text
,
self
.
alignment
def
xml
(
self
):
return
'<formula align="%s" format="%s">%s</formula>'
%
(
align2xml
[
self
.
alignment
],
self
.
fmt
,
escape
(
self
.
formula
))
def
renumber
(
self
,
x1
,
y1
,
x2
,
y2
,
dx
,
dy
):
out
=
[]
for
part
in
re
.
split
(
r'(\
w+)
', self.formula):
m = re.match('
^
([
A
-
Z
]
+
)([
1
-
9
][
0
-
9
]
*
)
$
', part)
if m is not None:
sx, sy = m.groups()
x = colname2num(sx)
y = int(sy)
if x1 <= x <= x2 and y1 <= y <= y2:
part = cellname(x+dx, y+dy)
out.append(part)
return FormulaCell("".join(out), self.fmt, self.alignment)
def translate(formula):
"""Translate a formula containing fancy cell names to valid Python code.
Examples:
B4 -> cell(2, 4)
B4:Z100 -> cells(2, 4, 26, 100)
"""
out = []
for part in re.split(r"(
\
w+(?::
\
w+)?)", formula):
m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part)
if m is None:
out.append(part)
else:
x1, y1, x2, y2 = m.groups()
x1 = colname2num(x1)
if x2 is None:
s = "cell(%s, %s)" % (x1, y1)
else:
x2 = colname2num(x2)
s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2)
out.append(s)
return "".join(out)
def cellname(x, y):
"Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'
A1
')."
assert x > 0 # Column 0 has an empty name, so can'
t
use
that
return
colnum2name
(
x
)
+
str
(
y
)
def
colname2num
(
s
):
"Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)."
s
=
s
.
upper
()
n
=
0
for
c
in
s
:
assert
'A'
<=
c
<=
'Z'
n
=
n
*
26
+
ord
(
c
)
-
ord
(
'A'
)
+
1
return
n
def
colnum2name
(
n
):
"Translate a column number to name (e.g. 1->'A', etc.)."
assert
n
>
0
s
=
""
while
n
:
n
,
m
=
divmod
(
n
-
1
,
26
)
s
=
chr
(
m
+
ord
(
'A'
))
+
s
return
s
import
tkinter
as
Tk
class
SheetGUI
:
"""Beginnings of a GUI for a spreadsheet.
TO DO:
- clear multiple cells
- Insert, clear, remove rows or columns
- Show new contents while typing
- Scroll bars
- Grow grid when window is grown
- Proper menus
- Undo, redo
- Cut, copy and paste
- Formatting and alignment
"""
def
__init__
(
self
,
filename
=
"sheet1.xml"
,
rows
=
10
,
columns
=
5
):
"""Constructor.
Load the sheet from the filename argument.
Set up the Tk widget tree.
"""
# Create and load the sheet
self
.
filename
=
filename
self
.
sheet
=
Sheet
()
if
os
.
path
.
isfile
(
filename
):
self
.
sheet
.
load
(
filename
)
# Calculate the needed grid size
maxx
,
maxy
=
self
.
sheet
.
getsize
()
rows
=
max
(
rows
,
maxy
)
columns
=
max
(
columns
,
maxx
)
# Create the widgets
self
.
root
=
Tk
.
Tk
()
self
.
root
.
wm_title
(
"Spreadsheet: %s"
%
self
.
filename
)
self
.
beacon
=
Tk
.
Label
(
self
.
root
,
text
=
"A1"
,
font
=
(
'helvetica'
,
16
,
'bold'
))
self
.
entry
=
Tk
.
Entry
(
self
.
root
)
self
.
savebutton
=
Tk
.
Button
(
self
.
root
,
text
=
"Save"
,
command
=
self
.
save
)
self
.
cellgrid
=
Tk
.
Frame
(
self
.
root
)
# Configure the widget lay-out
self
.
cellgrid
.
pack
(
side
=
"bottom"
,
expand
=
1
,
fill
=
"both"
)
self
.
beacon
.
pack
(
side
=
"left"
)
self
.
savebutton
.
pack
(
side
=
"right"
)
self
.
entry
.
pack
(
side
=
"left"
,
expand
=
1
,
fill
=
"x"
)
# Bind some events
self
.
entry
.
bind
(
"<Return>"
,
self
.
return_event
)
self
.
entry
.
bind
(
"<Shift-Return>"
,
self
.
shift_return_event
)
self
.
entry
.
bind
(
"<Tab>"
,
self
.
tab_event
)
self
.
entry
.
bind
(
"<Shift-Tab>"
,
self
.
shift_tab_event
)
self
.
entry
.
bind
(
"<Delete>"
,
self
.
delete_event
)
self
.
entry
.
bind
(
"<Escape>"
,
self
.
escape_event
)
# Now create the cell grid
self
.
makegrid
(
rows
,
columns
)
# Select the top-left cell
self
.
currentxy
=
None
self
.
cornerxy
=
None
self
.
setcurrent
(
1
,
1
)
# Copy the sheet cells to the GUI cells
self
.
sync
()
def
delete_event
(
self
,
event
):
if
self
.
cornerxy
!=
self
.
currentxy
and
self
.
cornerxy
is
not
None
:
self
.
sheet
.
clearcells
(
*
(
self
.
currentxy
+
self
.
cornerxy
))
else
:
self
.
sheet
.
clearcell
(
*
self
.
currentxy
)
self
.
sync
()
self
.
entry
.
delete
(
0
,
'end'
)
return
"break"
def
escape_event
(
self
,
event
):
x
,
y
=
self
.
currentxy
self
.
load_entry
(
x
,
y
)
def
load_entry
(
self
,
x
,
y
):
cell
=
self
.
sheet
.
getcell
(
x
,
y
)
if
cell
is
None
:
text
=
""
elif
isinstance
(
cell
,
FormulaCell
):
text
=
'='
+
cell
.
formula
else
:
text
,
alignment
=
cell
.
format
()
self
.
entry
.
delete
(
0
,
'end'
)
self
.
entry
.
insert
(
0
,
text
)
self
.
entry
.
selection_range
(
0
,
'end'
)
def
makegrid
(
self
,
rows
,
columns
):
"""Helper to create the grid of GUI cells.
The edge (x==0 or y==0) is filled with labels; the rest is real cells.
"""
self
.
rows
=
rows
self
.
columns
=
columns
self
.
gridcells
=
{}
# Create the top left corner cell (which selects all)
cell
=
Tk
.
Label
(
self
.
cellgrid
,
relief
=
'raised'
)
cell
.
grid_configure
(
column
=
0
,
row
=
0
,
sticky
=
'NSWE'
)
cell
.
bind
(
"<ButtonPress-1>"
,
self
.
selectall
)
# Create the top row of labels, and configure the grid columns
for
x
in
range
(
1
,
columns
+
1
):
self
.
cellgrid
.
grid_columnconfigure
(
x
,
minsize
=
64
)
cell
=
Tk
.
Label
(
self
.
cellgrid
,
text
=
colnum2name
(
x
),
relief
=
'raised'
)
cell
.
grid_configure
(
column
=
x
,
row
=
0
,
sticky
=
'WE'
)
self
.
gridcells
[
x
,
0
]
=
cell
cell
.
__x
=
x
cell
.
__y
=
0
cell
.
bind
(
"<ButtonPress-1>"
,
self
.
selectcolumn
)
cell
.
bind
(
"<B1-Motion>"
,
self
.
extendcolumn
)
cell
.
bind
(
"<ButtonRelease-1>"
,
self
.
extendcolumn
)
cell
.
bind
(
"<Shift-Button-1>"
,
self
.
extendcolumn
)
# Create the leftmost column of labels
for
y
in
range
(
1
,
rows
+
1
):
cell
=
Tk
.
Label
(
self
.
cellgrid
,
text
=
str
(
y
),
relief
=
'raised'
)
cell
.
grid_configure
(
column
=
0
,
row
=
y
,
sticky
=
'WE'
)
self
.
gridcells
[
0
,
y
]
=
cell
cell
.
__x
=
0
cell
.
__y
=
y
cell
.
bind
(
"<ButtonPress-1>"
,
self
.
selectrow
)
cell
.
bind
(
"<B1-Motion>"
,
self
.
extendrow
)
cell
.
bind
(
"<ButtonRelease-1>"
,
self
.
extendrow
)
cell
.
bind
(
"<Shift-Button-1>"
,
self
.
extendrow
)
# Create the real cells
for
x
in
range
(
1
,
columns
+
1
):
for
y
in
range
(
1
,
rows
+
1
):
cell
=
Tk
.
Label
(
self
.
cellgrid
,
relief
=
'sunken'
,
bg
=
'white'
,
fg
=
'black'
)
cell
.
grid_configure
(
column
=
x
,
row
=
y
,
sticky
=
'NSWE'
)
self
.
gridcells
[
x
,
y
]
=
cell
cell
.
__x
=
x
cell
.
__y
=
y
# Bind mouse events
cell
.
bind
(
"<ButtonPress-1>"
,
self
.
press
)
cell
.
bind
(
"<B1-Motion>"
,
self
.
motion
)
cell
.
bind
(
"<ButtonRelease-1>"
,
self
.
release
)
cell
.
bind
(
"<Shift-Button-1>"
,
self
.
release
)
def
selectall
(
self
,
event
):
self
.
setcurrent
(
1
,
1
)
self
.
setcorner
(
sys
.
maxsize
,
sys
.
maxsize
)
def
selectcolumn
(
self
,
event
):
x
,
y
=
self
.
whichxy
(
event
)
self
.
setcurrent
(
x
,
1
)
self
.
setcorner
(
x
,
sys
.
maxsize
)
def
extendcolumn
(
self
,
event
):
x
,
y
=
self
.
whichxy
(
event
)
if
x
>
0
:
self
.
setcurrent
(
self
.
currentxy
[
0
],
1
)
self
.
setcorner
(
x
,
sys
.
maxsize
)
def
selectrow
(
self
,
event
):
x
,
y
=
self
.
whichxy
(
event
)
self
.
setcurrent
(
1
,
y
)
self
.
setcorner
(
sys
.
maxsize
,
y
)
def
extendrow
(
self
,
event
):
x
,
y
=
self
.
whichxy
(
event
)
if
y
>
0
:
self
.
setcurrent
(
1
,
self
.
currentxy
[
1
])
self
.
setcorner
(
sys
.
maxsize
,
y
)
def
press
(
self
,
event
):
x
,
y
=
self
.
whichxy
(
event
)
if
x
>
0
and
y
>
0
:
self
.
setcurrent
(
x
,
y
)
def
motion
(
self
,
event
):
x
,
y
=
self
.
whichxy
(
event
)
if
x
>
0
and
y
>
0
:
self
.
setcorner
(
x
,
y
)
release
=
motion
def
whichxy
(
self
,
event
):
w
=
self
.
cellgrid
.
winfo_containing
(
event
.
x_root
,
event
.
y_root
)
if
w
is
not
None
and
isinstance
(
w
,
Tk
.
Label
):
try
:
return
w
.
__x
,
w
.
__y
except
AttributeError
:
pass
return
0
,
0
def
save
(
self
):
self
.
sheet
.
save
(
self
.
filename
)
def
setcurrent
(
self
,
x
,
y
):
"Make (x, y) the current cell."
if
self
.
currentxy
is
not
None
:
self
.
change_cell
()
self
.
clearfocus
()
self
.
beacon
[
'text'
]
=
cellname
(
x
,
y
)
self
.
load_entry
(
x
,
y
)
self
.
entry
.
focus_set
()
self
.
currentxy
=
x
,
y
self
.
cornerxy
=
None
gridcell
=
self
.
gridcells
.
get
(
self
.
currentxy
)
if
gridcell
is
not
None
:
gridcell
[
'bg'
]
=
'yellow'
def
setcorner
(
self
,
x
,
y
):
if
self
.
currentxy
is
None
or
self
.
currentxy
==
(
x
,
y
):
self
.
setcurrent
(
x
,
y
)
return
self
.
clearfocus
()
self
.
cornerxy
=
x
,
y
x1
,
y1
=
self
.
currentxy
x2
,
y2
=
self
.
cornerxy
or
self
.
currentxy
if
x1
>
x2
:
x1
,
x2
=
x2
,
x1
if
y1
>
y2
:
y1
,
y2
=
y2
,
y1
for
(
x
,
y
),
cell
in
self
.
gridcells
.
items
():
if
x1
<=
x
<=
x2
and
y1
<=
y
<=
y2
:
cell
[
'bg'
]
=
'lightBlue'
gridcell
=
self
.
gridcells
.
get
(
self
.
currentxy
)
if
gridcell
is
not
None
:
gridcell
[
'bg'
]
=
'yellow'
self
.
setbeacon
(
x1
,
y1
,
x2
,
y2
)
def
setbeacon
(
self
,
x1
,
y1
,
x2
,
y2
):
if
x1
==
y1
==
1
and
x2
==
y2
==
sys
.
maxsize
:
name
=
":"
elif
(
x1
,
x2
)
==
(
1
,
sys
.
maxsize
):
if
y1
==
y2
:
name
=
"%d"
%
y1
else
:
name
=
"%d:%d"
%
(
y1
,
y2
)
elif
(
y1
,
y2
)
==
(
1
,
sys
.
maxsize
):
if
x1
==
x2
:
name
=
"%s"
%
colnum2name
(
x1
)
else
:
name
=
"%s:%s"
%
(
colnum2name
(
x1
),
colnum2name
(
x2
))
else
:
name1
=
cellname
(
*
self
.
currentxy
)
name2
=
cellname
(
*
self
.
cornerxy
)
name
=
"%s:%s"
%
(
name1
,
name2
)
self
.
beacon
[
'text'
]
=
name
def
clearfocus
(
self
):
if
self
.
currentxy
is
not
None
:
x1
,
y1
=
self
.
currentxy
x2
,
y2
=
self
.
cornerxy
or
self
.
currentxy
if
x1
>
x2
:
x1
,
x2
=
x2
,
x1
if
y1
>
y2
:
y1
,
y2
=
y2
,
y1
for
(
x
,
y
),
cell
in
self
.
gridcells
.
items
():
if
x1
<=
x
<=
x2
and
y1
<=
y
<=
y2
:
cell
[
'bg'
]
=
'white'
def
return_event
(
self
,
event
):
"Callback for the Return key."
self
.
change_cell
()
x
,
y
=
self
.
currentxy
self
.
setcurrent
(
x
,
y
+
1
)
return
"break"
def
shift_return_event
(
self
,
event
):
"Callback for the Return key with Shift modifier."
self
.
change_cell
()
x
,
y
=
self
.
currentxy
self
.
setcurrent
(
x
,
max
(
1
,
y
-
1
))
return
"break"
def
tab_event
(
self
,
event
):
"Callback for the Tab key."
self
.
change_cell
()
x
,
y
=
self
.
currentxy
self
.
setcurrent
(
x
+
1
,
y
)
return
"break"
def
shift_tab_event
(
self
,
event
):
"Callback for the Tab key with Shift modifier."
self
.
change_cell
()
x
,
y
=
self
.
currentxy
self
.
setcurrent
(
max
(
1
,
x
-
1
),
y
)
return
"break"
def
change_cell
(
self
):
"Set the current cell from the entry widget."
x
,
y
=
self
.
currentxy
text
=
self
.
entry
.
get
()
cell
=
None
if
text
.
startswith
(
'='
):
cell
=
FormulaCell
(
text
[
1
:])
else
:
for
cls
in
int
,
float
,
complex
:
try
:
value
=
cls
(
text
)
except
(
TypeError
,
ValueError
):
continue
else
:
cell
=
NumericCell
(
value
)
break
if
cell
is
None
and
text
:
cell
=
StringCell
(
text
)
if
cell
is
None
:
self
.
sheet
.
clearcell
(
x
,
y
)
else
:
self
.
sheet
.
setcell
(
x
,
y
,
cell
)
self
.
sync
()
def
sync
(
self
):
"Fill the GUI cells from the sheet cells."
self
.
sheet
.
recalc
()
for
(
x
,
y
),
gridcell
in
self
.
gridcells
.
items
():
if
x
==
0
or
y
==
0
:
continue
cell
=
self
.
sheet
.
getcell
(
x
,
y
)
if
cell
is
None
:
gridcell
[
'text'
]
=
""
else
:
if
hasattr
(
cell
,
'format'
):
text
,
alignment
=
cell
.
format
()
else
:
text
,
alignment
=
str
(
cell
),
LEFT
gridcell
[
'text'
]
=
text
gridcell
[
'anchor'
]
=
align2anchor
[
alignment
]
def
test_basic
():
"Basic non-gui self-test."
a
=
Sheet
()
for
x
in
range
(
1
,
11
):
for
y
in
range
(
1
,
11
):
if
x
==
1
:
cell
=
NumericCell
(
y
)
elif
y
==
1
:
cell
=
NumericCell
(
x
)
else
:
c1
=
cellname
(
x
,
1
)
c2
=
cellname
(
1
,
y
)
formula
=
"%s*%s"
%
(
c1
,
c2
)
cell
=
FormulaCell
(
formula
)
a
.
setcell
(
x
,
y
,
cell
)
## if os.path.isfile("sheet1.xml"):
## print "Loading from sheet1.xml"
## a.load("sheet1.xml")
a
.
display
()
a
.
save
(
"sheet1.xml"
)
def
test_gui
():
"GUI test."
if
sys
.
argv
[
1
:]:
filename
=
sys
.
argv
[
1
]
else
:
filename
=
"sheet1.xml"
g
=
SheetGUI
(
filename
)
g
.
root
.
mainloop
()
if
__name__
==
'__main__'
:
#test_basic()
test_gui
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment