当前位置:   article > 正文

Python tkinter库:简易画板(笔、直线、矩形、圆形和橡皮擦工具+导入、保存、撤销、清屏功能)_tkinter画图软件

tkinter画图软件

Tkinter

Tkinter是Python的一款功能强大且全面、操作简易的GUI编程模块。今天,我们将使用tkinter制作一款简易画图软件。加油吧!

最终效果如下:

 


下载模块

我们将使用Python 3.10为编译器,使用 pip 下载所需模块:

  1. pip install tkinter
  2. pip install PIL

导入模块

这里,我们将导入所有所需的模块。

  1. import time
  2. import tkinter
  3. import tkinter.simpledialog
  4. import tkinter.colorchooser
  5. import tkinter.filedialog
  6. from PIL import Image, ImageTk, ImageGrab

设置主窗口

设置所有接下来所需的元素,并初始化。

  1. def center_window(w, h):
  2. app.winfo_screenwidth()
  3. app.winfo_screenheight()
  4. app.geometry('%dx%d' % (w, h))
  5. app = tkinter.Tk()
  6. app.title('轩氏画图')
  7. x = 1200
  8. y = 800
  9. center_window(x, y)
  10. yesno = tkinter.IntVar(value=0)
  11. what = tkinter.IntVar(value=1)
  12. X = tkinter.IntVar(value=0)
  13. Y = tkinter.IntVar(value=0)
  14. foreColor = '#000000'
  15. backColor = '#FFFFFF'
  16. image = tkinter.PhotoImage()
  17. canvas = tkinter.Canvas(app, bg='white', width=x, height=y)
  18. canvas.create_image(x, y, image=image)
  19. lastDraw = 0
  20. end = [0]
  21. size = "20"

基本画图运算逻辑

重点来了!我们使用鼠标左键按下等动作探测,绘制曲线:

  1. def getter(widget):
  2. time.sleep(0.5)
  3. x = app.winfo_x() + widget.winfo_x()
  4. y = app.winfo_y() + widget.winfo_y()
  5. if app.winfo_x() < 0:
  6. x = 0
  7. if app.winfo_y() < 0:
  8. y = 0
  9. x1 = x + widget.winfo_width() + 200
  10. y1 = y + widget.winfo_height() + 200
  11. filename = tkinter.filedialog.asksaveasfilename(filetypes=[('.jpg', 'JPG')],
  12. initialdir='C:\\Users\\lin042\\Desktop\\')
  13. ImageGrab.grab().crop((x, y, x1, y1)).save(filename)
  14. def onLeftButtonDown(event):
  15. yesno.set(1)
  16. X.set(event.x)
  17. Y.set(event.y)
  18. if what.get() == 4:
  19. canvas.create_text(event.x, event.y, font=("等线", int(size)), text=text, fill=foreColor)
  20. what.set(1)
  21. def onLeftButtonMove(event):
  22. global lastDraw
  23. if yesno.get() == 0:
  24. return
  25. if what.get() == 1:
  26. lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y,
  27. fill=foreColor)
  28. X.set(event.x)
  29. Y.set(event.y)
  30. elif what.get() == 2:
  31. try:
  32. canvas.delete(lastDraw)
  33. except Exception:
  34. pass
  35. lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y,
  36. fill=foreColor)
  37. elif what.get() == 3:
  38. try:
  39. canvas.delete(lastDraw)
  40. except Exception:
  41. pass
  42. lastDraw = canvas.create_rectangle(X.get(), Y.get(), event.x, event.y,
  43. outline=foreColor)
  44. elif what.get() == 5:
  45. lastDraw = canvas.create_rectangle(event.x - 10, event.y - 10, event.x + 10, event.y + 10,
  46. outline=backColor)
  47. elif what.get() == 6:
  48. try:
  49. canvas.delete(lastDraw)
  50. except Exception:
  51. pass
  52. lastDraw = canvas.create_oval(X.get(), Y.get(), event.x, event.y,
  53. fill=backColor, outline=foreColor)
  54. def onLeftButtonUp(event):
  55. global lastDraw
  56. if what.get() == 2:
  57. lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y, fill=foreColor)
  58. elif what.get() == 3:
  59. lastDraw = canvas.create_rectangle(X.get(), Y.get(), event.x, event.y, outline=foreColor)
  60. elif what.get() == 6:
  61. lastDraw = canvas.create_oval(X.get(), Y.get(), event.x, event.y, outline=foreColor)
  62. yesno.set(0)
  63. end.append(lastDraw)
  64. def onRightButtonUp(event):
  65. menu.post(event.x_root, event.y_root)

最后通过bind来移动画笔:

  1. canvas.bind('<Button-1>', onLeftButtonDown)
  2. canvas.bind('<B1-Motion>', onLeftButtonMove)
  3. canvas.bind('<ButtonRelease-1>', onLeftButtonUp)
  4. canvas.bind('<ButtonRelease-3>', onRightButtonUp)
  5. canvas.pack(fill=tkinter.BOTH, expand=tkinter.YES)

顶部主菜单

设置主菜单功能及运算函数。目前包括以下五个选项:导入、保存、撤销、清屏和工具栏。

  1. '''主菜单及其关联的函数'''
  2. menu = tkinter.Menu(app, bg="red")
  3. app.config(menu=menu)
  4. def Open():
  5. filename = tkinter.filedialog.askopenfilename(title='导入图片',
  6. filetypes=[('image', '*.jpg *.png *.gif')])
  7. if filename:
  8. global image
  9. image = Image.open(filename)
  10. image = image.resize((800, 600), Image.ANTIALIAS)
  11. image = ImageTk.PhotoImage(image)
  12. canvas.create_image(400, 300, image=image)
  13. menu.add_command(label='导入', command=Open)
  14. def Save():
  15. getter(canvas)
  16. menu.add_command(label='保存', command=Save)
  17. def Clear():
  18. global lastDraw, end
  19. for item in canvas.find_all():
  20. canvas.delete(item)
  21. end = [0]
  22. lastDraw = 0
  23. menu.add_command(label='清屏', command=Clear)
  24. def Back():
  25. global end
  26. try:
  27. for i in range(end[-2], end[-1] + 1):
  28. canvas.delete(i)
  29. end.pop()
  30. except:
  31. end = [0]
  32. menu.add_command(label='撤销', command=Back)
  33. menu.add_separator()

工具栏子菜单

设置“工具栏”下子菜单函数和内容,运算逻辑前面已经定义过了,这里我们只需要调用并绑定按钮即可。

  1. '''子菜单及其关联的函数'''
  2. menuType = tkinter.Menu(menu, tearoff=0)
  3. def drawCurve():
  4. what.set(1)
  5. menuType.add_command(label='铅笔', command=drawCurve)
  6. def drawLine():
  7. what.set(2)
  8. menuType.add_command(label='直线', command=drawLine)
  9. def drawRectangle():
  10. what.set(3)
  11. menuType.add_command(label='矩形', command=drawRectangle)
  12. def drawCircle():
  13. what.set(6)
  14. menuType.add_command(label='圆形', command=drawCircle)
  15. def drawText():
  16. global text, size
  17. text = tkinter.simpledialog.askstring(title='输入文本', prompt='')
  18. if text is not None:
  19. size = tkinter.simpledialog.askinteger('输入字号', prompt='', initialvalue=20)
  20. if size is None:
  21. size = "20"
  22. what.set(4)
  23. menuType.add_command(label='文本', command=drawText)
  24. def onErase():
  25. what.set(5)
  26. menuType.add_command(label='橡皮擦', command=onErase)
  27. menuType.add_separator()
  28. def chooseForeColor():
  29. global foreColor
  30. foreColor = tkinter.colorchooser.askcolor()[1]
  31. menuType.add_command(label='选择前景色', command=chooseForeColor)
  32. def chooseBackColor():
  33. global backColor
  34. backColor = tkinter.colorchooser.askcolor()[1]
  35. menuType.add_command(label='选择背景色', command=chooseBackColor)
  36. menu.add_cascade(label='工具栏', menu=menuType)

进入窗口循环

最后,使用mainloop进入窗口循环。

app.mainloop()

效果展示

最终效果展示:

 

 

 


完整代码

完整代码如下:

  1. import time
  2. import tkinter
  3. import tkinter.simpledialog
  4. import tkinter.colorchooser
  5. import tkinter.filedialog
  6. from PIL import Image, ImageTk, ImageGrab
  7. def center_window(w, h):
  8. app.winfo_screenwidth()
  9. app.winfo_screenheight()
  10. app.geometry('%dx%d' % (w, h))
  11. app = tkinter.Tk()
  12. app.title('轩氏画图')
  13. x = 1200
  14. y = 800
  15. center_window(x, y)
  16. yesno = tkinter.IntVar(value=0)
  17. what = tkinter.IntVar(value=1)
  18. X = tkinter.IntVar(value=0)
  19. Y = tkinter.IntVar(value=0)
  20. foreColor = '#000000'
  21. backColor = '#FFFFFF'
  22. image = tkinter.PhotoImage()
  23. canvas = tkinter.Canvas(app, bg='white', width=x, height=y)
  24. canvas.create_image(x, y, image=image)
  25. lastDraw = 0
  26. end = [0]
  27. size = "20"
  28. def getter(widget):
  29. time.sleep(0.5)
  30. x = app.winfo_x() + widget.winfo_x()
  31. y = app.winfo_y() + widget.winfo_y()
  32. if app.winfo_x() < 0:
  33. x = 0
  34. if app.winfo_y() < 0:
  35. y = 0
  36. x1 = x + widget.winfo_width() + 200
  37. y1 = y + widget.winfo_height() + 200
  38. filename = tkinter.filedialog.asksaveasfilename(filetypes=[('.jpg', 'JPG')],
  39. initialdir='C:\\Users\\lin042\\Desktop\\')
  40. ImageGrab.grab().crop((x, y, x1, y1)).save(filename)
  41. def onLeftButtonDown(event):
  42. yesno.set(1)
  43. X.set(event.x)
  44. Y.set(event.y)
  45. if what.get() == 4:
  46. canvas.create_text(event.x, event.y, font=("等线", int(size)), text=text, fill=foreColor)
  47. what.set(1)
  48. def onLeftButtonMove(event):
  49. global lastDraw
  50. if yesno.get() == 0:
  51. return
  52. if what.get() == 1:
  53. lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y,
  54. fill=foreColor)
  55. X.set(event.x)
  56. Y.set(event.y)
  57. elif what.get() == 2:
  58. try:
  59. canvas.delete(lastDraw)
  60. except Exception:
  61. pass
  62. lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y,
  63. fill=foreColor)
  64. elif what.get() == 3:
  65. try:
  66. canvas.delete(lastDraw)
  67. except Exception:
  68. pass
  69. lastDraw = canvas.create_rectangle(X.get(), Y.get(), event.x, event.y,
  70. outline=foreColor)
  71. elif what.get() == 5:
  72. lastDraw = canvas.create_rectangle(event.x - 10, event.y - 10, event.x + 10, event.y + 10,
  73. outline=backColor)
  74. elif what.get() == 6:
  75. try:
  76. canvas.delete(lastDraw)
  77. except Exception:
  78. pass
  79. lastDraw = canvas.create_oval(X.get(), Y.get(), event.x, event.y,
  80. fill=backColor, outline=foreColor)
  81. def onLeftButtonUp(event):
  82. global lastDraw
  83. if what.get() == 2:
  84. lastDraw = canvas.create_line(X.get(), Y.get(), event.x, event.y, fill=foreColor)
  85. elif what.get() == 3:
  86. lastDraw = canvas.create_rectangle(X.get(), Y.get(), event.x, event.y, outline=foreColor)
  87. elif what.get() == 6:
  88. lastDraw = canvas.create_oval(X.get(), Y.get(), event.x, event.y, outline=foreColor)
  89. yesno.set(0)
  90. end.append(lastDraw)
  91. def onRightButtonUp(event):
  92. menu.post(event.x_root, event.y_root)
  93. canvas.bind('<Button-1>', onLeftButtonDown)
  94. canvas.bind('<B1-Motion>', onLeftButtonMove)
  95. canvas.bind('<ButtonRelease-1>', onLeftButtonUp)
  96. canvas.bind('<ButtonRelease-3>', onRightButtonUp)
  97. canvas.pack(fill=tkinter.BOTH, expand=tkinter.YES)
  98. '''主菜单及其关联的函数'''
  99. menu = tkinter.Menu(app, bg="red")
  100. app.config(menu=menu)
  101. def Open():
  102. filename = tkinter.filedialog.askopenfilename(title='导入图片',
  103. filetypes=[('image', '*.jpg *.png *.gif')])
  104. if filename:
  105. global image
  106. image = Image.open(filename)
  107. image = image.resize((800, 600), Image.ANTIALIAS)
  108. image = ImageTk.PhotoImage(image)
  109. canvas.create_image(400, 300, image=image)
  110. menu.add_command(label='导入', command=Open)
  111. def Save():
  112. getter(canvas)
  113. menu.add_command(label='保存', command=Save)
  114. def Clear():
  115. global lastDraw, end
  116. for item in canvas.find_all():
  117. canvas.delete(item)
  118. end = [0]
  119. lastDraw = 0
  120. menu.add_command(label='清屏', command=Clear)
  121. def Back():
  122. global end
  123. try:
  124. for i in range(end[-2], end[-1] + 1):
  125. canvas.delete(i)
  126. end.pop()
  127. except:
  128. end = [0]
  129. menu.add_command(label='撤销', command=Back)
  130. menu.add_separator()
  131. '''子菜单及其关联的函数'''
  132. menuType = tkinter.Menu(menu, tearoff=0)
  133. def drawCurve():
  134. what.set(1)
  135. menuType.add_command(label='铅笔', command=drawCurve)
  136. def drawLine():
  137. what.set(2)
  138. menuType.add_command(label='直线', command=drawLine)
  139. def drawRectangle():
  140. what.set(3)
  141. menuType.add_command(label='矩形', command=drawRectangle)
  142. def drawCircle():
  143. what.set(6)
  144. menuType.add_command(label='圆形', command=drawCircle)
  145. def drawText():
  146. global text, size
  147. text = tkinter.simpledialog.askstring(title='输入文本', prompt='')
  148. if text is not None:
  149. size = tkinter.simpledialog.askinteger('输入字号', prompt='', initialvalue=20)
  150. if size is None:
  151. size = "20"
  152. what.set(4)
  153. menuType.add_command(label='文本', command=drawText)
  154. def onErase():
  155. what.set(5)
  156. menuType.add_command(label='橡皮擦', command=onErase)
  157. menuType.add_separator()
  158. def chooseForeColor():
  159. global foreColor
  160. foreColor = tkinter.colorchooser.askcolor()[1]
  161. menuType.add_command(label='选择前景色', command=chooseForeColor)
  162. def chooseBackColor():
  163. global backColor
  164. backColor = tkinter.colorchooser.askcolor()[1]
  165. menuType.add_command(label='选择背景色', command=chooseBackColor)
  166. menu.add_cascade(label='工具栏', menu=menuType)
  167. app.mainloop()

喜欢就点个赞,收藏一下吧~

我是轩哥啊哈,下期我们不见不散~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/772840
推荐阅读
相关标签
  

闽ICP备14008679号