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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: simplegraphics-python
3
- Version: 1.0.12
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
- __loop = False
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 = draw_spline(__canvas, new_pts, True, fill=__fill, outline=__outline, width=__width)
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
- __shape = __canvas.create_oval(x + 1, y + 1, x+w, y+h, fill=__fill, outline=__outline, width=__width)
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
- __shape = __canvas.create_oval(x + 1 - r, y + 1 - r, x + r, y + r, fill=__fill, outline=__outline, width=__width)
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
- ## Moves the specified object to the new coordinates (x, y).
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
- x1, y1, x2, y2 = __canvas.coords(obj)
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
- x1, y1, x2, y2 = __canvas.coords(obj)
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 putUp(obj):
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 putDown(obj):
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
- __update()
1186
-
1187
- ## Configure object properties
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.11"
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.12',
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
1
+ Metadata-Version: 2.4
2
2
  Name: simplegraphics-python
3
- Version: 1.0.12
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