simplegraphics-python 1.0.12__tar.gz → 1.0.13.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/PKG-INFO +33 -2
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/README.md +21 -0
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/SimpleGraphics/__main__.py +208 -148
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/setup.py +1 -1
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/simplegraphics_python.egg-info/PKG-INFO +33 -2
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/SimpleGraphics/__init__.py +0 -0
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/setup.cfg +0 -0
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/simplegraphics_python.egg-info/SOURCES.txt +0 -0
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/simplegraphics_python.egg-info/dependency_links.txt +0 -0
- {simplegraphics-python-1.0.12 → simplegraphics_python-1.0.13.1}/simplegraphics_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: simplegraphics-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.13.1
|
|
4
4
|
Summary: A simple graphics wrapper on top of tkinter
|
|
5
5
|
Home-page: https://cspages.ucalgary.ca/~bdstephe/217_P24/
|
|
6
6
|
Author: Ben Stephenson
|
|
@@ -12,6 +12,16 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Requires-Python: >=3.1.0
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: maintainer
|
|
22
|
+
Dynamic: maintainer-email
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
15
25
|
|
|
16
26
|
****SimpleGraphics**** is a lightweight Python graphics library designed as a convenient wrapper around the standard ****tkinter**** library. Its primary purpose is to make graphical programming accessible even to beginners: simply import the module, and a graphics window opens automatically, without the need to create classes, objects or manually call mainloop.
|
|
17
27
|
|
|
@@ -394,3 +404,24 @@ text(200, 340, "SimpleGraphics!")
|
|
|
394
404
|
being drawn 1 pixel too narrow / 1 pixel too short
|
|
395
405
|
Added the optional angle argument parameter to text when
|
|
396
406
|
the Python version is greater than or equal to X.Y.Z.
|
|
407
|
+
v1.0.12 -- Publicly released April 10, 2025
|
|
408
|
+
Added the circle function (Thanks to Grygoriy Gromko for
|
|
409
|
+
suggesting its inclusion and providing the preliminary
|
|
410
|
+
implementation)
|
|
411
|
+
Updated all of the drawing primitive functions so that they
|
|
412
|
+
return the created object so that it can be modified
|
|
413
|
+
subsequently.
|
|
414
|
+
Added support for moving, scaling, deleting, and changing
|
|
415
|
+
the draw order of objects (Thanks to Grygoriy Gromko for
|
|
416
|
+
suggesting their inclusion and providing preliminary
|
|
417
|
+
implementations)
|
|
418
|
+
Fixed a bug where the ability to change the background color
|
|
419
|
+
was lost after clear has been called.
|
|
420
|
+
v1.0.13 -- Public released June 9, 2026
|
|
421
|
+
Added the savePNG function
|
|
422
|
+
Circles with diameter 1 and diameter 2 are handled as special
|
|
423
|
+
cases so that they render as a single pixel and a 2x2
|
|
424
|
+
square respectively
|
|
425
|
+
Ellipses with width and height 1 and width and height 2 are
|
|
426
|
+
handled as special cases so that they render as a single
|
|
427
|
+
pixel and a 2x2 square respectively
|
|
@@ -379,3 +379,24 @@ text(200, 340, "SimpleGraphics!")
|
|
|
379
379
|
being drawn 1 pixel too narrow / 1 pixel too short
|
|
380
380
|
Added the optional angle argument parameter to text when
|
|
381
381
|
the Python version is greater than or equal to X.Y.Z.
|
|
382
|
+
v1.0.12 -- Publicly released April 10, 2025
|
|
383
|
+
Added the circle function (Thanks to Grygoriy Gromko for
|
|
384
|
+
suggesting its inclusion and providing the preliminary
|
|
385
|
+
implementation)
|
|
386
|
+
Updated all of the drawing primitive functions so that they
|
|
387
|
+
return the created object so that it can be modified
|
|
388
|
+
subsequently.
|
|
389
|
+
Added support for moving, scaling, deleting, and changing
|
|
390
|
+
the draw order of objects (Thanks to Grygoriy Gromko for
|
|
391
|
+
suggesting their inclusion and providing preliminary
|
|
392
|
+
implementations)
|
|
393
|
+
Fixed a bug where the ability to change the background color
|
|
394
|
+
was lost after clear has been called.
|
|
395
|
+
v1.0.13 -- Public released June 9, 2026
|
|
396
|
+
Added the savePNG function
|
|
397
|
+
Circles with diameter 1 and diameter 2 are handled as special
|
|
398
|
+
cases so that they render as a single pixel and a 2x2
|
|
399
|
+
square respectively
|
|
400
|
+
Ellipses with width and height 1 and width and height 2 are
|
|
401
|
+
handled as special cases so that they render as a single
|
|
402
|
+
pixel and a 2x2 square respectively
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
##
|
|
2
2
|
# A simple graphics wrapper on top of tkinter
|
|
3
|
-
# Copyright (C) 2013, 2014, 2015, 2017, 2019, 2024 Ben Stephenson
|
|
3
|
+
# Copyright (C) 2013, 2014, 2015, 2017, 2019, 2024, 2025, 2026 Ben Stephenson
|
|
4
4
|
#
|
|
5
5
|
# This wrapper is designed to require as little effort as possible from the
|
|
6
6
|
# programmer making use of it. Importing the library opens a graphics
|
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
# of Cygwin -- It just resizes the canvas and the window fails to resize
|
|
33
33
|
# with it. Could this be related to the resize bug noted previously?
|
|
34
34
|
#
|
|
35
|
+
# * There are asymmetries in circles/ellipses with diameter 5 and 13. This
|
|
36
|
+
# may be a bug in tkinter and not practical to work around.
|
|
37
|
+
#
|
|
35
38
|
# Please report bugs by sending email to ben.stephenson@ucalgary.ca.
|
|
36
39
|
#
|
|
37
40
|
# Revision History:
|
|
@@ -86,12 +89,31 @@
|
|
|
86
89
|
# being drawn 1 pixel too narrow / 1 pixel too short
|
|
87
90
|
# Added the optional angle argument parameter to text when
|
|
88
91
|
# the Python version is greater than or equal to X.Y.Z.
|
|
92
|
+
# v1.0.12 -- Publicly released April 10, 2025
|
|
93
|
+
# Added the circle function (Thanks to Grygoriy Gromko for
|
|
94
|
+
# suggesting its inclusion and providing the preliminary
|
|
95
|
+
# implementation)
|
|
96
|
+
# Updated all of the drawing primitive functions so that they
|
|
97
|
+
# return the created object so that it can be modified
|
|
98
|
+
# subsequently.
|
|
99
|
+
# Added support for moving, scaling, deleting, and changing
|
|
100
|
+
# the draw order of objects (Thanks to Grygoriy Gromko for
|
|
101
|
+
# suggesting their inclusion and providing preliminary
|
|
102
|
+
# implementations)
|
|
103
|
+
# Fixed a bug where the ability to change the background color
|
|
104
|
+
# was lost after clear has been called.
|
|
105
|
+
# v1.0.13 -- Public released June 9, 2026
|
|
106
|
+
# Added the savePNG function
|
|
107
|
+
# Circles with diameter 1 and diameter 2 are handled as special
|
|
108
|
+
# cases so that they render as a single pixel and a 2x2
|
|
109
|
+
# square respectively
|
|
110
|
+
# Ellipses with width and height 1 and width and height 2 are
|
|
111
|
+
# handled as special cases so that they render as a single
|
|
112
|
+
# pixel and a 2x2 square respectively
|
|
89
113
|
#
|
|
90
114
|
import pprint
|
|
91
115
|
|
|
92
116
|
from sys import exit
|
|
93
|
-
from typing import Callable, Optional
|
|
94
|
-
from tkinter import *
|
|
95
117
|
|
|
96
118
|
try:
|
|
97
119
|
from atexit import register, unregister
|
|
@@ -156,10 +178,7 @@ __heldLock = Lock()
|
|
|
156
178
|
|
|
157
179
|
__background = None
|
|
158
180
|
__bgcolor = "#d0d0d0"
|
|
159
|
-
|
|
160
|
-
__frmTime = 50
|
|
161
|
-
__animation: Optional[Callable] = None
|
|
162
|
-
|
|
181
|
+
|
|
163
182
|
## Create a window containing a canvas and setup a second thread to ensure
|
|
164
183
|
# that it stays up to date. Setup the handlers needed for keyboard and
|
|
165
184
|
# mouse input.
|
|
@@ -170,7 +189,6 @@ def __init():
|
|
|
170
189
|
|
|
171
190
|
# Create the window
|
|
172
191
|
__master = tk.Tk()
|
|
173
|
-
__master.title("SimpleGraphics")
|
|
174
192
|
__master.protocol("WM_DELETE_WINDOW", __closeClicked)
|
|
175
193
|
__canvas = tk.Canvas(__master, width=800, height=600)
|
|
176
194
|
__canvas.pack()
|
|
@@ -203,47 +221,6 @@ def __init():
|
|
|
203
221
|
update()
|
|
204
222
|
__master.focus_set()
|
|
205
223
|
|
|
206
|
-
# doAnimate() - animation loop
|
|
207
|
-
# Starts the animation loop by repeatedly calling the provided function.
|
|
208
|
-
# The loop continues until `noAnimate()` is called.
|
|
209
|
-
def doAnimate(func):
|
|
210
|
-
global __loop, __animation
|
|
211
|
-
if not __loop:
|
|
212
|
-
__animation = func
|
|
213
|
-
__loop = True
|
|
214
|
-
|
|
215
|
-
__animation()
|
|
216
|
-
__canvas.after(__frmTime, doAnimate, func)
|
|
217
|
-
|
|
218
|
-
# noAnimate() - stop animation
|
|
219
|
-
# Stops the animation loop by setting the loop flag to False.
|
|
220
|
-
# Also cancels any pending animation updates.
|
|
221
|
-
def noAnimate():
|
|
222
|
-
global __loop
|
|
223
|
-
__loop = False
|
|
224
|
-
__canvas.after_cancel(__canvas)
|
|
225
|
-
|
|
226
|
-
# isAnimate() - True/False
|
|
227
|
-
# Returns the current state of the animation loop.
|
|
228
|
-
# True if the animation is running, False otherwise.
|
|
229
|
-
def isAnimate():
|
|
230
|
-
return __loop
|
|
231
|
-
|
|
232
|
-
# animationTime() - set/get frame time
|
|
233
|
-
# Sets or gets the time interval between animation frames.
|
|
234
|
-
# If a valid frame time is provided, it updates the interval.
|
|
235
|
-
# If the frame time is invalid (<= 0), it stops the animation.
|
|
236
|
-
def animationTime(frm_time=None):
|
|
237
|
-
global __frmTime
|
|
238
|
-
if frm_time is not None:
|
|
239
|
-
if frm_time > 0:
|
|
240
|
-
__frmTime = frm_time
|
|
241
|
-
else:
|
|
242
|
-
__frmTime = 0
|
|
243
|
-
noAnimate()
|
|
244
|
-
else:
|
|
245
|
-
return __frmTime
|
|
246
|
-
|
|
247
224
|
# Clear all keys being held when our window loses focus
|
|
248
225
|
# @param event the event data associated with the FocusOut event
|
|
249
226
|
def __focusOut(event):
|
|
@@ -726,6 +703,7 @@ def line(*pts):
|
|
|
726
703
|
__shape = __canvas.create_line(new_pts, fill=__outline, width=__width, capstyle=__capstyle, joinstyle=__joinstyle, arrow=__arrow, arrowshape=__arrowshape)
|
|
727
704
|
__update()
|
|
728
705
|
return __shape
|
|
706
|
+
|
|
729
707
|
except Exception as e:
|
|
730
708
|
if __canvas == None:
|
|
731
709
|
pass;
|
|
@@ -755,6 +733,7 @@ def curve(*pts):
|
|
|
755
733
|
__shape = __canvas.create_line(new_pts, fill=__outline, width=__width, capstyle=__capstyle, smooth=True, splinesteps=25, joinstyle=__joinstyle, arrow=__arrow, arrowshape=__arrowshape)
|
|
756
734
|
__update()
|
|
757
735
|
return __shape
|
|
736
|
+
|
|
758
737
|
except Exception as e:
|
|
759
738
|
if __canvas == None:
|
|
760
739
|
pass;
|
|
@@ -773,61 +752,6 @@ def curve(*pts):
|
|
|
773
752
|
# @param the points of the curve in the form x1, y1, x2, y2, ... , xn, yn.
|
|
774
753
|
# The parameter can either be a single list or provided as individual
|
|
775
754
|
# parameters.
|
|
776
|
-
|
|
777
|
-
def draw_spline(canvas, points_array, is_closed, tension=0.5, num_of_segments=12, fill=None, outline=None, width=1):
|
|
778
|
-
if len(points_array) < 2:
|
|
779
|
-
return
|
|
780
|
-
|
|
781
|
-
points = []
|
|
782
|
-
for i in range(0, len(points_array), 2):
|
|
783
|
-
points.append((points_array[i], points_array[i + 1]))
|
|
784
|
-
|
|
785
|
-
if is_closed:
|
|
786
|
-
points.append(points[0])
|
|
787
|
-
if len(points) == 3:
|
|
788
|
-
points.append(points[1])
|
|
789
|
-
|
|
790
|
-
all_points = [] # Тут зберігатимемо всі точки сплайну
|
|
791
|
-
|
|
792
|
-
plength = len(points)
|
|
793
|
-
|
|
794
|
-
for i in range(plength - 1):
|
|
795
|
-
p0 = points[i - 1] if i > 0 else (points[-2] if is_closed else points[i])
|
|
796
|
-
p1 = points[i]
|
|
797
|
-
p2 = points[i + 1]
|
|
798
|
-
p3 = points[i + 2] if i < len(points) - 2 else (points[1] if is_closed else points[i + 1])
|
|
799
|
-
|
|
800
|
-
segment_points = []
|
|
801
|
-
for t in range(num_of_segments + 1):
|
|
802
|
-
t1 = t / num_of_segments
|
|
803
|
-
t2 = t1 * t1
|
|
804
|
-
t3 = t2 * t1
|
|
805
|
-
|
|
806
|
-
m1 = tension * (p2[0] - p0[0])
|
|
807
|
-
m2 = tension * (p3[0] - p1[0])
|
|
808
|
-
n1 = tension * (p2[1] - p0[1])
|
|
809
|
-
n2 = tension * (p3[1] - p1[1])
|
|
810
|
-
|
|
811
|
-
x = (2 * t3 - 3 * t2 + 1) * p1[0] + (t3 - 2 * t2 + t1) * m1 + (-2 * t3 + 3 * t2) * p2[0] + (t3 - t2) * m2
|
|
812
|
-
y = (2 * t3 - 3 * t2 + 1) * p1[1] + (t3 - 2 * t2 + t1) * n1 + (-2 * t3 + 3 * t2) * p2[1] + (t3 - t2) * n2
|
|
813
|
-
|
|
814
|
-
segment_points.append((x, y))
|
|
815
|
-
|
|
816
|
-
all_points.extend(segment_points)
|
|
817
|
-
|
|
818
|
-
# Якщо фігура замкнута - заповнюємо
|
|
819
|
-
if is_closed and fill:
|
|
820
|
-
# Створюємо полігон з усіма точками
|
|
821
|
-
shape = canvas.create_polygon(all_points, fill=fill, outline=outline, width=width)
|
|
822
|
-
else:
|
|
823
|
-
# Малюємо тільки лінії
|
|
824
|
-
for j in range(1, len(all_points)):
|
|
825
|
-
shape =canvas.create_line(all_points[j-1][0], all_points[j-1][1],
|
|
826
|
-
all_points[j][0], all_points[j][1],
|
|
827
|
-
fill=outline if outline else 'black',
|
|
828
|
-
width=width)
|
|
829
|
-
return shape
|
|
830
|
-
|
|
831
755
|
def blob(*pts):
|
|
832
756
|
try:
|
|
833
757
|
if len(pts) == 1:
|
|
@@ -837,7 +761,7 @@ def blob(*pts):
|
|
|
837
761
|
for i in range(len(new_pts)):
|
|
838
762
|
new_pts[i] = new_pts[i] + 1
|
|
839
763
|
|
|
840
|
-
__shape =
|
|
764
|
+
__shape = __canvas.create_polygon(new_pts, fill=__fill, outline=__outline, smooth=1, width=__width, joinstyle=__joinstyle)
|
|
841
765
|
__update()
|
|
842
766
|
return __shape
|
|
843
767
|
|
|
@@ -862,7 +786,6 @@ def rect(x, y, w, h):
|
|
|
862
786
|
if abs(w) >= 2 and abs(h) >= 2:
|
|
863
787
|
__shape = __canvas.create_rectangle(x + 1, y + 1, x + 1 + w - 1, y + 1 + h - 1, fill=__fill, outline=__outline, width=__width)
|
|
864
788
|
__update()
|
|
865
|
-
|
|
866
789
|
elif abs(w) == 1 and abs(h) == 1:
|
|
867
790
|
__shape = line(x, y, x + 1, y)
|
|
868
791
|
__update()
|
|
@@ -873,6 +796,7 @@ def rect(x, y, w, h):
|
|
|
873
796
|
__shape = line(x, y, x + w, y)
|
|
874
797
|
__update()
|
|
875
798
|
return __shape
|
|
799
|
+
|
|
876
800
|
except Exception as e:
|
|
877
801
|
if __canvas == None:
|
|
878
802
|
pass;
|
|
@@ -889,9 +813,16 @@ def rect(x, y, w, h):
|
|
|
889
813
|
# @param h the height of the ellipse
|
|
890
814
|
def ellipse(x, y, w, h):
|
|
891
815
|
try:
|
|
892
|
-
|
|
816
|
+
if w == 1 and h == 1:
|
|
817
|
+
__shape = line(x, y, x + 1, y)
|
|
818
|
+
elif w == 2 and h == 2:
|
|
819
|
+
__shape = __canvas.create_rectangle(x + 1, y + 1, x + 1 + 2 - 1, y + 1 + 2 - 1, fill=__fill, outline=__outline, width=__width)
|
|
820
|
+
else:
|
|
821
|
+
__shape = __canvas.create_oval(x + 1, y + 1, x+w, y+h, fill=__fill, outline=__outline, width=__width)
|
|
822
|
+
|
|
893
823
|
__update()
|
|
894
824
|
return __shape
|
|
825
|
+
|
|
895
826
|
except Exception as e:
|
|
896
827
|
if __canvas == None:
|
|
897
828
|
pass;
|
|
@@ -905,11 +836,16 @@ def ellipse(x, y, w, h):
|
|
|
905
836
|
# @param x the set x location of center.
|
|
906
837
|
# @param y the set y location of center.
|
|
907
838
|
# @param d the diameter of the circle
|
|
908
|
-
|
|
909
839
|
def circle(x, y, d):
|
|
910
|
-
r = d//2
|
|
840
|
+
r = d // 2
|
|
911
841
|
try:
|
|
912
|
-
|
|
842
|
+
if d == 1:
|
|
843
|
+
__shape = line(x, y, x + 1, y)
|
|
844
|
+
elif d == 2:
|
|
845
|
+
__shape = __canvas.create_rectangle(x + 1, y + 1, x + 1 + 2 - 1, y + 1 + 2 - 1, fill=__fill, outline=__outline, width=__width)
|
|
846
|
+
else:
|
|
847
|
+
__shape = __canvas.create_oval(x + 1 - r, y + 1 - r, x - r + d, y - r + d, fill=__fill, outline=__outline, width=__width)
|
|
848
|
+
|
|
913
849
|
__update()
|
|
914
850
|
return __shape
|
|
915
851
|
|
|
@@ -922,6 +858,7 @@ def circle(x, y, d):
|
|
|
922
858
|
finally:
|
|
923
859
|
pass
|
|
924
860
|
|
|
861
|
+
|
|
925
862
|
## Place some text on the canvas
|
|
926
863
|
# @param x the x part of the coordinate of the where the text will be placed
|
|
927
864
|
# @param y the y part of the coordinate of the where the text will be placed
|
|
@@ -933,6 +870,7 @@ def text(x, y, what, align="c", ang=0):
|
|
|
933
870
|
__shape = __canvas.create_text(x + 1, y + 1, text=str(what), anchor=align, fill=__outline, font=__font, angle=ang)
|
|
934
871
|
__update()
|
|
935
872
|
return __shape
|
|
873
|
+
|
|
936
874
|
except Exception as e:
|
|
937
875
|
if __canvas == None:
|
|
938
876
|
pass;
|
|
@@ -1061,6 +999,7 @@ def arc(x, y, w, h, s, e):
|
|
|
1061
999
|
__shape = __canvas.create_arc(x + 1, y + 1, x+1+w, y+1+h, start=s, extent=e, fill=__fill, outline=__outline, style=tk.ARC, width=__width)
|
|
1062
1000
|
__update()
|
|
1063
1001
|
return __shape
|
|
1002
|
+
|
|
1064
1003
|
except Exception as e:
|
|
1065
1004
|
if __canvas == None:
|
|
1066
1005
|
pass;
|
|
@@ -1084,6 +1023,7 @@ def pieSlice(x, y, w, h, s, e):
|
|
|
1084
1023
|
__shape = __canvas.create_arc(x + 1, y + 1, x+1+w, y+1+h, start=s, extent=e, fill=__fill, outline=__outline, style=tk.PIESLICE, width=__width)
|
|
1085
1024
|
__update()
|
|
1086
1025
|
return __shape
|
|
1026
|
+
|
|
1087
1027
|
except Exception as e:
|
|
1088
1028
|
if __canvas == None:
|
|
1089
1029
|
pass;
|
|
@@ -1123,6 +1063,8 @@ def polygon(x1, y1=[], *args):
|
|
|
1123
1063
|
|
|
1124
1064
|
## Remove all drawing objects from the canvas
|
|
1125
1065
|
def clear():
|
|
1066
|
+
global __background
|
|
1067
|
+
|
|
1126
1068
|
try:
|
|
1127
1069
|
__canvas.delete("all")
|
|
1128
1070
|
__background = __canvas.create_rectangle(0, 0, getWidth(), getHeight(), fill=__bgcolor, outline=__bgcolor, tag="__background")
|
|
@@ -1132,14 +1074,30 @@ def clear():
|
|
|
1132
1074
|
__image_references.clear()
|
|
1133
1075
|
__update()
|
|
1134
1076
|
|
|
1135
|
-
## Move drawing object on the canvas
|
|
1136
|
-
|
|
1077
|
+
## Move a drawing object on the canvas to the new coordinates (x, y).
|
|
1078
|
+
# @param obj the object to move
|
|
1079
|
+
# @param x the new x coordinate
|
|
1080
|
+
# @param y the new y coordinate
|
|
1081
|
+
#
|
|
1082
|
+
# Anchor points:
|
|
1083
|
+
# ellipse / circle: the upper left corner of the bounding box
|
|
1084
|
+
# rectangle: the upper left corner of the bounding box
|
|
1085
|
+
# curve: the first point in the point list for the curve
|
|
1086
|
+
# line: the line's first point
|
|
1087
|
+
# text: the anchor point for the text
|
|
1088
|
+
# blob: the first point in the point list for the blob
|
|
1089
|
+
# arc: the upper left corner of the bounding box
|
|
1090
|
+
# polygon: the first point in the point list for the polygon
|
|
1091
|
+
# pie slice: the upper left corner of the bounding box
|
|
1137
1092
|
def move(obj, x, y):
|
|
1138
1093
|
try:
|
|
1139
|
-
|
|
1094
|
+
parts = __canvas.coords(obj)
|
|
1095
|
+
x1 = parts[0]
|
|
1096
|
+
y1 = parts[1]
|
|
1097
|
+
|
|
1140
1098
|
__canvas.move(obj, x-x1, y-y1)
|
|
1141
1099
|
except AttributeError:
|
|
1142
|
-
pass
|
|
1100
|
+
pass
|
|
1143
1101
|
|
|
1144
1102
|
__update()
|
|
1145
1103
|
|
|
@@ -1153,20 +1111,30 @@ def delete(obj):
|
|
|
1153
1111
|
|
|
1154
1112
|
__update()
|
|
1155
1113
|
|
|
1156
|
-
## Scale object on the canvas
|
|
1157
1114
|
## Scales the specified object by the given factors (xs, ys).
|
|
1115
|
+
# @param obj the object so scale
|
|
1116
|
+
# @param xs the x scale factor as a floating point number
|
|
1117
|
+
# @param ys the y scale factor as a floating point number
|
|
1118
|
+
#
|
|
1119
|
+
# A scale factor of 1.0 retains the object's original size. Values larger
|
|
1120
|
+
# than 1.0 enlarge the object. Smaller values shrink it.
|
|
1121
|
+
#
|
|
1122
|
+
# Calling scale on text objects has no effect.
|
|
1123
|
+
#
|
|
1158
1124
|
def scale(obj, xs, ys):
|
|
1159
1125
|
try:
|
|
1160
|
-
|
|
1126
|
+
parts = __canvas.coords(obj)
|
|
1127
|
+
x1 = parts[0]
|
|
1128
|
+
y1 = parts[1]
|
|
1129
|
+
|
|
1161
1130
|
__canvas.scale(obj, x1, y1, xs, ys)
|
|
1162
1131
|
except AttributeError:
|
|
1163
1132
|
pass;
|
|
1164
1133
|
|
|
1165
1134
|
__update()
|
|
1166
1135
|
|
|
1167
|
-
## Raise object to the top
|
|
1168
1136
|
## Brings the specified object to the top of the drawing order.
|
|
1169
|
-
def
|
|
1137
|
+
def bringToFront(obj):
|
|
1170
1138
|
try:
|
|
1171
1139
|
__canvas.tag_raise(obj)
|
|
1172
1140
|
except AttributeError:
|
|
@@ -1174,46 +1142,23 @@ def putUp(obj):
|
|
|
1174
1142
|
|
|
1175
1143
|
__update()
|
|
1176
1144
|
|
|
1177
|
-
## Lower object to the bottom
|
|
1178
1145
|
## Sends the specified object to the bottom of the drawing order.
|
|
1179
|
-
def
|
|
1146
|
+
def sendToBack(obj):
|
|
1180
1147
|
try:
|
|
1181
|
-
__canvas.tag_lower(obj)
|
|
1182
|
-
except AttributeError:
|
|
1183
|
-
pass;
|
|
1148
|
+
__canvas.tag_lower(obj, __background)
|
|
1184
1149
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
## Configures the properties of the specified object using keyword arguments.
|
|
1189
|
-
def itemConfig(obj, **kwargs):
|
|
1190
|
-
try:
|
|
1191
|
-
__canvas.itemconfig(obj, **kwargs)
|
|
1150
|
+
# Ensure that the background stays at the back
|
|
1151
|
+
__canvas.tag_lower(__background)
|
|
1152
|
+
|
|
1192
1153
|
except AttributeError:
|
|
1193
1154
|
pass;
|
|
1194
1155
|
|
|
1195
1156
|
__update()
|
|
1196
|
-
|
|
1197
|
-
## Checks if two objects on the Canvas have collided.
|
|
1198
|
-
## Returns True if the objects intersect, otherwise False.
|
|
1199
|
-
def checkCollision(obj1, obj2):
|
|
1200
|
-
|
|
1201
|
-
# Get the bounding box coordinates for both objects
|
|
1202
|
-
x1_min, y1_min, x1_max, y1_max = __canvas.bbox(obj1)
|
|
1203
|
-
x2_min, y2_min, x2_max, y2_max = __canvas.bbox(obj2)
|
|
1204
|
-
|
|
1205
|
-
# Check if the rectangles intersect
|
|
1206
|
-
if (x1_max >= x2_min and # Right edge of obj1 >= Left edge of obj2
|
|
1207
|
-
x1_min <= x2_max and # Left edge of obj1 <= Right edge of obj2
|
|
1208
|
-
y1_max >= y2_min and # Bottom edge of obj1 >= Top edge of obj2
|
|
1209
|
-
y1_min <= y2_max): # Top edge of obj1 <= Bottom edge of obj2
|
|
1210
|
-
return True
|
|
1211
|
-
return False
|
|
1212
|
-
|
|
1213
1157
|
|
|
1214
1158
|
|
|
1215
1159
|
## Should the screen be updated automatically after each graphics primitive
|
|
1216
1160
|
# is drawn?
|
|
1161
|
+
# @param status True if automatic redrawing is enabled. False otherwise.
|
|
1217
1162
|
def setAutoUpdate(status):
|
|
1218
1163
|
global __autoupdate
|
|
1219
1164
|
__autoupdate = status
|
|
@@ -1225,7 +1170,7 @@ def __shutdown():
|
|
|
1225
1170
|
## Determine the version of the library
|
|
1226
1171
|
# @return the version number as a floating point value
|
|
1227
1172
|
def version():
|
|
1228
|
-
return "1.0.
|
|
1173
|
+
return "1.0.13"
|
|
1229
1174
|
|
|
1230
1175
|
## Save the current contents of the window as an encapsulated postscript file.
|
|
1231
1176
|
# @param fname the name of the file that will be written (normally ends with
|
|
@@ -1295,11 +1240,124 @@ def savePPM(img, fname):
|
|
|
1295
1240
|
def saveGIF(img, fname):
|
|
1296
1241
|
img.write(fname, format="gif")
|
|
1297
1242
|
|
|
1243
|
+
## Save the contents of an image to a GIF file
|
|
1244
|
+
# @param img the image object to save
|
|
1245
|
+
# @param fname the name of the file that will be created
|
|
1246
|
+
def savePNG(img, fname):
|
|
1247
|
+
img.write(fname, format="png")
|
|
1248
|
+
|
|
1298
1249
|
## Retrieve a list of all of the fonts that are available on the system
|
|
1299
1250
|
# @return a list of strings containing the names of the available fonts
|
|
1300
1251
|
def fontList():
|
|
1301
1252
|
return list(font.families())
|
|
1302
1253
|
|
|
1254
|
+
## Perform a collection of tests and display a sample image. Only runs
|
|
1255
|
+
# when SimpleGraphics.py has not been imported into another program.
|
|
1256
|
+
def run_tests():
|
|
1257
|
+
resize(800, 700)
|
|
1258
|
+
background("white")
|
|
1259
|
+
|
|
1260
|
+
# Draw the ellipse
|
|
1261
|
+
setFill("gray75")
|
|
1262
|
+
ellipse_id = ellipse(100, 100, 100, 100)
|
|
1263
|
+
|
|
1264
|
+
# Draw the rectangle
|
|
1265
|
+
setOutline("red")
|
|
1266
|
+
setFill("light cyan")
|
|
1267
|
+
rect_id = rect(300, 100, 200, 100)
|
|
1268
|
+
|
|
1269
|
+
# Draw the line segments
|
|
1270
|
+
setOutline("blue")
|
|
1271
|
+
line1_id = line(150, 350, 200, 400)
|
|
1272
|
+
line2_id = line(100, 400, 100, 300, 200, 300, 200, 350)
|
|
1273
|
+
|
|
1274
|
+
# Draw the text
|
|
1275
|
+
setOutline("darkgreen")
|
|
1276
|
+
setFont("Times", "24", "bold")
|
|
1277
|
+
text_id = text(400, 350, "Hello World!", "c")
|
|
1278
|
+
|
|
1279
|
+
# Draw the arc
|
|
1280
|
+
setOutline("purple")
|
|
1281
|
+
arc_id = arc(100, 500, 100, 100, 0, 270)
|
|
1282
|
+
|
|
1283
|
+
# Draw the pie slice
|
|
1284
|
+
setOutline("Orange")
|
|
1285
|
+
setFill("yellow")
|
|
1286
|
+
pieslice_id = pieSlice(600, 500, 100, 100, 60, 60)
|
|
1287
|
+
|
|
1288
|
+
# Draw the polygon
|
|
1289
|
+
setOutline("gray50")
|
|
1290
|
+
setFill("pink")
|
|
1291
|
+
polygon_id = polygon(300, 500, 350, 500, 500, 550, 500, 600, 450, 600, 300, 550)
|
|
1292
|
+
|
|
1293
|
+
# Draw a curve
|
|
1294
|
+
setOutline("tomato")
|
|
1295
|
+
curve_id = curve(600, 125, 600, 100, 700, 100, 700, 125, 600, 150, 600, 200, 700, 200, 700, 150)
|
|
1296
|
+
|
|
1297
|
+
# Draw a blob
|
|
1298
|
+
setOutline("dark orchid")
|
|
1299
|
+
setFill("bisque")
|
|
1300
|
+
blob_id = blob(600, 400, 600, 350, 700, 350, 700, 300, 650, 300, 650, 400)
|
|
1301
|
+
|
|
1302
|
+
# Label all of the shapes
|
|
1303
|
+
setOutline("Black")
|
|
1304
|
+
setFont("Arial", 10)
|
|
1305
|
+
ellipsetext_id = text(150, 225, "ellipse")
|
|
1306
|
+
recttext_id = text(400, 225, "rect")
|
|
1307
|
+
curvetext_id = text(650, 225, "curve")
|
|
1308
|
+
linetext_id = text(150, 425, "line")
|
|
1309
|
+
texttext_id = text(400, 425, "text")
|
|
1310
|
+
blobtext_id = text(650, 425, "blob")
|
|
1311
|
+
arctext_id = text(150, 625, "arc")
|
|
1312
|
+
pieslicetext_id = text(650, 625, "pieSlice")
|
|
1313
|
+
polygontext_id = text(400, 625, "polygon")
|
|
1314
|
+
|
|
1315
|
+
# Display the IDs
|
|
1316
|
+
print("Object IDs:")
|
|
1317
|
+
print(" ellipse:", ellipse_id)
|
|
1318
|
+
print(" rectangle:", rect_id)
|
|
1319
|
+
print(" curve:", curve_id)
|
|
1320
|
+
print(" line 1:", line1_id)
|
|
1321
|
+
print(" line 2:", line2_id)
|
|
1322
|
+
print(" text:", text_id)
|
|
1323
|
+
print(" blob:", blob_id)
|
|
1324
|
+
print(" arc:", arc_id)
|
|
1325
|
+
print(" polygon:", polygon_id)
|
|
1326
|
+
print(" pie slice:", pieslice_id)
|
|
1327
|
+
|
|
1328
|
+
# Test the move function by moving the objects apart.
|
|
1329
|
+
move(ellipse_id, 10, 10)
|
|
1330
|
+
move(ellipsetext_id, 60, 135)
|
|
1331
|
+
|
|
1332
|
+
move(rect_id, 300, 10)
|
|
1333
|
+
move(recttext_id, 400, 135)
|
|
1334
|
+
|
|
1335
|
+
move(curve_id, 600+90, 125-90)
|
|
1336
|
+
move(curvetext_id, 650+90, 225-90)
|
|
1337
|
+
|
|
1338
|
+
move(line1_id, 150 - 90, 350)
|
|
1339
|
+
move(line2_id, 100 - 90, 400)
|
|
1340
|
+
move(linetext_id, 60, 425)
|
|
1341
|
+
|
|
1342
|
+
move(blob_id, 600 + 90, 400)
|
|
1343
|
+
move(blobtext_id, 650+90, 425)
|
|
1344
|
+
|
|
1345
|
+
move(arc_id, 10, 500 + 55)
|
|
1346
|
+
move(arctext_id, 60, 625 + 55)
|
|
1347
|
+
|
|
1348
|
+
move(polygon_id, 300, 500 + 55)
|
|
1349
|
+
move(polygontext_id, 400, 625 + 55)
|
|
1350
|
+
|
|
1351
|
+
move(pieslice_id, 600 + 90, 500 + 55)
|
|
1352
|
+
move(pieslicetext_id, 650 + 90, 625 + 55)
|
|
1353
|
+
|
|
1354
|
+
# Draw a circle at the middle of the screen
|
|
1355
|
+
setFill("lemon chiffon")
|
|
1356
|
+
circle_id = circle(getWidth() / 2, getHeight() / 2, 300)
|
|
1357
|
+
|
|
1358
|
+
# Move the new circle behind the 'Hello, World!' text
|
|
1359
|
+
sendToBack(circle_id)
|
|
1360
|
+
|
|
1303
1361
|
# Call the __init function.
|
|
1304
1362
|
__init()
|
|
1305
1363
|
|
|
@@ -1328,3 +1386,5 @@ except AttributeError:
|
|
|
1328
1386
|
def getPixel(img, x, y):
|
|
1329
1387
|
return img.get(x, y)
|
|
1330
1388
|
|
|
1389
|
+
if __name__ == "__main__":
|
|
1390
|
+
run_tests()
|
|
@@ -3,7 +3,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
3
3
|
long_description = fh.read()
|
|
4
4
|
setup(
|
|
5
5
|
name = 'simplegraphics-python',
|
|
6
|
-
version = '1.0.
|
|
6
|
+
version = '1.0.13.1',
|
|
7
7
|
description = 'A simple graphics wrapper on top of tkinter',
|
|
8
8
|
long_description=long_description,
|
|
9
9
|
long_description_content_type="text/markdown",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: simplegraphics-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.13.1
|
|
4
4
|
Summary: A simple graphics wrapper on top of tkinter
|
|
5
5
|
Home-page: https://cspages.ucalgary.ca/~bdstephe/217_P24/
|
|
6
6
|
Author: Ben Stephenson
|
|
@@ -12,6 +12,16 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Requires-Python: >=3.1.0
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: author-email
|
|
17
|
+
Dynamic: classifier
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: maintainer
|
|
22
|
+
Dynamic: maintainer-email
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
15
25
|
|
|
16
26
|
****SimpleGraphics**** is a lightweight Python graphics library designed as a convenient wrapper around the standard ****tkinter**** library. Its primary purpose is to make graphical programming accessible even to beginners: simply import the module, and a graphics window opens automatically, without the need to create classes, objects or manually call mainloop.
|
|
17
27
|
|
|
@@ -394,3 +404,24 @@ text(200, 340, "SimpleGraphics!")
|
|
|
394
404
|
being drawn 1 pixel too narrow / 1 pixel too short
|
|
395
405
|
Added the optional angle argument parameter to text when
|
|
396
406
|
the Python version is greater than or equal to X.Y.Z.
|
|
407
|
+
v1.0.12 -- Publicly released April 10, 2025
|
|
408
|
+
Added the circle function (Thanks to Grygoriy Gromko for
|
|
409
|
+
suggesting its inclusion and providing the preliminary
|
|
410
|
+
implementation)
|
|
411
|
+
Updated all of the drawing primitive functions so that they
|
|
412
|
+
return the created object so that it can be modified
|
|
413
|
+
subsequently.
|
|
414
|
+
Added support for moving, scaling, deleting, and changing
|
|
415
|
+
the draw order of objects (Thanks to Grygoriy Gromko for
|
|
416
|
+
suggesting their inclusion and providing preliminary
|
|
417
|
+
implementations)
|
|
418
|
+
Fixed a bug where the ability to change the background color
|
|
419
|
+
was lost after clear has been called.
|
|
420
|
+
v1.0.13 -- Public released June 9, 2026
|
|
421
|
+
Added the savePNG function
|
|
422
|
+
Circles with diameter 1 and diameter 2 are handled as special
|
|
423
|
+
cases so that they render as a single pixel and a 2x2
|
|
424
|
+
square respectively
|
|
425
|
+
Ellipses with width and height 1 and width and height 2 are
|
|
426
|
+
handled as special cases so that they render as a single
|
|
427
|
+
pixel and a 2x2 square respectively
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|